原创 基于ad9851的 信号发生器

2009-6-18 08:25 9938 8 41 分类: MCU/ 嵌入式

 本人有一块个人闲置的ad9852芯片转让;需要者点击本链接,进入本人淘宝店


 


最近几年的电子设计大赛,差不多每年都考了DDS的设计。本人曾经也调试过DDS,但走了一些弯路,在这里写下一些心得,希望能对初调者有点帮助。下面将有电路图,以及详细的代码。


  学过FPGA的同仁们,应该对DDS的原理就会有很好的理解了。用FPGA是很容易把一个简单型的ad8952烧出来的!其实原理相当的简单,无非就是由相位累加器,相位调制器,正弦查找ROMDAC构成。通过改变相位累加的增量就很容易的改变的输出的频率了。


  如果相位累加器(频率控制子)的位宽为N位(ad9851N=32位)这就意味着把一个周期的正弦波形离散成了2N次方个点,把这些点的幅值存在一个ROM中就构成了正弦查找ROM。如果系统时钟为Fclk,即把Fclk分成了2N次方份。如果此时的相位累加增量为(频率控制字)为B,那么此时的输出频率应为Fout=(B*Fclk)/<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />N。显然B=1时其最小值为Fclk/ NB的值也不能太大,否则会输出失真波形。Fout的最大值理论上应该至少小于Fclk/4。所以要想提高输出频率的最大值,就得靠提高系统的外部时钟Fclk<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


   下面结合本人的代码来具体讲讲AD9851的应用。


AD9851的一些具体介绍这里就不说了。其DATASHEET上都说的很清楚。若看不懂E文,可以发E_M给我,我有中文资料。AD9851要写40位的控制子。其中前面32位就是频率控制子了。后面是有16倍频使能位,1logic0位,1POWER_DOWN位,还有5位相位模式字。这里我们只解决频率控制问题。也就是说在代码中本人只写了,32位的频率控制子,还有一个6倍频使能。其余的剩下几位由于没用到也就默认写为0了。AD9851可以用并和串俩中方式写入控制子。


其串行发送方式的控制子表如下:


点击看大图


本人主要将用串写控制子的时序与代码。其并的方式的代码也会给出。硬件电路图网上有很多资源,自己去找找!


主要看看代码吧:


/*************************************************************


 ad9851串口驱动程序


 2007-8-28-------------water


************************************************************/


#include <reg52.h>


#include <intrins.h>


#include <ABSACC.H> 


//-----------------------定义管脚--------------------------------------------------------


sbit     D7=P3^3;                        //控制子串传送位


sbit     DDS_FQUD=P3^4;         //更新发送频率


sbit     DDS_CLK=P3^5;     //接外部晶振时钟 这里为30M


unsigned long control_word(float  freq);


void send_control( unsigned long  bytedata);  


 


void AD9851Init(void)                     //DDS初始化函数,包括DDS复位和初始化为串行发送


{


      DDS_CLK=0;


    DDS_FQUD=0;


    DDS_CLK=1;


    DDS_CLK=0;


    DDS_FQUD=1;


      DDS_FQUD=0;


}


 


main()


{


      unsigned long  x;


      DDS_FQUD=0;


      AD9851Init();


      x=control_word(500000);


     


      while(1)


      send_control(x);


}


 


//计算9851控制字,freq为你要输出的频率


unsigned long control_word(float freq)                      


{


unsigned long  water;


water=23.86115*freq;//外部晶振为30M6倍频后180M,其关系由公式算出。


//water=143.456*freq;      //若不用6倍频,则其关系


      return(water);


}


 


//发送控制字


void send_control( unsigned long  bytedata)


{ 


     int i;


       unsigned char model="0x01";//模式选择为六倍频


     DDS_FQUD=0;


     _nop_();_nop_();_nop_();_nop_();_nop_();


     for(i=0;i<32;i++)//先写32位的频率控制子(现低位后高位)


     {


     D7=(bit)(bytedata&(0x00000001));     //按时序写入


     DDS_CLK=1;


     _nop_();_nop_();_nop_();_nop_();_nop_();  //必要的时序延时


     DDS_CLK=0;                 


     _nop_();_nop_();_nop_();_nop_();_nop_();


     bytedata>>=1;


     }


     for(i=0;i<8;i++)//再写其他8位控制字,这里只写了6倍频使能


     {


        D7=(bit)(model&(0x01));


        DDS_CLK=1;


        _nop_();_nop_();_nop_();_nop_();_nop_(); 


        DDS_CLK=0;                 


        _nop_();_nop_();_nop_();_nop_();_nop_();


             model>>=1;


     }


     DDS_FQUD=1;              


     DDS_FQUD=0;


}


