矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
楼主: laghi

AD9850使用心得体会(信号发生器,DDS,数字信号源)

  [复制链接]
     
 楼主| 发表于 2012-2-18 11:14:09 | 显示全部楼层
接下来就是程序了:
laghi.c
//============
#include <reg51.h>
#include <intrins.h>
#include <stdio.h>
sbit ad9850_bit_data =P1^4;  //ad9850的D7脚/PIN25
sbit ad9850_rest     =P1^5;  //ad9850的rest脚/PIN12
sbit ad9850_fq_up    =P1^6;  //ad9850的fq_up脚/PIN8
sbit ad9850_w_clk    =P1^7;  //ad9850的w_clk脚/PIN7
sbit SPK=P3^4;                //SPK定义为P3口的第4位,就是驱动蜂鸣器的脚


code unsigned char table[]=
                  {0x3f,0x06,0x5b,0x4f,
          0x66,0x6d,0x7d,0x07,
          0x7f,0x6f,0x48,0x5c,
          0x00,0x5e,0x76,0x71};
//共阴数码管显示 0-9 a-f 表
code unsigned char key_tab[17]={0xed,0x7e,0x7d,0x7b,
                                                                        0xbe,0xbd,0xbb,0xde,
                                                                        0xdd,0xdb,0x77,0xb7,
                                                                        0xee,0xd7,0xeb,0xe7,0Xff};
//========================此数组为键盘编码,
//Laghi采用类式类似电话按键的编码方式,方便以后设计
//        1        2        3        up                                        0x01 0x02 0x03 0x0a
//        4        5        6  dn对应16进制码 0x04 0x05 0x06 0x0b
//        7        8        9        M1                                        0x07 0x08 0x09 0x0d
//        *c 0 #ok        M1                                        0x0c 0x00 0x0e 0x0f
//打个比方,如果你按下0键,P0口读到数据为0xed
//如果你按下2键,P0口读到数据为0x7d,按下9键为0xdb,
//将读到的P0口数据经过查表法就能得到相应的16进制码                               
//键盘的读取,采用中断法,电路用一个4与门(74HC21)接入
//中断口(INT0),利用中断来扫描键盘矩阵,读取数据
//输入数据后按#确认后向ad9850发送控制数据,按*后重新输入频率
unsigned char l_tmpdate[8]={15,11,10,0,0,14,2,12};
//定义数组变量显示:Fo=000Hz
unsigned char l_key=0xff;                                        //定义变量,存放键值       
unsigned char l_keyold=0xFF;        //做为按键松开否的凭证                               
unsigned char count_i=0;
unsigned long freq=10000;
void ad9850_reset();//ad9850复位(串口模式)
void ad9850_wr(unsigned char w0,double frequence);
//向ad9850中写命令与数据(串口)//
void diszf();//处理转换给数码管显示字符
void ReadKey(void);   //扫描键盘 获取键值
void delay();//延时子函数,5个空指令
void display(unsigned char *lp,unsigned char lc);
//void AD9850_w(unsigned char *lp,unsigned char lc);
//数字的显示函数;lp为指向数组的地址,lc为显示的个数
//==================================================
void main(void)     //入口函数
{
        EA=1;                //首先开启总中断
        EX0=1;   //开启外部中断 0
        IT0=1;   // 设置成 下降沿触发方式
        P0=0xf0;        //P0口高位输高电平,经过74HC21四输入与门,
       //连接外中断0,有键按下调用中断函数
P1=0x00;
P2=0x00;
P3=0xff;
//***************************************************//
//                   测试程序freqHz频率               //
//---------------------------------------------------//
ad9850_reset();
//ad9850_wr(0x00,1000);//串行写1000Hz频率测试程序
//---------------------------------------------------//
        while(1){
                display(l_tmpdate,8);                        //输出获取的键值码
if(l_key==0x01){                        //1按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=1;break;
                                        case 2: freq=freq*10+1;break;                                       
                                        case 3: freq=freq*10+1;break;
                                        case 4: freq=freq*10+1;break;
                                        case 5: freq=freq*10+1;break;
                                        case 6: freq=freq*10+1;break;
                                        case 7: freq=freq*10+1;break;
                                        case 8: freq=freq*10+1;break;
                                                    }
                          count_i++;
                  }
           diszf();   
                                }
