论坛风格切换切换到宽版
  • 13179阅读
  • 36回复

讨论一下DDS控制字的算法 [复制链接]

上一主题 下一主题
离线wycx
发帖
1497
只看该作者 20楼 发表于: 2006-10-25
用户被禁言,该主题自动屏蔽!
离线jiandanzq
只看该作者 21楼 发表于: 2007-06-01
不错不错!学习一下!
离线tcy22222
只看该作者 22楼 发表于: 2007-06-12
值得学习,高手好多
离线PengPeng0419
发帖
16
只看该作者 23楼 发表于: 2008-03-21
'
而且这个代码去我是试过好多种写法,,最后才定的...最快,,,编译出的目标代码最小.....误差最小
没你说的那么大的误差啦...0.4*9+0.1*9+0.3*9+0.3*9+0.4*9+0.1*9+0.5*9=18.2个控制字
最大大约0.3hz了而且是这些误差不可能同时发生
'
请问这个算法是怎么弄出来的~!~!我想针对我的125m输入时钟以这个算法编写~!~!
离线ba6iv
发帖
1285
只看该作者 24楼 发表于: 2008-04-02
最近也在看dds,关于控制字的计算看帖子好像大概有三种算法(不包含查表法,程序太长没来得及试)
第一种:直接乘除法 word=f/(180000000/4294967296)或者
            word=f*(4294967296/180000000)
(180000000/4294967296)和 (4294967296/180000000)事先算好的。

用avr单片机运算14.020000mhz (手工计算的控制字为334530230)
              word=f/(180000000/4294967296) 耗时1112个时钟单位 结果334530208
          word=f*(4294967296/180000000)耗时520个时钟单位 结果334530208
      好像乘法比除法快一倍以上。但是误差最大,相差22。
注:搞不清为什么直接乘除误差这么大,也试过双精度,程序更大了,但结果一样。


第二种:简化的大整数乘法
#define ff0               238609294
#define ff1               23860929
#define ff2               2386093
#define ff3               238609
#define ff4               23861
#define ff5               2386
#define ff6               237
#define ff7               24

unsigned long dds_ctrl(unsigned char *fno)
{
  unsigned long dds_no;
  dds_no=(*(fno+7))*ff7+
     (*(fno+6))*ff6+
     (*(fno+5))*ff5+
     (*(fno+4))*ff4+
     (*(fno+3))*ff3+
     (*(fno+2))*ff2+
     (*(fno+1))*ff1+
     (*fno)*ff0 ;
  return(dds_no);
}


用avr单片机运算14.020000mhz (手工计算的控制字为334530230)

耗时823个时钟单位 结果334530228 误差为2。

第三种:简化的大整数除法(位移运算实现)
long dds_fre_word(long fre)
{
  long tmp1;
  long tmp2=0;
  unsigned char i;
  tmp1=fre;
  for(i=0;i<32;i++)
  {
  if(tmp1>=180000000)
  {
    tmp2++;
    tmp1=tmp1-180000000;
  }
  tmp1=tmp1<<1;
      tmp2=tmp2<<1;
  }
  return tmp2;
}

用avr单片机运算14.020000mhz (手工计算的控制字为334530230)

耗时2812个时钟单位 结果334530230 误差为0。

从以上三种算法来看是精度高的用时长,用时短的精度差,第二种算法精度和用时比较适中。
离线ba6iv
发帖
1285
只看该作者 25楼 发表于: 2008-04-02
'
请问这个算法是怎么弄出来的~!~!我想针对我的125m输入时钟以这个算法编写~!~!
'

125m时钟 343597384   用2的32次方除以125000000hz得来的