上面的代码中已经有详细的注解。其参考DATASHEET中的时序如下:


8bb26171-33a2-4e2e-886d-21f82fb55622.bmp


并行方式的驱动代码如下:


 


 


AD9851.H文件


//======IO Define=======


//sbit DDSRST="P2"^0;


sbit FQ_UD_AD9851=P3^3;


sbit W_CLK_AD9851=P3^4;


 


 


//======================


unsigned long int freq = 0;


//unsigned char Control_AD9851 = 0x09; //  Phase0 ,power down mode and 6 REFCLK Multiplier enable


//unsigned char Control_AD9851 = 0x00; //  Phase0 ,power on   mode and 6 REFCLK Multiplier disable


unsigned char Control_AD9851 = 0x01; //  Phase0 ,power on   mode and 6 REFCLK Multiplier enable


unsigned char W1=0X0e;//附初值为1MHZ


unsigned char W2=0X38;


unsigned char W3=0Xe3;


unsigned char W4=0X8e;


void Parallel2Serial_AD9851(void)


{    FQ_UD_AD9851=0;


     W_CLK_AD9851=0;


     P2=Control_AD9851;_nop_();_nop_();_nop_();_nop_();//延时很重要,对时序


     W_CLK_AD9851=1;//字装入信号,上升沿有效


     W_CLK_AD9851=0;


 


     P2=W1;_nop_();_nop_();_nop_();_nop_();_nop_();


     W_CLK_AD9851=1;


     W_CLK_AD9851=0;


 


     P2=W2;_nop_();_nop_();_nop_();_nop_();_nop_();


     W_CLK_AD9851=1;


     W_CLK_AD9851=0;


 


     P2=W3;_nop_();_nop_();_nop_();_nop_();_nop_();


     W_CLK_AD9851=1;


     W_CLK_AD9851=0;


 


     P2=W4;_nop_();_nop_();_nop_();_nop_();_nop_();


     W_CLK_AD9851=1;


     W_CLK_AD9851=0;


 


     FQ_UD_AD9851=1;


     FQ_UD_AD9851=0;


}


 


void Set_Freq(float Freqency)


{  


   //freq= (unsigned long int)(23.86092942*Freqency);     // SYSCLK = 180 MHz


   freq= (unsigned long int)(23.86115*Freqency);      // SYSCLK = 180 MHz


   W4=(unsigned char)freq&0xff;


   freq=freq>>8;


 


   W3=(unsigned char)freq&0xff;


   freq=freq>>8;


 


   W2=(unsigned char)freq&0xff;


   freq=freq>>8;


 


   W1=(unsigned char)freq&0xff;


    


   Parallel2Serial_AD9851();


}


AD9851.C文件


/*******************************************************


 ad9851并口驱动程序


 外部提供30MHZ晶振,6倍频率模式


2007-8-28-----------------water


 


*********************************************************/


 


#include<reg52.h>


#include <intrins.h>


#include <AD9851.h>


sbit RST_AD9851= P3^2; 


//长延时


void Delay80Ms(unsigned int k)


{


      unsigned int j;


      while(k--)


      {


             j=7269;


             while(j--);


      }


}


void main(void)


{


 RST_AD9851=1;


 RST_AD9851=1;


 RST_AD9851=0;


 //Set_Freq(23000000);//发送的频率


      while(1)


      {


Set_Freq(22000000);//发送的频率


      }


}


以上就是AD9851的驱动程序。


下面是本人用KS0108控制器的LCD做的任意频率信号发生器(当然为简单只写了正弦波和方波)AD9851是可以直接产生方波的(里面有比较器)。


866be798-8d31-4f7e-a01d-01934ce80838.bmp