if(l_key==0x02){                        //2按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=2;break;
                                        case 2: freq=freq*10+2;break;                                       
                                        case 3: freq=freq*10+2;break;
                                        case 4: freq=freq*10+2;break;
                                        case 5: freq=freq*10+2;break;
                                        case 6: freq=freq*10+2;break;
                                        case 7: freq=freq*10+2;break;
                                        case 8: freq=freq*10+2;break;
                                                    }
                          count_i++;
                  }
           diszf();   
                               
                                }
if(l_key==0x03){                        //3按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=3;break;
                                        case 2: freq=freq*10+3;break;                                       
                                        case 3: freq=freq*10+3;break;
                                        case 4: freq=freq*10+3;break;
                                        case 5: freq=freq*10+3;break;
                                        case 6: freq=freq*10+3;break;
                                        case 7: freq=freq*10+3;break;
                                        case 8: freq=freq*10+3;break;
                                                    }
                          count_i++;
                  }
           diszf();   
                                }
if(l_key==0x04){                        //4按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=4;break;
                                        case 2: freq=freq*10+4;break;                                       
                                        case 3: freq=freq*10+4;break;
                                        case 4: freq=freq*10+4;break;
                                        case 5: freq=freq*10+4;break;
                                        case 6: freq=freq*10+4;break;
                                        case 7: freq=freq*10+4;break;
                                        case 8: freq=freq*10+4;break;
                                                    }
                          count_i++;
                  }
           diszf();   
                                }
if(l_key==0x05){                        //5按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=5;break;
                                        case 2: freq=freq*10+5;break;                                       
                                        case 3: freq=freq*10+5;break;
                                        case 4: freq=freq*10+5;break;
                                        case 5: freq=freq*10+5;break;
                                        case 6: freq=freq*10+5;break;
                                        case 7: freq=freq*10+5;break;
                                        case 8: freq=freq*10+5;break;
                                                    }
                          count_i++;
                  }
           diszf();   
                                }
if(l_key==0x06){                        //6按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=6;break;
                                        case 2: freq=freq*10+6;break;                                       
                                        case 3: freq=freq*10+6;break;
                                        case 4: freq=freq*10+6;break;
                                        case 5: freq=freq*10+6;break;
                                        case 6: freq=freq*10+6;break;
                                        case 7: freq=freq*10+6;break;
                                        case 8: freq=freq*10+6;break;
                                                    }
                          count_i++;
                  }
           diszf();   
                                }
if(l_key==0x07){                        //7按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=7;break;
                                        case 2: freq=freq*10+7;break;                                       
                                        case 3: freq=freq*10+7;break;
                                        case 4: freq=freq*10+7;break;
                                        case 5: freq=freq*10+7;break;
                                        case 6: freq=freq*10+7;break;
                                        case 7: freq=freq*10+7;break;
                                        case 8: freq=freq*10+7;break;
                                                    }
                          count_i++;
                  }
           diszf();   
                                }
if(l_key==0x08){                        //8按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=8;break;
                                        case 2: freq=freq*10+8;break;                                       
                                        case 3: freq=freq*10+8;break;
                                        case 4: freq=freq*10+8;break;
                                        case 5: freq=freq*10+8;break;
                                        case 6: freq=freq*10+8;break;
                                        case 7: freq=freq*10+8;break;
                                        case 8: freq=freq*10+8;break;
                                                    }
                          count_i++;
                  }
           diszf();
                                }
if(l_key==0x09){                        //9按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=9;break;
                                        case 2: freq=freq*10+9;break;                                       
                                        case 3: freq=freq*10+9;break;
                                        case 4: freq=freq*10+9;break;
                                        case 5: freq=freq*10+9;break;
                                        case 6: freq=freq*10+9;break;
                                        case 7: freq=freq*10+9;break;
                                        case 8: freq=freq*10+9;break;
                                                    }
                          count_i++;
                  }
           diszf();
                                }       
