找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于51单片机的正玄波和方波输出设计(源码+原理图+proteus仿真)

[复制链接]
跳转到指定楼层
楼主
题目:多路数据采集显示器设计
用的芯片是:STC90C516RD+,PCF8591
一、基本要求:
1、用DA转换器输出一正弦信号,频率150Hz
2、用AD转换器周期测量此正弦信号的频率,在数码管或LCD上将频率值显示出来,精确到0.1Hz
3、同时用IO口输出一500Hz的方波信号,用另一IO测量,显示信号参数,
4、设置一功能键,切换两种信号的显示参数
5、通过键盘,可修改方波的频率。每按一次键,频率步进或后退一定值,频率范围100Hz~1500Hz

二、发挥部分:
1、通过键盘,可修改正弦波的频率。每按一次键,频率步进或后退一定值,频率范围10Hz~1000Hz
2、显示器能同步反应参数的变化
3、按键时,蜂鸣器发出提示音,表示按键有效
显示格式:
使用LCD1602,参数必须能显示,并通过按键更改显示不同参数内容

三、protuse仿真运行图(方波和正玄波)


四、源代码见附件

单片机源程序如下:
  1. /*-----------------------------------------------
  2.   名称:LCD1602
  3.   编写:shifang
  4.   日期:2019-9-3
  5.   修改:无
  6.   内容:通过标准程序动态显示字符
  7.   引脚定义如下:1-VSS 2-VDD 3-V0 4-RS 5-R/W 6-E 7-14 DB0-DB7 15-BLA 16-BLK
  8. ------------------------------------------------*/
  9. #include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  10. #include<intrins.h>

  11. #define  _Nop()  _nop_()        //定义空指令
  12. bit ack;                      //应答标志位
  13. bit flag_dis=0;

  14. sbit SDA=P2^1;
  15. sbit SCL=P2^0;
  16. #define AddWr 0x90   //写数据地址
  17. #define AddRd 0x91   //读数据地址
  18. unsigned char ReadADC(unsigned char Chl);
  19. bit WriteDAC(unsigned char dat);

  20. //--定义全局变量--//
  21. unsigned char code table[] ={"Welcome use: 000 "};
  22. unsigned char code table1[]={"SIN:0000.0Hz FAG "};
  23. unsigned int dis,deg;     //{"D:0 Voltage:0.00"};

  24. sbit RS = P2^4;   //定义端口
  25. sbit RW = P2^5;
  26. sbit EN = P2^6;
  27. sbit out = P2^7;

  28. sbit k1 = P3^5;
  29. sbit k2 = P3^6;
  30. sbit k3 = P3^7;

  31. sbit out2 =P1^7;
  32. sbit buz = P1^2;

  33. unsigned int fh=150,fh2=100;        //初始频率为150Hz
  34. unsigned int t_10us=0,pinlv,t100us,t100us2;
  35. #define RS_CLR RS=0
  36. #define RS_SET RS=1

  37. #define RW_CLR RW=0
  38. #define RW_SET RW=1

  39. #define EN_CLR EN=0
  40. #define EN_SET EN=1

  41. #define DataPort P0

  42. unsigned char code table2[256] ={
  43.    0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95, 0x98, 0x9c, 0x9f,
  44.    0xa2, 0xa5, 0xa8, 0xab, 0xae, 0xb0, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf,
  45.    0xc1, 0xc4, 0xc7, 0xc9, 0xcc, 0xce, 0xd1, 0xd3, 0xd5, 0xd8, 0xda,
  46.    0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xed, 0xef,
  47.    0xf0, 0xf2, 0xf3, 0xf4, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
  48.    0xfc, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  49.    0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfb, 0xfa,
  50.    0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf3, 0xf2, 0xf0, 0xef, 0xed, 0xec,
  51.    0xea, 0xe8, 0xe6, 0xe4, 0xe3, 0xe1, 0xde, 0xdc, 0xda, 0xd8, 0xd6,
  52.    0xd3, 0xd1, 0xce, 0xcc, 0xc9, 0xc7, 0xc4, 0xc1, 0xbf, 0xbc, 0xb9,
  53.    0xb6, 0xb4, 0xb1, 0xae, 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, 0x99,
  54.    0x96, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x83, 0x80, 0x7d, 0x79, 0x76,
  55.    0x73, 0x70, 0x6d, 0x6a, 0x67, 0x64, 0x61, 0x5e, 0x5b, 0x58, 0x55,
  56.    0x52, 0x4f, 0x4c, 0x49, 0x46, 0x43, 0x41, 0x3e, 0x3b, 0x39, 0x36,
  57.    0x33, 0x31, 0x2e, 0x2c, 0x2a, 0x27, 0x25, 0x23, 0x21, 0x1f, 0x1d,
  58.    0x1b, 0x19, 0x17, 0x15, 0x14, 0x12, 0x10, 0x0f, 0x0d, 0x0c, 0x0b,
  59.    0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x03, 0x02, 0x01, 0x01,
  60.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  61.    0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
  62.    0x0a, 0x0c, 0x0d, 0x0e, 0x10, 0x12, 0x13, 0x15, 0x17, 0x18, 0x1a,
  63.    0x1c, 0x1e, 0x20, 0x23, 0x25, 0x27, 0x29, 0x2c, 0x2e, 0x30, 0x33,
  64.    0x35, 0x38, 0x3b, 0x3d, 0x40, 0x43, 0x46, 0x48, 0x4b, 0x4e, 0x51,
  65.    0x54, 0x57, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x73,
  66.    0x76, 0x79, 0x7c,
  67. };
  68. /*------------------------------------------------
  69. uS延时函数,含有输入参数 unsigned char t,无返回值
  70. unsigned char 是定义无符号字符变量,其值的范围是
  71. 0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
  72. 长度如下 T=tx2+5 uS
  73. ------------------------------------------------*/
  74. void DelayUs2x(unsigned int t)
  75. {   
  76. while(--t);
  77. }
  78. /*------------------------------------------------
  79. mS延时函数,含有输入参数 unsigned char t,无返回值
  80. unsigned char 是定义无符号字符变量,其值的范围是
  81. 0~255 这里使用晶振12M,精确延时请使用汇编
  82. ------------------------------------------------*/
  83. void DelayMs(unsigned int t)
  84. {
  85.      
  86. while(t--)
  87. {
  88.      //大致延时1mS
  89.      DelayUs2x(245);
  90.          DelayUs2x(245);
  91. }
  92. }

  93. /*------------------------------------------------
  94.                     启动总线
  95. ------------------------------------------------*/
  96. void Start_I2c()
  97. {
  98.   SDA=1;   //发送起始条件的数据信号
  99.   _Nop();
  100.   SCL=1;
  101.   _Nop();    //起始条件建立时间大于4.7us,延时
  102.   _Nop();
  103.   _Nop();
  104.   _Nop();   
  105.   SDA=0;     //发送起始信号
  106.   _Nop();    //起始条件锁定时间大于4μ
  107.   _Nop();
  108.   _Nop();
  109.   _Nop();      
  110.   SCL=0;    //钳住I2C总线,准备发送或接收数据
  111.   _Nop();
  112.   _Nop();
  113. }
  114. /*------------------------------------------------
  115.                     结束总线
  116. ------------------------------------------------*/
  117. void Stop_I2c()
  118. {
  119.   SDA=0;    //发送结束条件的数据信号
  120.   _Nop();   //发送结束条件的时钟信号
  121.   SCL=1;    //结束条件建立时间大于4μ
  122. /* _Nop();
  123.   _Nop();
  124.   _Nop();
  125.   _Nop();*/
  126.    DelayUs2x(1);
  127.   SDA=1;    //发送I2C总线结束信号
  128. /*  _Nop();
  129.   _Nop();
  130.   _Nop();*/
  131. }

  132. /*----------------------------------------------------------------
  133.                  字节数据传送函数               
  134. 函数原型: void  SendByte(unsigned char c);
  135. 功能:  将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
  136.      此状态位进行操作.(不应答或非应答都使ack=0 假)     
  137.      发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
  138. ------------------------------------------------------------------*/
  139. void  SendByte(unsigned char c)
  140. {
  141. unsigned char BitCnt;

  142. for(BitCnt=0;BitCnt<8;BitCnt++)  //要传送的数据长度为8位
  143.     {
  144.      if((c<<BitCnt)&0x80)SDA=1;   //判断发送位
  145.        else  SDA=0;               
  146.      _Nop();
  147.      SCL=1;               //置时钟线为高,通知被控器开始接收数据位
  148.       DelayUs2x(2);
  149.     /*  _Nop();             //保证时钟高电平周期大于4μ
  150.       _Nop();
  151.       _Nop();
  152.       _Nop();  */      
  153.      SCL=0;
  154.     }
  155.    
  156.   //  _Nop();
  157.     _Nop();
  158.     SDA=1;               //8位发送完后释放数据线,准备接收应答位
  159.   //  _Nop();
  160.     _Nop();   
  161.     SCL=1;
  162.     DelayUs2x(1);
  163.    /* _Nop();
  164.     _Nop();
  165.     _Nop();
  166.     if(SDA==1)ack=0;     
  167.        else ack=1;  */      //判断是否接收到应答信号
  168.     SCL=0;
  169.   //  _Nop();
  170. }

  171. /*----------------------------------------------------------------
  172.                  字节数据传送函数               
  173. 函数原型: unsigned char  RcvByte();
  174. 功能:  用来接收从器件传来的数据,并判断总线错误(不发应答信号),
  175.      发完后请用应答函数。  
  176. ------------------------------------------------------------------*/        
  177. unsigned char  RcvByte()
  178. {
  179.   unsigned char retc;
  180.   unsigned char BitCnt;
  181.   
  182.   retc=0;
  183.   SDA=1;             //置数据线为输入方式
  184.   for(BitCnt=0;BitCnt<8;BitCnt++)
  185.       {
  186.         _Nop();           
  187.         SCL=0;       //置时钟线为低,准备接收数据位
  188.         DelayUs2x(2);
  189.       /*  _Nop();
  190.         _Nop();      //时钟低电平周期大于4.7us
  191.         _Nop();
  192.         _Nop();
  193.         _Nop();*/
  194.         SCL=1;       //置时钟线为高使数据线上数据有效
  195.       //  _Nop();
  196.       //  _Nop();
  197.         retc=retc<<1;
  198.         if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
  199.      //   _Nop();
  200.      //   _Nop();
  201.       }
  202.   SCL=0;   
  203.   return(retc);
  204. }

  205. /*----------------------------------------------------------------
  206.                      非应答子函数
  207. 原型:  void NoAck_I2c(void);

  208. ----------------------------------------------------------------*/
  209. void NoAck_I2c(void)
  210. {
  211.   
  212.   SDA=1;
  213.    DelayUs2x(1);
  214. /* _Nop();
  215.   _Nop();
  216.   _Nop();   */   
  217.   SCL=1;
  218.   /*_Nop();
  219.   _Nop();              //时钟低电平周期大于4μ
  220.   _Nop();
  221.   _Nop(); */
  222.   DelayUs2x(1);
  223.   SCL=0;                //清时钟线,钳住I2C总线以便继续接收
  224. // _Nop();
  225. //_Nop();   
  226. }

  227. /*------------------------------------------------
  228.               写入命令函数
  229. ------------------------------------------------*/
  230. void LCD_Write_Com(unsigned char com)
  231. {  
  232. // while(LCD_Check_Busy()); //忙则等待
  233. DelayMs(5);
  234. RS_CLR;
  235. RW_CLR;
  236. EN_SET;
  237. DataPort= com;
  238. _nop_();
  239. EN_CLR;
  240. }
  241. /*------------------------------------------------
  242.               写入数据函数
  243. ------------------------------------------------*/
  244. void LCD_Write_Data(unsigned char Data)
  245. {
  246. //while(LCD_Check_Busy()); //忙则等待
  247. DelayMs(5);
  248. RS_SET;
  249. RW_CLR;
  250. EN_SET;
  251. DataPort= Data;
  252. _nop_();
  253. EN_CLR;
  254. }

  255. /*------------------------------------------------
  256.                 清屏函数
  257. ------------------------------------------------*/
  258. void LCD_Clear(void)
  259. {
  260. LCD_Write_Com(0x01);
  261. DelayMs(5);
  262. }

  263. /*------------------------------------------------
  264.               初始化函数
  265. ------------------------------------------------*/
  266. void LCD_Init(void)
  267. {
  268.   // LCD_Write_Com(0x38);    /*显示模式设置*/
  269. //  DelayMs(5);
  270. //  LCD_Write_Com(0x38);
  271. //  DelayMs(5);
  272.    LCD_Write_Com(0x38);
  273.    DelayMs(5);
  274.    LCD_Write_Com(0x38);  
  275.    LCD_Write_Com(0x08);    /*显示关闭*/
  276.    LCD_Write_Com(0x01);    /*显示清屏*/
  277.    LCD_Write_Com(0x06);    /*显示光标移动设置*/
  278.    DelayMs(5);
  279.    LCD_Write_Com(0x0C);    /*显示开及光标设置*/
  280.    }

  281. /*------------------------------------------------
  282.              读AD转值程序
  283. 输入参数 Chl 表示需要转换的通道,范围从0-3
  284. 返回值范围0-255
  285. ------------------------------------------------*/
  286. /*unsigned char ReadADC(unsigned char Chl)
  287. {
  288.    unsigned char Val;
  289.    Start_I2c();               //启动总线
  290.    SendByte(AddWr);             //发送器件地址
  291.      if(ack==0)return(0);
  292.    SendByte(0x40|Chl);            //发送器件子地址
  293.      if(ack==0)return(0);
  294.    Start_I2c();
  295.    SendByte(AddWr+1);
  296.       if(ack==0)return(0);
  297.    Val=RcvByte();
  298.    NoAck_I2c();                 //发送非应位
  299.    Stop_I2c();                  //结束总线
  300.    t_10us=100;
  301.   return(Val);
  302. }*/

  303. /*------------------------------------------------
  304.                写入DA转换数值
  305. 输入参数:dat 表示需要转换的DA数值,范围是0-255
  306. ------------------------------------------------*/
  307. /*bit WriteDAC(unsigned char dat)
  308. {
  309.    Start_I2c();               //启动总线
  310.    SendByte(AddWr);             //发送器件地址
  311.      if(ack==0)return(0);
  312.    SendByte(0x40);            //发送器件子地址
  313.      if(ack==0)return(0);
  314.    SendByte(dat);             //发送数据
  315.      if(ack==0)return(0);
  316.    Stop_I2c();  
  317. }*/

  318. bit WriteDAC2()
  319. {
  320.    unsigned int numm;
  321.    Start_I2c();               //启动总线
  322.    SendByte(AddWr);             //发送器件地址
  323.    //  if(ack==0)return(0);
  324.    SendByte(0x40);            //发送器件子地址
  325.    //  if(ack==0)return(0);
  326.         
  327.     for(numm=0;numm<256;numm++)
  328.     {        
  329.        SendByte(table2[numm]);             //发送数据
  330.        DelayUs2x((unsigned int)(1000/fh*3.9)-4);                //150-1000Hz
  331.     }   
  332.    
  333.   //   if(ack==0)return(0);
  334.   // Stop_I2c();  
  335. }

  336. /*void InitTimer0(void)
  337. {
  338.     TMOD = 0x01;
  339.     TH0 = 0x0FF;
  340.     TL0 = 0x0F6;
  341.     EA = 1;
  342.     ET0 = 1;
  343.     TR0 = 0;
  344. }

  345. void Timer0Interrupt(void) interrupt 1
  346. {
  347.     TH0 = 0x0FF;
  348.     TL0 = 0x0F6;
  349.     t_10us++;
  350.     if(t_10us>10000)t_10us=0;
  351. }*/

  352. void InitTimer1(void)
  353. {
  354.     TMOD |= 0x10;
  355.     TH1 = 0xFF;
  356.     TL1 = 0xF6;
  357.     EA = 1;
  358.     ET1 = 1;
  359.     TR1 = 0;
  360. }
  361. void Timer1Interrupt(void) interrupt 3
  362. {
  363.     TH1 = 0xFF;
  364.     TL1 = 0xF6;
  365.     t100us++;
  366.     t100us2++;   
  367.     if(t100us2<10)out2=0;
  368.        else if(t100us2<20)out2=1;
  369.           else t100us2=0;
  370.    
  371.    // if(t100us>10000)
  372.    //   t100us=0;
  373.     if(t100us<(500*5/fh2))out=1;   
  374.       else if(t100us<(500*8/fh2))out=0;  
  375.          else t100us=0;

  376.      // keyscan();            
  377. }

  378. void display()
  379. {
  380. unsigned int shi,ge,bai,qian,wan;
  381.    
  382.       LCD_Write_Com(0x80+0x40);   
  383.       if(flag_dis==1)
  384.       {         
  385.        LCD_Write_Data(table1[13]);      
  386.        LCD_Write_Data(table1[14]);
  387.        LCD_Write_Data(table1[15]);
  388.        pinlv=fh2;         
  389.       }
  390.       if(flag_dis==0)
  391.       {         
  392.        LCD_Write_Data(table1[0]);      
  393.        LCD_Write_Data(table1[1]);
  394.        LCD_Write_Data(table1[2]);
  395.        pinlv=fh;
  396.       }  
  397.        pinlv*=10.0;
  398.        wan=pinlv/10000;
  399.        qian=pinlv%10000/1000;
  400.        bai=pinlv%1000/100;
  401.      //  shi=pinlv%100/10;
  402.      //  ge=pinlv%10;  
  403.       
  404.        LCD_Write_Com(0x8d);   
  405.        if(flag_dis==1)         
  406.           LCD_Write_Data(0x35);
  407.        else LCD_Write_Data(0x30);
  408.          
  409.        LCD_Write_Com(0x80+0x44);
  410.        LCD_Write_Data(0x30+wan);      
  411.        LCD_Write_Data(0x30+qian);      
  412.        LCD_Write_Data(0x30+bai);
  413.      //  LCD_Write_Data(0x30+shi);
  414.     //   LCD_Write_Com(0x80+0x49);   
  415.     //   LCD_Write_Data(0x30+ge);      
  416. }

  417. void keyscan()
  418. {
  419.    TR1 = 0;
  420.       if(k1==0)
  421.       {TR1 = 0;
  422.         DelayMs(10);
  423.          if(k1==0)
  424.          {
  425.             if(flag_dis==0)
  426.             flag_dis=1;
  427.             else flag_dis=0;
  428.           while(!k1){buz=!buz;DelayUs2x(250);}
  429.          }
  430.                display();
  431.       }
  432.       if(k2==0)
  433.       {TR1 = 0;
  434.         DelayMs(10);
  435.          if(k2==0)
  436.          {
  437.             if(flag_dis==0)
  438.             if(fh==10)fh=0;
  439.             if(fh<1000)
  440.             fh+=50;
  441.             if(flag_dis==1)
  442.             if(fh2<1500)
  443.             fh2+=100;            
  444.           while(!k2){buz=!buz;DelayUs2x(250);}  
  445.          }
  446.                display();
  447.       }
  448.       if(k3==0)
  449.       {TR1 = 0;
  450.         DelayMs(10);
  451.          if(k3==0)
  452. ……………………

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

所有资料51hei提供下载:
仿真程序.7z (309.04 KB, 下载次数: 76)


评分

参与人数 2黑币 +55 收起 理由
狂吃不胖没办法 + 5
admin + 50 共享资料的黑币奖励!

查看全部评分

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

使用道具 举报

沙发
ID:1077762 发表于 2023-5-16 09:00 | 只看该作者
仿真程序是真的吗?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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