全部代码如下(有兴趣的可以参考):


// body.h文件


 


void delay(unsigned int t);


void write_com(unsigned char cmdcode);


void write_data(unsigned char Dispdata);


unsigned char read_data();


 


void Clr_Scr();


void Disp_Img(unsigned char code *img);


 


 


void hz_disp16(unsigned char pag,unsigned char col, unsigned char code *hzk);


void hz_disp32(unsigned char pag,unsigned char col, unsigned char code *hzk);


void hz_disp48(unsigned char pag,unsigned char col, unsigned char code *hzk);


void hz_disp64(unsigned char pag,unsigned char col, unsigned char code *hzk);


void init_lcd();


void Putedot(unsigned char Order);


void Putstr( unsigned char *str   , unsigned char i , unsigned char lie, unsigned char hang);


void Msg(int flg)  ;


bit judge_hitkey()  ;


void mdelay(unsigned  int N)  ;


unsigned char kbscan(void);


 


unsigned long int covert_decimal_to_hex(unsigned long int r) ;


 


 


#define Disp_On  0x3f


#define Disp_Off 0x3e


#define Col_Add  0x40


#define Page_Add 0xb8


#define Start_Line 0xc0


                                                                    


#define Lcd_Bus P0 //MCU P1<------> LCM


 


sbit Mcs="P1"^5;  //Master chip enable


sbit Scs="P1"^6;  //Slave chip enable


sbit Enable="P1"^2; //6800 mode Enable single


sbit Di="P1"^0;  //Data or Instrument Select


sbit RW="P1"^1;  //Write or Read


sbit Lcd_Rst=P1^7; //Lcm reset


 


 


 


 


// body.c文件


#include <reg52.h>


#include <ctype.h>


#include <string.h>


#include <stdlib.h>


#include <stdio.h>


//#include <math.h>


#include "data.h"


//-----------液晶定义引脚-----------------------


#define Disp_On  0x3f


#define Disp_Off 0x3e


#define Col_Add  0x40


#define Page_Add 0xb8


#define Start_Line 0xc0


#define Lcd_Bus P0 //MCU P1<------> LCM


sbit Mcs="P1"^5;  //Master chip enable


sbit Scs="P1"^6;  //Slave chip enable


sbit Enable="P1"^2; //6800 mode Enable single


sbit Di="P1"^0;  //Data or Instrument Select


sbit RW="P1"^1;  //Write or Read


sbit Lcd_Rst=P1^7; //Lcm reset


//-----------------------ad9851定义管脚--------------------------------------------------------


sbit     D7=P3^3;                


sbit     DDS_FQUD=P3^4;         //更新发送频率


sbit     DDS_CLK=P3^5;


//--------------------ad9851函数声明-------------


unsigned long control_word(float  freq);


void send_control( unsigned long  bytedata);  


 


//-----------全局变量---------------------------


 unsigned char row;


 unsigned char col;


 extern    unsigned char j_j;   //一级菜单标志j_j为全局变量


 extern    float beauty;


/****************************液晶程序部分************************************/


/*------------------延时子程序-----------------------------*/


void delay(unsigned int t)


{


unsigned int i,j;


for(i=0;i<t;i++)


for(j=0;j<10;j++)


   ;


}


/*------------------写命令到LCD------------------------------*/


void write_com(unsigned char cmdcode)


{


 Di=0;


 RW=0;


 Lcd_Bus=cmdcode;


 delay(0);


 Enable=1;


 delay(0);


 Enable=0;


}


/*-------------------写数据到LCD----------------------------*/


void write_data(unsigned char Dispdata)


{


 Di=1;


 RW=0;


 Lcd_Bus=Dispdata;


 delay(0);


 Enable=1;


 delay(0);


 Enable=0;


}


/*-------------------LCD数据----------------------------*/


unsigned char read_data()


{


 unsigned char tmpin;


 Di=1;


 RW=1;


 delay(0);


 Enable=1;


 delay(0);


 Enable=0;


 tmpin=Lcd_Bus;


 return tmpin;


}


/*------------------清除内存---------------*/


void Clr_Scr()