if(l_key==0x00){                        //0按键判断
           l_key=0xff;
           if(count_i && count_i<9){
                          switch(count_i){
                                        case 1: freq=0;break;
                                        case 2: freq=freq*10;break;                                       
                                        case 3: freq=freq*10;break;
                                        case 4: freq=freq*10;break;
                                        case 5: freq=freq*10;break;
                                        case 6: freq=freq*10;break;
                                        case 7: freq=freq*10;break;
                                        case 8: freq=freq*10;break;
                                                    }
                          count_i++;
                  }
           diszf();
                                }       
if(l_key==0x0a){                        //步进按键
           l_key=0xff;
                          freq+=100;
           diszf();
           ad9850_reset();
           ad9850_wr(0x00,freq);//串行写freqHz频率程序   
                                }
if(l_key==0x0b){                        //步退按键
           l_key=0xff;
                          freq-=100;
           diszf();
           ad9850_reset();
           ad9850_wr(0x00,freq);//串行写freqHz频率程序   
                                }
if(l_key==0x0c){                        //更改按键
           l_key=0xff;
                                count_i=1;
           freq=0;
           ad9850_reset();
                          diszf();               
                                }
if(l_key==0x0e){                        //确认输出按键
           l_key=0xff;
           count_i=0;
                          diszf();
           ad9850_reset();
           ad9850_wr(0x00,freq);//串行写freqHz频率程序
                                }       
if(l_key==0x0d){                        //记忆1按键
           l_key=0xff;
           count_i=0;
                          freq=38000000;
           diszf();
           ad9850_reset();
           ad9850_wr(0x00,freq);//串行写freqHz频率程序
                                }