ff7   343597384
ff6   34359738
ff5   3435974
ff4   343597
ff3   34360
ff2   3436
ff1   344
ff0   34
离线funghome
发帖
143
只看该作者 26楼 发表于: 2008-04-10
'
http://www.hellocq.net/forum/showthread.php?t=124374&12m时钟882us计算dds控制字源程序
12m时钟882us计算dds控制字源程序
这个速度够用么????\
我试过..时间好像与频率的数值无关...
'
剛學c
unsigned char data *fno當中的*什麼意思??
离线ba6iv
发帖
1285
只看该作者 27楼 发表于: 2008-04-11
*号是指针的意思,*fno就是一个指针变量
离线庄乾章
发帖
1047
只看该作者 28楼 发表于: 2008-06-19
jh12345
离线BG7RKR
发帖
16
只看该作者 29楼 发表于: 2008-11-03
可以考虑用两片单片机来跑,很爽的,我的跑起来很不错
离线BG4UVR
发帖
11207
只看该作者 30楼 发表于: 2008-11-04
'
可以考虑用两片单片机来跑,很爽的,我的跑起来很不错
'

这…… 这也太那个了吧……
离线BD4WE
发帖
284
只看该作者 31楼 发表于: 2008-11-08
我是用ateml 的arm7--at91s7sam64来做的,直接算除法,做了一个扫频的,用示波器看,频率变化很快的

/*
ad9851 fq_ud----pa9 sam64
ad9851 sdi ----mosi sam64       bit13
ad9851 sck ----sck sam64             bit14
2e32=4294967296

fout= tune_word*systemclock/2e32
fout=30m
systemclock=120m(板子上装晶振20m*6)

tune__word=(fout*2e32)/systemclock
      =(fout*2e30)/30m
            2e30)/120m= 35.791394133


tune__word=0x2222222 --1mhz


tune__word=(fout*2e32)/systemclock                                          
想要的频率      基准频率(mhz)      倍频数      系统频率      2.00e+32      32位调谐字(10进制)      32位调谐字(16进制)      
1      20      6      120      4294967296      35791394      02222222      
2      20      6      120      4294967296      71582788      04444444      
3      20      6      120      4294967296      107374182      06666666      
4      20      6      120      4294967296      143165577      08888888      
5      20      6      120      4294967296      178956971      0aaaaaaa      
6      20      6      120      4294967296      214748365      0ccccccc      
7      20      6      120      4294967296      250539759      0eeeeeee      
8      20      6      120      4294967296      286331153      11111111      
9      20      6      120      4294967296      322122547      13333333      
10      20      6      120      4294967296      357913941      15555555      
11      20      6      120      4294967296      393705335      17777777      
12      20      6      120      4294967296      429496730      19999999      
13      20      6      120      4294967296      465288124      1bbbbbbb      
14      20      6      120      4294967296      501079518      1ddddddd      
15      20      6      120      4294967296      536870912      20000000      
16      20      6      120      4294967296      572662306      22222222      
17      20      6      120      4294967296      608453700      24444444      
18      20      6      120      4294967296      644245094      26666666      
19      20      6      120      4294967296      680036489      28888888      
20      20      6      120      4294967296      715827883      2aaaaaaa      
21      20      6      120      4294967296      751619277      2ccccccc      
22      20      6      120      4294967296      787410671      2eeeeeee      
23      20      6      120      4294967296      823202065      31111111      
24      20      6      120      4294967296      858993459      33333333      
25      20      6      120      4294967296      894784853      35555555      
26      20      6      120      4294967296      930576247      37777777      
27      20      6      120      4294967296      966367642      39999999      
28      20      6      120      4294967296      1002159036      3bbbbbbb      
29      20      6      120      4294967296      1037950430      3ddddddd      
30      20      6      120      4294967296      1073741824      40000000      
30.001      20      6      120      4294967296      1073777615      40008bcf      
15.001      20      6      120      4294967296      536906703      20008bcf      100hz的差0x8bcf
30.0001      20      6      120      4294967296      1073745403      40000dfb      10hz的差0x0dfb
                                         
15      20      6      120      4294967296      536870912      20000000      
15.001      20      6      120      4294967296      536906703      20008bcf      100hz的差0x8bcf
15      20      6      120      4294967296      536870912      20000000      
15.0001      20      6      120      4294967296      536874491      20000dfb      10hz的差0x0dfb
#include "at91sam7s64.h"
#include "lib_at91sam7s64.h"
#include "my.h"


#define ad_start   bit9

//编码器输入
#define int_ok     bit24
#define int_left   bit25
#define int_right   bit26

//----|______|------- bit25       顺时针
//--------|__|------- bit26   最小间隔5ms

//----|______|------- bit25       n时针
//----|__|----------- bit26   最小间隔5ms


#define ok     0
#define up   1
#define down   2

#define fq_ud   bit9
#define sdi   bit13
#define sck   bit14

unsigned char   key_state,ok_number      ,number;
unsigned char      pioa_change_time=0;
unsigned int key;
unsigned int   key1;
unsigned char key_changed=0;

/*struct {
unsigned   char   freq0;
unsigned   char   freq1;
unsigned   char   freq2;
unsigned   char   freq3;
}cmd_struct; */