{


 unsigned char j,k;


 Mcs=1;Scs=1;


 write_com(Page_Add+0);


 write_com(Col_Add+0);


 for(k=0;k<8;k++)


 {


  write_com(Page_Add+k);


  for(j=0;j<64;j++)write_data(0x00);


 }


}


 


/*---------------------指定位置显示汉字8*16-----------------------*/


void hz_disp8(unsigned char pag,unsigned char col, unsigned char code *hzk)


{


 unsigned char j="0",i=0;


 for(j=0;j<2;j++)


    {


     write_com(Page_Add+pag+j);


     write_com(Col_Add+col);


     for(i=0;i<8;i++) write_data(hzk[8*j+i]);


    }


}


/*---------------------指定位置显示汉字16*16-----------------------*/


void hz_disp16(unsigned char pag,unsigned char col, unsigned char code *hzk)


{


 unsigned char j="0",i=0;


 for(j=0;j<2;j++)


    {


    write_com(Page_Add+pag+j);


    write_com(Col_Add+col);


    for(i=0;i<16;i++) write_data(hzk[16*j+i]);


     }


}


 


/*---------------------显示32*16的汉字字窜-----------------------*/


void hz_disp32(unsigned char pag,unsigned char col, unsigned char code *hzk) 


{


 unsigned char j="0",i=0;


 for(j=0;j<2;j++)


  {


   write_com(Page_Add+pag+j);


   write_com(Col_Add+col);


   for(i=0;i<32;i++) write_data(hzk[32*j+i]);


  }


}


/*---------------------显示48*16的字窜----------------------*/


void hz_disp48(unsigned char pag,unsigned char col, unsigned char code *hzk) 


{


  unsigned char j="0",i=0;


  for(j=0;j<2;j++)


  {


   write_com(Page_Add+pag+j);


   write_com(Col_Add+col);


   for(i=0;i<48;i++) write_data(hzk[48*j+i]);


  }


}


/*--------------------显示64*16的字窜---------------------*/


void hz_disp64(unsigned char pag,unsigned char col, unsigned char code *hzk)  


{


  unsigned char j="0",i=0;


  for(j=0;j<2;j++)


  {


  write_com(Page_Add+pag+j);


  write_com(Col_Add+col);


  for(i=0;i<64;i++) write_data(hzk[64*j+i]);


  }


}


/*------------------初始化LCD--------------------------*/


void init_lcd()


{


 Lcd_Rst=0;


 delay(100);


 Lcd_Rst=1;


 delay(100);


 Mcs=1;


 Scs=1;


 delay(100);


 write_com(Disp_Off);


 write_com(Page_Add+0);


 write_com(Start_Line+0);


 write_com(Col_Add+0);


 write_com(Disp_On);


}


//-----------------半角字符点阵码数据输出----------------------


void Putedot(unsigned char Order)


{


      unsigned char cbyte, j="0",i=0;


      int x;


      x=Order * 0x10; 


      for(j=0;j<2;j++)


        {


         write_com(Page_Add+row+j);


         write_com(Col_Add+col);


         for(i=0;i<8;i++)


               {


                cbyte = Ezk[x];     


                write_data(cbyte);               //写输出一字节


                x++;


               }


        }


}


 


//------------------------一个字串的输出----------------------------------------


void Putstr( unsigned char *str   , unsigned char i , unsigned char lie, unsigned char hang)


{


      unsigned char j,X;


    for (j=0;j<i;j++)


             {


              col=lie+8*j;               //换列。。。。。肖注释


              row=hang;


           X = str[j];


              Putedot(X-0x20);             /*ascii码表从0x20开始*/


              }


}


/*************************键盘扫描程序部分*******************************/


//--------------判断是否有键按下,有返回1,没有返回0 ----------------


bit judge_hitkey()                   


{


 unsigned char scancode,keycode;


 scancode=0x0f;                    //P1.4~P1.7输出全11则无键闭合


 P2=scancode;


 keycode=P2;                      //P1.0~P1.3的状态


 if(keycode==0x0f)


 return(0);                        //1则无键闭合


 else


 return(1);                        //否则有键闭合


}


//---------------------延时---------------------------------


void mdelay(unsigned  int N) 


{


  int i;


  for(i=0;i<N;i++);


}


//----------------按键扫描--------------------------------