if(l_key==0x0f){                        //记忆2按键,弄个蛙鸣的频率试试
           l_key=0xff;
           count_i=0;
                          freq=7023000;
           diszf();
           ad9850_reset();
           ad9850_wr(0x00,freq);//串行写freqHz频率程序
                                }
                }
}//入口函数结束。
void key_scan()   interrupt 0    //外部中断 0  0的优先级最高                                                

       
{
        EX0=0;        //在读键盘期间,我们关闭中断,防止干扰带来的多次中断
//为了消除抖动带来的干扰,在按下键后我们采用延时十多毫秒再读取键值
//如果采用循环语句来延时,比如(for,while。。。)会使CPU处理循环而占用
//系统资源,所以这里我们采用定时器中断法,让定时器等待十多毫秒触发定时器
//中断,这里用到定时器0
        TMOD&=0XF1;//设置定时器0为模式1方式,
        TH0=0X2E;  //设置初值,为12毫秒
        TL0=0X00;
        ET0=1;         //开启定时器中断0
        TR0=1;         //启动定时器计数       
}
void timer0_isr(void) interrupt 1        //定时器0的中断函数
{       
        TR0=0;                                                //中断后我们停止计数
        ReadKey();                                        //定时器计数12毫秒后产生中断,调用此函数,

读取键值
}
void ReadKey(void)                                                //读键盘值
{
        unsigned char i,j,key;
        j=0xfe;
        key=0xff;                        //设定初值
        for (i=0;i<4;i++){               
                P0=j;                                //P0口低4位循环输出0,扫描键盘
                //leday();
                if ((P0&0xf0)!=0xf0){        //如果有键按下,P0口高4位不会为1,                               

                                       
                        key=P0;                                //读取P0口,退出循环,否则循环下次
                        break;               
                }
                j=_crol_(j,1);                        //此函数功能为左循环移位
        }
        if (key==0xff){                                //如果读取不到P0口的值,比如是干扰,我们不做键值处

理,返回
                l_keyold=0xff;
                //l_key=0xff;
                P0=0xf0;                        //恢复P0口,等待按键按下
                EX0=1;                                        //返回之前,开启外中断
                SPK=1;
                return;
        }
//        SPK=0;                                        //有键按下,就驱动蜂鸣器响。有干扰就停了
        if(l_keyold==key){                //检测按键放开否,如果一样表明没放开,
                TH0=0X2E;                        //继续启动定时器,检测按键松开否
                TL0=0;
                TR0=1;               
                   return;
        }               
        TH0=0X2E;                       
        TL0=0;
        TR0=1;                                        //继续启动定时器,检测按键松开否

        l_keyold=key;                        //获取键码做为放开的凭证

        for(i=0;i<17;i++){                        //查表获得相应的16进制值存放l_key变量中
                if (key==key_tab)
      {
                        l_key=i;
                        break;
                }
        }
//程序运行到这里,就表明有键值被读取存放于l_key变量中,
//主程序就可以检测此变量做相应外理,此时我们回到主程序
}  
void display(unsigned char *lp,unsigned char lc)//显示
{
        unsigned char i;                //定义变量
        P2=0;                                        //端口2为输出
        P1=P1&0xF8;                                //将P1口的前3位输出0,对应138译门输入脚,全0为第一

位数码管
        for(i=0;i<lc;i++)
   {                //循环显示
        P2=table[lp];        //查表法得到要显示数字的数码段
        delay();                                //延时5个空指令       
        if(i==7)                                //检测显示完8位否,完成直接退出,不让P1口再加1,否

则进位影响到第四位数据
                break;
        P2=0;                                        //清0端口,准备显示下位
        P1++;                                        //下一位数码管
        }
}
void diszf()//处理转换给数码管显示字符
{
bit nums=1;
unsigned long tmp;
                        l_tmpdate[0]=freq/10000000;
                  tmp=freq/10000000;
         if(tmp==0 && nums)l_tmpdate[0]=12;
                           else {
                              nums=0; }
                  tmp=freq%10000000;
                        l_tmpdate[1]=tmp/1000000;
         if(l_tmpdate[1]==0 && nums)l_tmpdate[1]=12;
                           else {
                              nums=0; }
                  tmp=tmp%1000000;
                        l_tmpdate[2]=tmp/100000;
         if(l_tmpdate[2]==0 && nums)l_tmpdate[2]=12;
                           else {
                              nums=0; }
                  tmp=tmp%100000;
                        l_tmpdate[3]=tmp/10000;
         if(l_tmpdate[3]==0 && nums)l_tmpdate[3]=12;
                           else {
                              nums=0; }
                  tmp=tmp%10000;
                        l_tmpdate[4]=tmp/1000;
         if(l_tmpdate[4]==0 && nums)l_tmpdate[4]=12;
                           else {
                              nums=0; }
                  tmp=tmp%1000;
                        l_tmpdate[5]=tmp/100;
         if(l_tmpdate[5]==0 && nums)l_tmpdate[5]=12;
                           else {
                              nums=0; }
                  tmp=tmp%100;
                        l_tmpdate[6]=tmp/10;
         if(l_tmpdate[6]==0 && nums)l_tmpdate[6]=12;
                           else {
                              nums=0; }
                  tmp=tmp%10;
              l_tmpdate[7]=tmp%10;
}
//***************************************************//
//              ad9850复位(串口模式)                 //
//---------------------------------------------------//
void ad9850_reset()
{
ad9850_w_clk=0;
ad9850_fq_up=0;
//rest信号
ad9850_rest=0;
ad9850_rest=1;
ad9850_rest=0;
//w_clk信号
ad9850_w_clk=0;
ad9850_w_clk=1;
ad9850_w_clk=0;
//fq_up信号
ad9850_fq_up=0;
ad9850_fq_up=1;
ad9850_fq_up=0;
}
//***************************************************//
//          向ad9850中写命令与数据(串口)             //
//---------------------------------------------------//
void ad9850_wr(unsigned char w0,double frequence)
{
unsigned char i,w;
long int y;
double x;//和long int长度一样,但是实验告诉.......
//计算频率的HEX值
x=4294795550/125;//修正频率使之更精确,减小晶振带来的误差
//x=4294967295/125;//适合125M晶振,理论算法
//如果时钟频率不为125MHZ,修改该处的频率值,单位MHz  !!!
frequence=frequence/1000000;
frequence=frequence*x;
y=frequence;
//写w4数据
w=(y>>=0);
for(i=0;i<8;i++)
{
ad9850_bit_data=(w>>i)&0x01;
ad9850_w_clk=1;
ad9850_w_clk=0;
}
//写w3数据
w=(y>>8);
for(i=0;i<8;i++)
{
ad9850_bit_data=(w>>i)&0x01;
ad9850_w_clk=1;
ad9850_w_clk=0;
}
//写w2数据
w=(y>>16);
for(i=0;i<8;i++)
{
ad9850_bit_data=(w>>i)&0x01;
ad9850_w_clk=1;
ad9850_w_clk=0;
}
//写w1数据
w=(y>>24);
for(i=0;i<8;i++)
{
ad9850_bit_data=(w>>i)&0x01;
ad9850_w_clk=1;
ad9850_w_clk=0;
}
//写w0数据
w=w0;   
for(i=0;i<8;i++)
{
ad9850_bit_data=(w>>i)&0x01;
ad9850_w_clk=1;
ad9850_w_clk=0;
}
//移入始能
ad9850_fq_up=1;
ad9850_fq_up=0;
}
//================================================
void delay(void)                                                                //空5个指令
{
        _nop_();_nop_();_nop_();_nop_();_nop_();
}