union tune_wd
{
unsigned char tx_word[4];
unsigned long   tune_word;
}cmd_word;

unsigned   char   work_state;
unsigned long   freqency_wanted;      // 想要的频率,单位:hz


void cmd_word_init(void)
{

cmd_word.tx_word[0]=0x00;
cmd_word.tx_word[1]=0x00;
cmd_word.tx_word[2]=0x00;
cmd_word.tx_word[3]=0x40;               //30mhz
work_state=0x01;

}
。。。
int main(void)
{      

  sys_init();      
     port_init();
  spi_init();
     //timer1_init();
     uart0_init();
     cmd_word_init();
     freqency_wanted =50000;
     *at91c_aic_eoicr = 0x00;
  *at91c_aic_iecr = 1<<at91c_id_pioa;                       //打开AIC中断
     while(1)
     {

        putchar(number);
        /*if(key_changed==1)
        {
        putchar(number);
        key_changed=0;
        } */
  if(freqency_wanted<30000000) //从100k到30m扫描
      {
        freqency_wanted+=100000;        
        cmd_word.tune_word=(unsigned long)(35.791394133* freqency_wanted);
        write_byte_spi(cmd_word.tx_word[0]);
        write_byte_spi(cmd_word.tx_word[1]);
        write_byte_spi(cmd_word.tx_word[2]);
        write_byte_spi(cmd_word.tx_word[3]);
        write_byte_spi(work_state);
        *at91c_pioa_sodr=fq_ud;
        //delay_us(100);
        *at91c_pioa_codr=fq_ud;
        // delay_ms(0x2ff);
           delay_ms(0x20);            
           }
      else freqency_wanted = 100000;


     /* *at91c_pioa_codr=bit7; //pioa7,25输出低电平 48mhz mck主频下,无延时程序,0-1一个周期需要375ns。
     delay_ms(1);
                 
  *at91c_pioa_sodr=bit7; //pioa25输出高电平
     delay_ms(1); */




       }
离线田鼠
发帖
233
只看该作者 32楼 发表于: 2011-01-15
'
我的查表算法思路是这样的:
1、构造n个二维数组(n=你需要输入的最大频率值位数,例如你需要精确到10hz,最高30mhz,那么就有10m位、1m位、100k位、10k位、1k位、100hz位、10hz位,共7位,所以n=7)。
2、根据你所用的芯片型号,和晶振频率,计算出每个频率位0-9时的控制字。
3、使用时,把你频率的每一位控制字,查表读出,并相加(特别需要注意进位也需要处理)。
4、把加出的4字节控制字,送dds。
此方法,理论最大控制字误差为n。一般9851或9850dds,常用的晶振频率值条件下,此误差实际表现在频率上时,小于1hz的1到2个数量级。
查表部分具体程序(尚未进行硬件测试)
  1. /*******************************************
  2.     ad9850 dds控制子程序
  3. ********************************************
  4. 编写:bg4uvr
  5. 描述:   mcs51单片机控制ad9850/ad9851子程序。
  6.     提供如下5个常用dds控制函数。例子中
  7.     dds控制字表的dds型号为ad9850,晶振
  8.     为16mhz。
  9. 注意:   使用前请修改程序内相应硬件端口
  10. ********************************************/
  11. void dds_reset(void);     //dds主复位程序
  12. void dds_serialmode(void);   //dds串行方式设置
  13. void dds_set(void);         //dds设置数据发送
  14. void fre2word(void);     //dds控制字计算
  15. void freupdata(void);     //dds频率输出更新
  16. /*******************************************/
  17. //其他函数此处省略,只留下了表的结构和控制字计算部分……
  18. /********************************************/
  19. //控制字表,dds=9850,晶振=16mhz
  20.   //word=0x100000000*fre/16000000;
  21. /********************************************/
  22. unsigned char code dds_word_10mhz[2][4]={
  23.   0x00,0x00,0x00,0x00,
  24.   0x00,0x00,0x00,0xa0
  25. };
  26. unsigned char code dds_word_1mhz[10][4]={
  27.   0x00,0x00,0x00,0x00,
  28.   0x00,0x00,0x00,0x10,
  29.   0x00,0x00,0x00,0x20,
  30.   0x00,0x00,0x00,0x30,
  31.   0x00,0x00,0x00,0x40,
  32.   0x00,0x00,0x00,0x50,
  33.   0x00,0x00,0x00,0x60,
  34.   0x00,0x00,0x00,0x70,
  35.   0x00,0x00,0x00,0x80,
  36.   0x00,0x00,0x00,0x90
  37. };
  38. unsigned char code dds_word_100khz[10][4]={
  39.   0x00,0x00,0x00,0x00,         //0
  40.   0x99,0x99,0x99,0x01,     //1
  41.   0x33,0x33,0x33,0x03,     //2
  42.   0xcc,0xcc,0xcc,0x04,     //3
  43.   0x66,0x66,0x66,0x06,     //4
  44.   0x00,0x00,0x00,0x08,     //5
  45.   0x99,0x99,0x99,0x09,     //6
  46.   0x33,0x33,0x33,0x0b,     //7
  47.   0xcc,0xcc,0xcc,0x0c,     //8
  48.   0x66,0x66,0x66,0x0e         //9
  49. };
  50. unsigned char code dds_word_10khz[10][4]={
  51.   0x00,0x00,0x00,0x00,     //0
  52.   0xc2,0xf5,0x28,0x00,     //1
  53.   0x85,0xeb,0x51,0x00,     //2
  54.   0x47,0xe1,0x7a,0x00,     //3
  55.   0x0a,0xd7,0xa3,0x00,     //4
  56.   0xcc,0xcc,0xcc,0x00,     //5
  57.   0x8f,0xc2,0xf5,0x00,     //6
  58.   0x51,0xb8,0x1e,0x01,     //7
  59.   0x14,0xae,0x47,0x01,     //8
  60.   0xd7,0xa3,0x70,0x01,     //9
  61. };
  62. unsigned char code dds_word_1khz[10][3]={
  63.   0x00,0x00,0x00,     //0
  64.   0x93,0x18,0x04,     //1
  65.   0x26,0x31,0x08,     //2
  66.   0xba,0x49,0x0c,     //3
  67.   0x4d,0x62,0x10,     //4
  68.   0xe1,0x7a,0x14,     //5
  69.   0x74,0x93,0x18,     //6
  70.   0x08,0xac,0x1c,     //7
  71.   0x9b,0xc4,0x20,     //8
  72.   0x2f,0xdd,0x24,     //9
  73. };
  74. unsigned char code dds_word_100hz[10][3]={
  75.   0x00,0x00,0x00,     //0
  76.   0xdb,0x68,0x00,     //1
  77.   0xb7,0xd1,0x00,     //2
  78.   0x92,0x3a,0x01,     //3
  79.   0x6e,0xa3,0x01,     //4
  80.   0x49,0x0c,0x02,     //5
  81.   0x25,0x75,0x02,     //6
  82.   0x00,0xde,0x02,     //7
  83.   0xdc,0x46,0x03,     //8
  84.   0xb7,0xaf,0x03     //9
  85. };
  86. unsigned char code dds_word_10hz[10][2]={
  87.   0x00,0x00,     //0
  88.   0x7c,0x0a,     //1
  89.   0x14,0xf8,     //2
  90.   0x75,0x1f,     //3
  91.   0xf1,0x29,     //4
  92.   0x6d,0x34,     //5
  93.   0xea,0x3e,     //6
  94.   0x66,0x49,     //7
  95.   0xe2,0x53,     //8
  96.   0x5f,0xfe     //9
  97. };
  98. unsigned char code dds_word_1hz[10][2]={
  99.   0x00,0x00,     //0
  100.   0x0c,0x01,     //1
  101.   0x18,0x02,     //2
  102.   0x25,0x03,     //3
  103.   0x31,0x04,     //4
  104.   0x3e,0x05,     //5
  105.   0x4a,0x06,     //6
  106.   0x57,0x07,     //7
  107.   0x63,0x08,     //8
  108.   0x6f,0x09     //9
  109. };
  110. /********************************************/
  111. //控制字计算
  112. void fre2word(void){
  113.   unsigned int temp1,temp2;
  114.   //计算w0的值。注意,本例dds工作在串行方式,这里w0是指控制字低8位,请区别于并行方式
  115.   temp1=dds_word_1hz[fre[7]][0]+dds_word_10hz[fre[6]][0]+dds_word_100hz[fre[5]][0]+dds_word_1khz[fre[4]][0]+dds_word_10khz[fre[3]][0]+dds_word_100khz[fre[2]][0]+dds_word_1mhz[fre[1]][0]+dds_word_10mhz[fre[0]][0];
  116.   w[0]=(unsigned char)temp1;
  117.   //计算w0相加时的进位
  118.   temp2=(unsigned char)(temp1>>8);
  119.   //计算w1值
  120.   temp1=dds_word_1hz[fre[7]][1]+dds_word_10hz[fre[6]][1]+dds_word_100hz[fre[5]][1]+dds_word_1khz[fre[4]][1]+dds_word_10khz[fre[3]][1]+dds_word_100khz[fre[2]][1]+dds_word_1mhz[fre[1]][1]+dds_word_10mhz[fre[0]][1]+temp2;
  121.   w[1]=(unsigned char)temp1;
  122.   temp2=(unsigned char)(temp1>>8);
  123.   //计算w2值
  124.   temp1=dds_word_100hz[fre[5]][2]+dds_word_1khz[fre[4]][2]+dds_word_10khz[fre[3]][2]+dds_word_100khz[fre[2]][2]+dds_word_1mhz[fre[1]][2]+dds_word_10mhz[fre[0]][2]+temp2;
  125.   w[2]=(unsigned char)temp1;
  126.   temp2=(unsigned char)(temp1>>8);
  127.   //计算w3值
  128.   temp1=dds_word_10khz[fre[3]][3]+dds_word_100khz[fre[2]][3]+dds_word_1mhz[fre[1]][3]+dds_word_10mhz[fre[0]][3]+temp2;
  129.   w[3]=(unsigned char)temp1;
  130. }
'
学习了!非常感谢!
离线BG4UVR
发帖
11207
只看该作者 33楼 发表于: 2011-01-15
[quote=田鼠]学习了!非常感谢! [/quote]

看到自己以前的学习笔记还能对别人有所帮助,真是从心底里感觉到开心
发帖
689
只看该作者 34楼 发表于: 2011-01-15
路过一下。
离线代洪波
发帖
4809
只看该作者 35楼 发表于: 2011-02-12
'
看到自己以前的学习笔记还能对别人有所帮助,真是从心底里感觉到开心 [表情]
'
你的代码让我也受益匪浅!!!!!!!!!!!!!!!
离线BG7RKR
发帖
16
只看该作者 36楼 发表于: 2011-03-09
'
经常做其他的单片机实验,还没做过dds的实验。最近打算写个程序试验一下。
看了n久datasheet和别人的例子,就开始写程序了。可到了控制字的计算,发现还真是麻烦。由于我是用c写程序,所以一开始定义了long型变量,让它算,几行代码就解决了。不过一想,单片机这样算也太慢了吧,要是一转编码器,频率变化几十次上百次,单片机还不累死了 [表情]
于是想换个查表方式吧。搞了一上午,把算法搞好,表也算好做出来了,一编译,晕!长出了好几百字节(这其中包括表本身约200字节,再加上算法中多句的加法代码),看来2051里面别想放了 [表情]
dds的控制字计算,大家有什么好的想法么?请各位指点 [表情]
'
在8051单片机里面是可以实现dds的累加器算法的