unsigned char kbscan(void)


{


unsigned char sccode,recode,key;


P2=0xf0;                      //置所有行为低电平,行扫描,列线输入(此时)


if((P2&0xf0)!=0xf0)           //判断是否有有键按下(读取列的真实状态,若第4列有键按下则P1的值会变成0111 0000),有往下执行


{


       mdelay(10000);                  //延时去抖动(10ms


   if((P2&0xf0)!=0xf0)        //再次判断列中是否是干扰信号,不是则向下执行


  {


    sccode=0xFE;                //逐行扫描初值(即先扫描第1行)


    while((sccode&0x10)!=0)       //行扫描完成时(即4行已经全部扫描完成)sccode1110 1111 停止while程序    


    {


     P2=sccode;                    //输出行扫描码


         if ((P2&0xf0)!=0xf0)          //本行有键按下(即P1(真实的状态)的高四位不全为1


     break;


     sccode=(sccode<<1)|0x01;//行扫描码左移一位


       }


      recode=(P2&0xf0)|0x0f; //


      key=~(sccode&recode); //返回行和列


        return(key);


    }


      


  }


}


 


/*------------------------------信息显示部分------------------------*/


void Msg(int flg) 


{   unsigned char STR1[]="1HZ";   //用字符窜输出,空间不够时改回,一律用字摸,把EZK库给删除


    unsigned char STR2[]="10HZ";


      unsigned char STR3[]="100HZ";


      unsigned char STR4[]="1kHZ";


      unsigned char STR5[]="(KHZ)";


    unsigned char STR6[]="ok";


    int i1=0,i2=0,i3=0,i4=0;


      unsigned char key="0" ;


      float beau="0", an="0";


      unsigned long  x;//频率控制字


    if(flg==1)          //信号发生器名字


     {


     Mcs=1;Scs=0;


     hz_disp48(3,16,xhf);


     Mcs=0;Scs=1;


     hz_disp48(3,0,syq);


     }


    if(flg==2)          //一级菜单界面


    {


     Mcs=1;Scs=0;


     hz_disp32(0,32,ry);


       hz_disp32(2,32,bj);


     Putstr(STR1,strlen(STR1),16,4);


     Putstr(STR2,strlen(STR2),16,6);


     Mcs=0;Scs=1;


     hz_disp16(0,0,p);


       hz_disp16(0,16,l);


       hz_disp32(2,0,xz);


     Putstr(STR3,strlen(STR3),16,4);


       Putstr(STR4,strlen(STR4),16,6);


       }


   if(flg==3)            //任意频率输入界面


    {


       int i="0",a=0,j=0;


       Clr_Scr();


       Mcs=1;Scs=0;


       hz_disp32(0,32,sr);


     Mcs=0;Scs=1;


       hz_disp16(0,0,p);


     hz_disp16(0,16,l);


     hz_disp8(0,32,mh);


       hz_disp32(3,32,hz);


     Mcs=1;Scs=0;


       while(1)                    //再次进入扫描死循环,键控键盘


        {


          j=i;//下面有用


        key=kbscan();             //再次扫描


          while(judge_hitkey());   //判断键释放


        Mcs=1;Scs=0;


          if(i<8)//只有8位数大的数据,若还要加大,则要稍改显示左右边


           {


            switch (key)


             {


               case 0x24:  hz_disp8(3,8*i,shu1[9]);an=9;i++;break;//i来确定数字显示的位置


                 case 0x28:  hz_disp8(3,8*i,shu1[8]);an=8;i++;break;//an来代表按下的数值


               case 0x41:  hz_disp8(3,8*i,shu1[7]);an=7;i++;break;


                 case 0x42:  hz_disp8(3,8*i,shu1[6]);an=6;i++;break;


                 case 0x44: hz_disp8(3,8*i,shu1[5]);an=5;i++;break;


                 case 0x48: hz_disp8(3,8*i,shu1[4]);an=4;i++;break;


               case 0x81:  hz_disp8(3,8*i,shu1[3]);an=3;i++;break;


                 case 0x82: hz_disp8(3,8*i,shu1[2]);an=2;i++;break;


                 case 0x84:  hz_disp8(3,8*i,shu1[1]);an=1;i++;break;


                 case 0x88: hz_disp8(3,8*i,shu1[0]);an=0;i++;break;


                 default :break;


                }


           }


          if(i!=j)//代表有按键按下,进行十进制移位,把按键值转为十进制数


             {


              beau=(float)beau*10;


            beau=(beau+an);


                 }


        if(key==0x18)           //按下确认键,


           {


            Mcs=1;Scs=0;


            Putstr(STR6,2,16,6);


            beauty=beau;     //  把十进制键值传给全局变量


              }


           x=control_word(beauty);//得到频率控制字


           send_control(x);//发送频率控制字


         if(key==0x14)     //退出死循环


           break;         //返回一级菜单


        }


        beau=0;


        beauty=0;     //清除键值


      Clr_Scr();      //清除此时界面


        j_j=0;            // 返回一级菜单界面


        i=0;          //清去i的数值


}


if(flg==4)             //步进为1HZ界面


  {


    


       Mcs=0;Scs=1;


       hz_disp32(3,0,hz);


       Mcs=1;Scs=0;  


     while(1)


        {


        key=kbscan();


          while(judge_hitkey());


          if(key==0x12) //每按一下加一HZ,i1位按下的次数


                i1++;


         if(key==0x11)


                 i1--;


        Mcs=1;Scs=0;


        hz_disp8(3,32,shu1[i1]);


          if(i1<0||i1>9)           //超出范围重0开始


                 i1=0;


          if(key==0x14) break;     //退出键


          if(key==0x18)  


          beauty=i1;          // 把步进值给全局变量beauty


             x=control_word(beauty);//得到频率控制字


        send_control(x);//发送频率控制字


      }


         beauty=0;


         Clr_Scr();


         j_j=0;            //返回一级菜单界面


         i1=0;          //消去i1的值


   }


 


if(flg==5)             //步进为10HZ界面


  {


    


       Mcs=0;Scs=1;


       hz_disp32(3,0,hz);


       Mcs=1;Scs=0;


      hz_disp8(3,32,shu1[0]);


     while(1)


        {


        key=kbscan();


         while(judge_hitkey());


          if(key==0x12)


                i2++;


         if(key==0x11)


                 i2--;


        Mcs=1;Scs=0;


        hz_disp8(3,24,shu1[i2]);


          if(i2<0||i2>9)           //超出范围重0开始


                 i2=0;


          if(key==0x14) break;     //退出键 返回一级菜单界面


          if(key==0x18) 


            beauty=(float)i2*10;           //把步进值给全局变量beauty


             x=control_word(beauty);//得到频率控制字


        send_control(x);//发送频率控制字


             }


             beauty=0;


          Clr_Scr();


          j_j=0;


          i2=0; 


   }


if(flg==6)         //步进为100HZ界面


  {


     Mcs=0;Scs=1;


       hz_disp32(3,0,hz);


       Mcs=1;Scs=0;


     hz_disp8(3,32,shu1[0]);


 


       hz_disp8(3,24,shu1[0]);


     while(1)


        {


        key=kbscan();


          while(judge_hitkey());


          if(key==0x12)


                i3++;


         if(key==0x11)


                 i3--;


        Mcs=1;Scs=0;


        hz_disp8(3,16,shu1[i3]);


          if(i3<0||i3>9)           //超出范围重0开始


                 i3=0;


          if(key==0x14) break;     //退出键 返回一级菜单界面


          if(key==0x18) 


           beauty=(float)i3*100;              //  把步进值给全局变量beauty   


             x=control_word(beauty);//得到频率控制字


        send_control(x);//发送频率控制字


        }


         beauty=0;


         Clr_Scr();


         j_j=0;


         i3=0; 


   }


 if(flg==7  )      //步进为1kHZ界面


  {


    


       Mcs=0;Scs=1;


       Putstr(STR5,strlen(STR5),0,3);


       Mcs=1;Scs=0;


     hz_disp8(3,56,shu1[0]);


     while(1)


        {


        key=kbscan();


          while(judge_hitkey());


          if(key==0x12)


                i4++;


         if(key==0x11)


                 i4--;


        Mcs=1;Scs=0;


        hz_disp8(3,56,shu1[i4]);


          if(i4<0||i4>9)           //超出范围重0开始


                 i4=0;


          if(key==0x14) break;     //退出键 返回一级菜单界面


          if(key==0x18) 


          beauty=(float)i4*1000;      //  把步进值给全局变量beauty   


         x=control_word(beauty);//得到频率控制字


       send_control(x);//发送频率控制字


        }


         beauty=0;


         Clr_Scr();


         j_j=0;


         i4=0;                 


   }


 }