评分

2

查看全部评分

回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 11:18:25 | 显示全部楼层
laghi.rar (3.65 KB, 下载次数: 1164)
共享源代码
写入程序我用这个:
51pro.JPG
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 11:35:48 | 显示全部楼层
第五个问题就是通电试验,但由于节奏过快,这个问题先停下。
说说电脑前的操作,还有单片机控制AD9850。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 11:46:46 | 显示全部楼层
编程我用Keil uVision2(51 C语言)安装后打开。
新建工程:
uv.JPG
弹出保存对话框,命名保存。
uv1.JPG
接着要选CPU,选择atmel的89S52确定
回复 支持 反对

使用道具 举报

     
发表于 2012-2-18 12:07:55 | 显示全部楼层
据说 DDS 的噪音特性有点讨厌啊,  玩玩还好。  

        用来做本振还不如三极管单管振荡器。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 13:25:23 | 显示全部楼层
回复 28# e3po


    说只是一说而已,具体还得实验。就好像说LC振荡不稳定一样,原来的接收机还不就用着。而且到现在性能还不错,
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 13:36:31 | 显示全部楼层
接下来要添加文件(laghi.c)“源程序”右键添加
然后要设置目标属性
uv3.JPG
uv4.JPG
更改晶体频率为实际工作频率(便于调试)
特别注意一定选红圈里的生成Hex文件
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 13:50:45 | 显示全部楼层
用该软件生成HEX文件点击红圈那里
uv4.JPG
之后在原文件夹里找。hex文件
用51PRO写入单片机
附带编译好的文件:
Laghi.rar (5.87 KB, 下载次数: 836)
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 13:53:28 | 显示全部楼层
顺便带上vu2工程文件:
Laghi.rar (7.31 KB, 下载次数: 851)
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 14:22:46 | 显示全部楼层
写入程序后
uv.JPG
初始化显示Fo=00Hz,呵呵小成。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 14:26:25 | 显示全部楼层
第五个问题就是测试了:
连接后
uv4.JPG
通电后:
uv3.JPG
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 14:32:32 | 显示全部楼层
使其输出1HZ看看:
uv3.JPG
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 15:34:53 | 显示全部楼层
1-40000000Hz测试信号输出幅度>100mV而<1000mV。
性能不错,在30M以后杂散较大点,40M以后波形变劣。
在1-25000000Hz上看起来很纯净。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 15:45:11 | 显示全部楼层
输入20000后确认,示波器上看到
uv4.JPG
uv3.JPG
输入20HZ
uv1.JPG
示波器上看到
uv.JPG
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2012-2-18 15:47:47 | 显示全部楼层
本帖最后由 laghi 于 2012-2-18 15:49 编辑

可以看出在20-20000Hz上输出幅度非常稳定,这是难得的,因为一些高档电脑上其输出幅度都不均衡,不是幅频逐渐高了就是逐渐低了
在这当中任意频率都很好。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-5-7 05:02

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表