找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5332|回复: 4
打印 上一主题 下一主题
收起左侧

单片机波形/函数信号发生器源码与仿真设计(10-100HZ)

[复制链接]
跳转到指定楼层
楼主
给大家分享一个可以产生10-100HZ信号的51单片机信号发生器设计,DAC0832数模转换电路+LM358放大电路,调节电位器使得波形不失真.

示波器被关闭怎么打开:
停止仿真状态下,点工具栏的调试(Debug)按钮,然后点恢复弹出窗口(Reset Popup Windows),弹出窗口点是(Yes)。

带波形选择,频率加,频率减,步进值这几个调节按钮

波形/函数信号发生器仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


波形/函数信号发生器的单片机源程序如下:
  1. #include<reg52.h>                                           //包含头文件
  2. #include<intrins.h>
  3. #define uchar unsigned char                           //宏定义
  4. #define uint unsigned int

  5. sbit s1=P3^5;                          //定义按键的接口
  6. sbit s2=P3^6;
  7. sbit s3=P3^7;
  8. sbit s4=P3^4;

  9. sbit led0=P3^0;                         //定义四个LED,分别表示不同的波形
  10. sbit led1=P3^1;
  11. sbit led2=P3^2;
  12. sbit led3=P3^3;
  13.                                        
  14. sbit lcdrs=P2^7;                       //液晶控制引脚,还有一个控制脚是RW,因为我们只需要向液晶里写数据就好了,所以,我们直接将RW引脚接地
  15. sbit lcden=P2^6;

  16. char num,boxing,u;                     //定义全局变量
  17. uchar pinlv=100,bujin=1,bujin1=1;          //频率初始值是10Hz,步进值默认是0.1,显示步进值变量
  18. uchar code table[]="0123456789";        //定义显示的数组
  19. uchar code table1[]="Fout=     Wave form:"; //初始化显示字符
  20. unsigned int m;                //定义变量 m
  21. int a,b,h,num1;                         //定义全局变量

  22. //自定义字符
  23. uchar code zifu[]={        //此数组内数据为液晶上显示波形符号的自定义字符
  24.                         0x0e,0x11,0x11,0x00,0x00,0x00,0x00,0x00,
  25.                         0x00,0x00,0x00,0x00,0x11,0x11,0x0e,0x00,      //正弦波    0  1

  26.                         0x00,0x07,0x04,0x04,0x04,0x04,0x1c,0x00,
  27.                         0x00,0x1c,0x04,0x04,0x04,0x04,0x07,0x00,      //矩形波    2  3

  28.                         0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00,
  29.                         0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00,      //三角波    4  5

  30.                         0x00,0x01,0x03,0x05,0x09,0x11,0x00,0x00,      //锯齿波    6
  31. };
  32. uchar code sin[64]={       //此数组内的数据为,da输出对应电压值对应的数字量,0是0V,255是5V
  33. 135,145,158,167,176,188,199,209,218,226,234,240,245,249,252,254,254,253,251,247,243,237,230,222,213,204,193,182,170,158,146,133,121,108,96,84,72,61,50,41,32,24,17,11,7,3,1,0,0,2,5,9,14,20,28,36,45,55,66,78,90,102,114,128
  34. };                    //正弦波取码
  35. uchar code juxing[64]={     //一个周期是采样64个点, 所以数组内是64个数据
  36. 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  37. 255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  38. };                    //矩形波取码

  39. uchar code sanjiao[64]={
  40. 0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248,
  41. 248,240,232,224,216,208,200,192,184,176,168,160,152,144,136,128,120,112,104,96,88,80,72,64,56,48,40,32,24,16,8,0
  42. };                      //三角波取码
  43. uchar code juchi[64]={
  44. 0,4,8,12,16,20,24,28,32,36,40,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125,130,134,138,142,
  45. 146,150,154,158,162,166,170,174,178,182,186,190,194,198,202,206,210,215,219,223,227,231,235,239,243,247,251,255
  46. };                    //锯齿波取码

  47. void delay(uint xms)     //延时函数
  48. {
  49.     int a,b;
  50.     for(a=xms;a>0;a--)
  51.         for(b=110;b>0;b--);
  52. }
  53. void write_com(uchar com)       //写命令函数
  54. {
  55.     lcdrs=0;
  56.     P0=com;
  57.     delay(1);
  58.     lcden=1;
  59.     delay(1);                                    
  60.     lcden=0;
  61. }

  62. void write_date(uchar date)     //写数据函数
  63. {
  64.     lcdrs=0;
  65.     P0=date;
  66.     delay(1);
  67.     lcden=1;
  68.     delay(1);
  69.     lcden=0;
  70. }

  71. //自定义字符集
  72. void Lcd_ram()      
  73. {
  74.     uint i,j,k=0,temp=0x40;
  75.     for(i=0;i<7;i++)
  76.     {
  77.        for(j=0;j<8;j++)
  78.        {
  79.         write_com(temp+j);
  80.         write_date(zifu[k]);
  81.         k++;
  82.        }
  83.        temp=temp+8;
  84.     }
  85. }

  86. void init_lcd()                 //初始化函数
  87. {
  88.     uchar i;                                 
  89.     lcden=0;                    //默认开始状态为关使能端,见时序图  
  90.     Lcd_ram();
  91.     write_com(0x01);            //显示清屏,将上次的内容清除,默认为0x01.
  92.     write_com(0x0f);
  93.     write_com(0x38);            //显示模式设置,默认为0x38,不用变。
  94.     write_com(0x0c);            //显示功能设置0x0f为开显示,显示光标,光标闪烁;0x0c为开显示,不显光标,光标不闪
  95.     write_com(0x06);            //设置光标状态默认0x06,为读一个字符光标加1.
  96.     write_com(0x80);            //设置初始化数据指针,是在读指令的操作里进行的
  97.     for(i=10;i<20;i++)             //显示初始化
  98.     {
  99.         write_date(table1[i]);         //显示第一行字符
  100.     }
  101.     write_com(0x80+40);            //选择第二行
  102.     for(i=0;i<9;i++)
  103.     {
  104.         write_date(table1[i]);         //显示第二行字符
  105.     }
  106.     write_com(0x80+10);                //选择第一行第十个位置
  107.     write_date(0);
  108.     write_date(1);
  109.     write_date(0);
  110.     write_date(1);
  111.     write_date(0);
  112.     write_date(1);                     //显示自定义的波形图案
  113.     write_com(0x80+0x40+0x09);          //选择第二行第九个位置
  114.     write_date(' ');
  115.     write_date('1');
  116.     write_date('0');
  117.     write_date('.');
  118.     write_date('0');
  119.     write_date('H');
  120.     write_date('z');                   //显示初始的频率值
  121. }
  122. void initclock()               //定时器初始化函数
  123. {
  124.     TMOD=0x01;                 //定时器的工作方式
  125.     TH0=a;
  126.     TL0=b;                     //定时器赋初值
  127.     EA=1;                      //打开中断总开关
  128.     ET0=1;                     //打开定时器允许中断开关
  129.     TR0=1;                     //打开定时器定时开关
  130. }
  131. void display()                 //显示函数
  132. {
  133.     uchar qian,bai,shi,ge;     //定义变量用于显示
  134.     qian=pinlv/1000;           //将频率值拆成一位的数据,将数据除以1000,得到的商是一位数,赋值给qian
  135.     bai=pinlv%1000/100;        //将频率除以1000的余数再除以100就得到了频率的百位,赋值给bai
  136.     shi=pinlv%1000%100/10;     //同上,得到频率的十位
  137.     ge=pinlv%1000/100%10;
  138.     write_com(0x80+0x40+0x09); //选中第二行第九个位置

  139.     if(qian==0)                //千位如果为0
  140.     write_date(' ');           //不显示
  141.     else                       //千位不为0
  142. write_date(table[qian]);   //正常显示千位

  143.     if(qian==0&&bai==0)        //千位和百位都为0
  144.     write_date(' ');           //百位不显示
  145.     else                       //不都为0
  146.     write_date(table[bai]);    //百位正常显示
  147.     write_date(table[shi]);    //显示十位数
  148.     write_date('.');           //显示小数点
  149.     write_date(table[ge]);     //显示个位
  150.     write_date('H');           //显示频率的单位Hz
  151.     write_date('z');
  152.     if(boxing==0)              //判断波形为正弦波
  153.     {
  154.         write_com(0x80+10);    //选中一行频率图案位置
  155.         write_date(0);         //显示正弦波图案
  156.         write_date(1);
  157.         write_date(0);
  158.         write_date(1);
  159.         write_date(0);
  160.         write_date(1);
  161.         led3=1;
  162.         led0=0;                 //点亮正弦波指示灯
  163.     }
  164.     if(boxing==1)               //注释同上
  165.     {
  166.         write_com(0x80+10);
  167.         write_date(2);
  168.         write_date(3);
  169.         write_date(2);
  170.         write_date(3);
  171.         write_date(2);
  172.         write_date(3);
  173.         led0=1;
  174.         led1=0;
  175.     }


  176.     if(boxing==2)
  177.     {
  178.         write_com(0x80+10);
  179.         write_date(4);
  180.         write_date(5);
  181.         write_date(4);
  182.         write_date(5);
  183.         write_date(4);
  184.         write_date(5);
  185.         led1=1;
  186.         led2=0;
  187.     }
  188.     if(boxing==3)
  189.     {
  190.         write_com(0x80+10);
  191.         write_date(6);
  192.         write_date(6);
  193.         write_date(6);
  194.         write_date(6);
  195.         write_date(6);
  196.         write_date(6);
  197.         led2=1;
  198.         led3=0;
  199.     }
  200. }
  201. void keyscan()                  //频率调节键盘检测函数
  202. {
  203.     if(s1==0)                   //加按键是否按下
  204.     {   
  205.         EA=0;                   //关闭中断
  206.         delay(2);               //延时去抖
  207.         if(s1==0)               //再次判断
  208.         {
  209.             while(!s1);         //按键松开
  210.             pinlv+=bujin;       //频率以步进值加
  211.             if(pinlv>1000)      //最大加到100Hz
  212.             {
  213.                 pinlv=100;      //100Hz
  214.             }
  215.             display();          //显示函数
  216.             m=65536-(150000/pinlv);//计算频率
  217. /*频率值最小是10Hz,pinlv的值是100(因为要显示小数点后一位),150000/100=1500,这个1500就是定时器需要计时的,单位是us,65536-1500得到的是定时器的初值,
  218. 先不管初值,先看定时时间,1500us,一个波形的周期是由64个定时组成的,所以,一个波形周期就是64*1500us=96000,也就是96ms,约等
  219. 于100ms,也就是10Hz的频率*/
  220.             a=m/256;            //将定时器的初值赋值给变量
  221.             b=m%256;
  222.             EA=1;               //打开中断总开关
  223.         }
  224.     }
  225.     if(s2==0)                   //减按键按下
  226.     {   
  227.         
  228.         delay(5);
  229.         if(s2==0)
  230.         {
  231.             EA=0;   
  232.             while(!s2);
  233.             pinlv-=bujin;          //频率以步进值减
  234.             if(pinlv<100)
  235.             {
  236.                 pinlv=100;
  237.             }
  238.             display();
  239.             m=65536-(15000/pinlv);
  240.             a=m/256;
  241.             b=m%256;   
  242.             EA=1;
  243.         }
  244.     }
  245.     if(s3==0)                    //波形切换按键
  246.     {   
  247.         delay(5);
  248.         if(s3==0)
  249.         {
  250.             EA=0;
  251.             while(!s3);
  252.             boxing++;              //波形切换
  253.             if(boxing>=4)          //4种波形
  254.             {
  255.                 boxing=0;
  256.             }
  257.             display();
  258.             EA=1;
  259.         }
  260.     }   
  261. }
  262. void bujindisplay()              //步进值设置界面显示程序
  263. {
  264.     uint bai,shi,ge;             //定义步进值 百十个位
  265.     bai=bujin1/100;              //将步进值除以100得到百位,也就是频率值的十位,因为有一个小数位
  266.     shi=bujin1%100/10;           //将步进值除以100的余数除以十得到十位
  267.     ge=bujin1%100%10;            //取余10后得到个位,也就是频率步进值的小数点后一位
  268.     write_com(0x80+11);          //选中液晶第一行第十一列
  269.     if(bai==0)                   //百位是否为0
  270.     write_date(' ');             //百位不显示
  271.     else                         //百位不为0
  272.     write_date(table[bai]);      //显示百位数据
  273.     write_date(table[shi]);      //显示十位数据
  274.     write_date('.');             //显示小数点
  275.     write_date(table[ge]);       //显示个位,也就是小数点后一位
  276. }
  277. void bujinjiance()               //步进值设置键盘程序
  278. {
  279.     if(s4==0)                    //步进设置按键按下
  280.     {
  281.         delay(5);                //延时去抖
  282.         if(s4==0)                //再次判断按键
  283.         {
  284.              while(!s4);         //按键释放,按键松开才继续向下执行
  285.              h++;                //变量加
  286.              if(h==1)            //进入设置状态时
  287.              {
  288.                  write_com(0x01);             //清屏
  289.                  write_com(0x80);             //初始化显示步进设置界面
  290.                  write_date('S');delay(1);    //step value
  291.                  write_date('t');delay(1);
  292.                  write_date('e');delay(1);
  293.                  write_date('p');delay(1);
  294.                  write_date(' ');delay(1);
  295.                  write_date('v');delay(1);
  296.                  write_date('a');delay(1);
  297.                  write_date('l');delay(1);
  298.                  write_date('u');delay(1);
  299.                  write_date('e');delay(1);
  300.                  write_date(':');delay(1);
  301.                  bujin1=bujin;                //步进值赋值给临时变量
  302.                  
  303.                  bujindisplay();              //显示步进值
  304.              }
  305.              if(h==2)                         //退出设置
  306.              {
  307.                 h=0;                          //清零
  308.                 bujin=bujin1;                 //设置好的临时步进值赋值给步进变量
  309.                
  310.                 init_lcd();                   //初始化液晶显示
  311.                 initclock();                  //定时器初始化
  312.                 display();                    //调用显示程序
  313.              }
  314.         }
  315.     }
  316.     if(h==1)                                  //设置步进值时
  317.     {
  318.         if(s1==0)                             //加按键按下
  319.         {
  320.             delay(5);                         //延时去抖
  321.             if(s1==0)                         //再次判断
  322.             {
  323.                 while(!s1);                   //按键释放
  324.                 bujin1++;                     //步进值加1
  325.                 if(bujin1>=101)               //步进值最大100,也就是10.0Hz
  326.                 {
  327.                     bujin1=1;                 //超过最大值就恢复到0.1Hz
  328.                 }
  329.                 bujindisplay();               //步进显示
  330.             }
  331.         }
  332.         if(s2==0)                             //减按键,注释同上
  333.         {
  334.             delay(5);
  335.             if(s2==0)
  336.             {
  337.                 while(!s2);
  338.                 bujin1--;                     //步进减
  339.                 if(bujin1<=0)
  340.                 {
  341.                     bujin1=100;
  342.                 }
  343.                 bujindisplay();
  344.             }
  345.         }
  346.     }
  347. }
  348. void main()                  //主函数
  349. {   
  350.     init_lcd();              //调用初始化程序
  351.     m=65536-(15000/pinlv);   //定时器初值
  352.     a=m/256;
  353.     b=m%256;
  354.     initclock();             //定时器初始化
  355.     led0=0;                  //点亮第一个波形指示灯
  356.     while(1)                 //进入while循环,括号内为1,一直成立,所以也叫死循环,程序不会跳出,一直在内执行
  357.     {
  358.         if(h==0)             //正常模式不是步进调节
  359.         {
  360.             keyscan();       //扫描按键
  361.         //  display();
  362.         }
  363.          
  364.         bujinjiance();       //扫描步进调节程序

  365.         switch(boxing)                          //选择波形
  366.         {
  367.             case 0 : P1=sin[u]; break;          //正弦波
  368.             case 1 : P1=juxing[u]; break;       //矩形波
  369.             case 2 : P1=sanjiao[u]; break;      //三角波
  370.             case 3 : P1=juchi[u]; break;        //锯齿波
  371.         }
  372.     }
  373. }
  374. void T0_time()interrupt 1          //定时器
  375. {
  376.     TH0=a;
  377.     TL0=b;                         //根据不同的初值,定时器定时时间不同,达到不同频率的目的
  378.     u++;                           //变量加
  379.     if(u>=64)                      //一个周期采样64个点, 所以加到64就清零
  380.     u=0;                           //u清零
  381. ……………………

  382. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码


所有资料51hei提供下载:

0422.zip (97.94 KB, 下载次数: 93)


评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:305306 发表于 2018-4-24 15:42 | 只看该作者
亲 ,我想知道DAC旁边接的电阻电容的作用是什么  还有LM358放大模块的工作原理是什么
回复

使用道具 举报

板凳
ID:266734 发表于 2018-7-4 13:16 | 只看该作者
楼主没波形显示啊,而且改了参数之后,走了波形,但是LCD一直没有显示
回复

使用道具 举报

地板
ID:348399 发表于 2018-11-3 08:46 | 只看该作者
不显示啊楼主,没有波形
回复

使用道具 举报

5#
ID:92810 发表于 2018-11-4 22:16 | 只看该作者
学习学习才行了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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