//主程序所在文件                                                                                                                                     


//2007-8-14,修改,


 #include <reg52.h>


#include <ctype.h>


#include <string.h>


#include <stdlib.h>


#include <stdio.h>


#include <math.h>


#include <body.h>


#include <intrins.h>


#include <ABSACC.H> 


#include"data.h"


unsigned char j_j;


float beauty;//要输出的频率


//-----------------------ad9851定义管脚--------------------------------------------------------


sbit     D7=P3^3;                


sbit     DDS_FQUD=P3^4;         //更新发送频率


sbit     DDS_CLK=P3^5;    


unsigned long control_word(float  freq);


void send_control( unsigned long  bytedata);  


//-------------------ad9851部分-------------------------------------------------------------------------


//DDS初始化函数,包括DDS复位和初始化为串行发送


void AD9851Init(void)


{


      DDS_CLK=0;


    DDS_FQUD=0;


    DDS_CLK=1;


    DDS_CLK=0;


    DDS_FQUD=1;


      DDS_FQUD=0;


}


 


//计算9851控制字


unsigned long control_word(float freq)                      


{


      unsigned long  water;


      water=23.86115*freq;


      return(water);


}


 


//发送控制字


void send_control( unsigned long  bytedata)


{ 


     int i;


       unsigned char model="0x01";//模式选择为六倍频


     DDS_FQUD=0;


     _nop_();_nop_();_nop_();_nop_();_nop_();


     for(i=0;i<32;i++)


     {


     D7=(bit)(bytedata&(0x00000001));    


     DDS_CLK=1;


     _nop_();_nop_();_nop_();_nop_();_nop_(); 


     DDS_CLK=0;                 


     _nop_();_nop_();_nop_();_nop_();_nop_();


     bytedata>>=1;


     }


     for(i=0;i<8;i++)


     {


        D7=(bit)(model&(0x01));


        DDS_CLK=1;


        _nop_();_nop_();_nop_();_nop_();_nop_(); 


        DDS_CLK=0;                 


        _nop_();_nop_();_nop_();_nop_();_nop_();


             model>>=1;


     }


     DDS_FQUD=1;              


     DDS_FQUD=0;


}


 


//--------------------------主函数部分(主要包括菜单框架)----------------------------------------------


 


 main(void)


{


  unsigned char key;


   int i,menu,k;


  unsigned long  x;//频率控制字


 


  i=1;


  Clr_Scr();


  init_lcd();


  Msg(0);


  delay(5000);


  Clr_Scr();


  Msg(1);


  delay(8000);


  Clr_Scr();


  Msg(2);


  DDS_FQUD=0;


  AD9851Init();//ad9851初始化


  x=control_word(1000);//得到频率控制字


  send_control(x);//发送频率控制字


  while(1)


    {


      // x="control"_word(2500000);     //DDS


         x=control_word(beauty);//得到频率控制字


         send_control(x);//发送频率控制字


       key=kbscan();


       while(judge_hitkey());              //判断按键释放 肖注释


       switch(key)


       {


        case 0x12: i++;Clr_Scr(); break;


        case 0x11: i--;Clr_Scr(); break;


         case 0x18: j_j=1;Clr_Scr(); break;


         case 0x14: j_j=0;Clr_Scr(); break;


             }


     menu=10*j_j+i;


     if(j_j==0)


       {


         Msg(2);


              k=i;    //下面有用


         switch(i)


           {


             case 1: Mcs="1";Scs=0;hz_disp16(0,0,xia);break;


             case 2: Mcs="1";Scs=0;hz_disp16(4,0,xia);break;


             case 3: Mcs="1";Scs=0;hz_disp16(6,0,xia);break;


             case 4: Mcs="0";Scs=1;hz_disp16(4,0,xia);break;


             case 5: Mcs="0";Scs=1;hz_disp16(6,0,xia);break;


            }


        }


     if(j_j==1)


       {


          i=k;   //锁定2级菜单的光标键


        switch(menu)


                 {


                     case 11: Msg(3);break;


                     case 12: Msg(4);break;


                     case 13: Msg(5);break;


                     case 14: Msg(6);break;


                     case 15: Msg(7);break;


                    }


              


        }


      if(i>5||i==0)    //  光标超出菜单界面处理


      i=1;


  }


 }    


 


 

文章评论33条评论)

登录后参与讨论

用户377235 2013-8-29 17:09

博主你好!谢谢你的分享~但是图没有显示出来,可以发一份电路图和程序到我的邮箱么?谢谢!我的邮箱是:381283893@qq.com

飞言走笔 2011-9-8 12:06

这么多要代码和电路的,呵呵~

用户373296 2011-8-14 18:50

麻烦楼主给我发一份电路图和程序,小弟感激不尽!1185581586qq.com

fengyang.0104_212519044 2011-8-13 20:21

兄弟,给我也发个吧,我的9851出不了波形。需要电路图和程序,谢谢。fengyang.0104@163.com

用户325392 2011-5-9 11:06

非常感谢博主对大家的帮助,能不能给我也发一份中文资料以及原理图和程序吧。谢谢。xiaogang8781@qq.com

huli184_389376486 2010-9-23 10:17

博主,给我也发一份中文资料以及原理图和程序吧。谢谢。huli184@126.com

用户327552 2010-8-28 12:00

麻烦大哥给我一份程序和中文资料 感激不尽! antonieliu@126.com

用户302290 2010-4-25 15:19

兄弟这个很急啊,能不能明天发给我啊,乳沟你有时间做的话,谢谢啊。

用户302290 2010-4-25 15:17

基于单片机与MAX038的信号发生器的设计,用lcd1602显示频率、幅度与波形名称,麻烦发个设计的详细资料。包括程序哦,谢谢。我的邮箱xushaoyu1988@163.com

用户258861 2010-4-14 21:05

我在做基于DDS技术的频率合成信号发生器,打算用51单片机和AD9851做,请问有没有相关的电气原理图和程序代码可以参考啊?我的邮箱是284993874@qq.com,老兄有时间的话麻烦发一份给我。先谢谢你了。
相关推荐阅读
用户161601 2013-06-06 11:27
AT91LINUX编译试验 SAMA5DX cortex A5
atmel官方网站www.at91.com中对基于DTB的linux内核编译流程如下:   本文档为本人在ubuntu 10.04下实验流程,红色文字为本人添加的记录; by Jevon...
用户161601 2013-04-21 10:54
ubuntu10.04 vm6.5 hgfs 共享实现
以前用的VMWARE6.5+FC12安装好VM TOOL后 就可以在/mnt/hgfs 访问window中的共享文件夹了; 如今把FC12抛弃了,改装了ubuntu10.04但发现hgfs目录...
用户161601 2012-11-29 09:46
芯片制造工艺流程(转)
  芯片制造工艺流程   芯片制作完整过程包括 芯片设计、晶片制作、封装制作、成本测试等几个环节,其中晶片片制作过程尤为...
用户161601 2011-12-13 14:28
摄像头的组成以及红外摄像头
摄像头的工作原理大致为:景物通过镜头(LENS)生成的光学图像投射到图像传感器表面上,然后转为电信号,经过A/D(模数转换)转换后变为数字图像信号,再送到数字信号处理芯片(DSP)中加工处理,再通...
用户161601 2011-11-01 10:50
KEIL MDK生成 bin 文件 for nxp MCU
说明:本文的实践是基于lpc1343; 要想在keil中直接生成bin文件一般需要加用户命令调用fromelf工具: 如下图在Options for Target 中 加上编译后的命令; ...
用户161601 2011-10-09 11:52
基于新唐DMX512帧头的判断
DMX 512协议是Digital Multiplex的缩写,是灯光行业数字化设备的通用信号控制协议,同时也是是一种国际协议;由美国剧场技术协会(United State Institute for...
我要评论
33
8
关闭 站长推荐上一条 /2 下一条