找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机+PCF8591有毒气体浓度报警器仿真设计与源码(LCD1602显示)

  [复制链接]
跳转到指定楼层
楼主
分享一个基于89C51单片机+LCD1602液晶显示+PCF8591 ad转换的有毒气体浓度报警器设计资料
内含     C 程序    isis仿真图  
操作注意事项

作品由小皮提供:

传感器 MQ -2
采集器 PCF8591
处理器 STC89c51
显示器 LCD1602
按键调整加减报警值 初始值为50%

有毒气体浓度报警器的仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)

单片机源程序如下:
  1. #include<reg52.h>   
  2. #include <intrins.h>

  3. #define ulong unsigned long
  4. #define uchar unsigned char
  5. #define uint unsigned int
  6. #define LCD1602_PORT P1               
  7. #define  PCF8591 0x90   
  8. #define  NOP()   _nop_()   
  9. #define  _Nop()  _nop_()  


  10. sbit SCL=P2^1;      
  11. sbit SDA=P2^0;      
  12. sbit LCD1602_RS = P2^5;         
  13. sbit LCD1602_RW = P2^4;         
  14. sbit LCD1602_EN = P2^3;        
  15. bit ack;     
  16. sbit key1= P0^4;
  17. sbit key2 = P0^5;
  18. sbit buzz = P2^6;
  19. int g=50;
  20. void delay_ms(uint n)        
  21. {
  22.         unsigned int  i,j;
  23.         for(i=0;i<n;i++)
  24.                 for(j=0;j<123;j++);
  25. }

  26. void key()
  27. {
  28.         key1 = 1;
  29.         delay_ms(50);
  30.         if(key1==0)g=g+1;
  31.                 if(g>99)g==0;
  32.         key2 = 1;        
  33.                 delay_ms(50);
  34.         if(key2==0)g=g-1;
  35.         if(g<0)g==99;
  36.         
  37. }
  38.             /*应答标志位*/

  39. // 变量定义
  40. uchar AD_CHANNEL;
  41. ulong xdata  LedOut[8];          //单片机内部存取器
  42. ulong  f,v,a,cj;
  43. uchar date;

  44. // 函数申明
  45. extern bit ack;                //起动总线函数
  46. extern void Start_I2c();        //结束总线函数  
  47. extern void Stop_I2c();                //应答子函数
  48. extern void Ack_I2c(bit a);                //字节数据发送函数
  49. extern void  SendByte(uchar  c);        //有子地址发送多字节数据函数               
  50. extern bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no) ;        //无子地址发送多字节数据函数   
  51. extern bit ISendStrExt(uchar sla,uchar *s,uchar no);        //无子地址读字节数据函数               
  52. extern uchar RcvByte();

  53. void LCD1602_delay_ms(uint n);
  54. void LCD1602_write_com(uchar com);
  55. void LCD1602_write_data(ulong dat);
  56. void LCD1602_write_word(uchar *s);
  57. void Init_LCD1602();

  58. bit ISendByte(uchar sla,uchar c);
  59. uchar IRcvByte(uchar sla);

  60. //MS延时函数(12M晶振下测试)

  61. //写指令
  62. void LCD1602_write_com(uchar com)
  63. {
  64.         LCD1602_RS = 0;                 //1602液晶显示屏的数据/命令选择端置0,数据/命令(H/L),此时选择写命令操作
  65.         delay_ms(1);
  66.         LCD1602_EN = 1;                 //使能,也就是打开液晶接收数据命令的通道
  67.         LCD1602_PORT = com;         //把命令送给P2口
  68.         delay_ms(1);
  69.         LCD1602_EN = 0;
  70. }

  71. //写数据
  72. void LCD1602_write_data(ulong dat)
  73. {
  74.         LCD1602_RS = 1;                 //1602液晶显示屏的数据/命令选择端置0,数据/命令(H/L),此时选择写数据操作
  75.         delay_ms(1);        
  76.         LCD1602_PORT = dat;         //把数据送给P2口
  77.         LCD1602_EN = 1;
  78.         delay_ms(1);
  79.         LCD1602_EN = 0;
  80. }

  81. //连续写字符
  82. void LCD1602_write_word(uchar *s)
  83. {
  84.         while(*s>0)
  85.         {
  86.                 LCD1602_write_data(*s);
  87.                 s++;
  88.         }
  89. }

  90. //1602初始化函数
  91. void Init_LCD1602()                                       
  92. {
  93.         LCD1602_EN = 0;
  94.         LCD1602_RW = 0;                                                //设置为写状态
  95.         LCD1602_write_com(0x38);                        //显示模式设定
  96.         LCD1602_write_com(0x0c);                        //开关显示、光标有无设置、光标闪烁设置
  97.         LCD1602_write_com(0x06);                        //写一个字符后指针加一
  98.         LCD1602_write_com(0x01);                        //清屏指令
  99. }
  100. /*******************************************************************
  101.                      起动总线函数               
  102. 函数原型: void  Start_I2c();  
  103. 功能:     启动I2C总线,即发送I2C起始条件.  
  104. ********************************************************************/
  105. void Start_I2c()
  106. {
  107.   SDA=1;         /*发送起始条件的数据信号*/
  108.   _Nop();
  109.   SCL=1;
  110.   _Nop();        /*起始条件建立时间大于4.7us,延时*/
  111.   _Nop();
  112.   _Nop();
  113.   _Nop();
  114.   _Nop();   
  115.   SDA=0;         /*发送起始信号*/
  116.   _Nop();        /* 起始条件锁定时间大于4μs*/
  117.   _Nop();
  118.   _Nop();
  119.   _Nop();
  120.   _Nop();      
  121.   SCL=0;       /*钳住I2C总线,准备发送或接收数据 */
  122.   _Nop();
  123.   _Nop();
  124. }

  125. /*******************************************************************
  126.                       结束总线函数               
  127. 函数原型: void  Stop_I2c();  
  128. 功能:     结束I2C总线,即发送I2C结束条件.  
  129. ********************************************************************/
  130. void Stop_I2c()
  131. {
  132.   SDA=0;      /*发送结束条件的数据信号*/
  133.   _Nop();       /*发送结束条件的时钟信号*/
  134.   SCL=1;      /*结束条件建立时间大于4μs*/
  135.   _Nop();
  136.   _Nop();
  137.   _Nop();
  138.   _Nop();
  139.   _Nop();
  140.   SDA=1;      /*发送I2C总线结束信号*/
  141.   _Nop();
  142.   _Nop();
  143.   _Nop();
  144.   _Nop();
  145. }

  146. /*******************************************************************
  147.                  字节数据发送函数               
  148. 函数原型: void  SendByte(UCHAR c);
  149. 功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
  150.           此状态位进行操作.(不应答或非应答都使ack=0)     
  151.            发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
  152. ********************************************************************/
  153. void  SendByte(uchar  c)
  154. {
  155. uchar  BitCnt;

  156. for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
  157.     {
  158.      if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/
  159.        else  SDA=0;               
  160.      _Nop();
  161.      SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
  162.       _Nop();
  163.       _Nop();             /*保证时钟高电平周期大于4μs*/
  164.       _Nop();
  165.       _Nop();
  166.       _Nop();         
  167.      SCL=0;
  168.     }
  169.    
  170.     _Nop();
  171.     _Nop();
  172.     SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
  173.     _Nop();
  174.     _Nop();   
  175.     SCL=1;
  176.     _Nop();
  177.     _Nop();
  178.     _Nop();
  179.     if(SDA==1)ack=0;     
  180.        else ack=1;        /*判断是否接收到应答信号*/
  181.     SCL=0;
  182.     _Nop();
  183.     _Nop();
  184. }

  185. /*******************************************************************
  186.                  字节数据接收函数               
  187. 函数原型: UCHAR  RcvByte();
  188. 功能:        用来接收从器件传来的数据,并判断总线错误(不发应答信号),
  189.           发完后请用应答函数应答从机。  
  190. ********************************************************************/   
  191. uchar   RcvByte()
  192. {
  193.   uchar  retc;
  194.   uchar  BitCnt;
  195.   
  196.   retc=0;
  197.   SDA=1;                     /*置数据线为输入方式*/
  198.   for(BitCnt=0;BitCnt<8;BitCnt++)
  199.       {
  200.         _Nop();           
  201.         SCL=0;                  /*置时钟线为低,准备接收数据位*/
  202.         _Nop();
  203.         _Nop();                 /*时钟低电平周期大于4.7μs*/
  204.         _Nop();
  205.         _Nop();
  206.         _Nop();
  207.         SCL=1;                  /*置时钟线为高使数据线上数据有效*/
  208.         _Nop();
  209.         _Nop();
  210.         retc=retc<<1;
  211.         if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
  212.         _Nop();
  213.         _Nop();
  214.       }
  215.   SCL=0;   
  216.   _Nop();
  217.   _Nop();
  218.   return(retc);
  219. }

  220. /********************************************************************
  221.                      应答子函数
  222. 函数原型:  void Ack_I2c(bit a);
  223. 功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
  224. ********************************************************************/
  225. void Ack_I2c(bit a)
  226. {
  227.   if(a==0)SDA=0;              /*在此发出应答或非应答信号 */
  228.   else SDA=1;
  229.   _Nop();
  230.   _Nop();
  231.   _Nop();      
  232.   SCL=1;
  233.   _Nop();
  234.   _Nop();                    /*时钟低电平周期大于4μs*/
  235.   _Nop();
  236.   _Nop();
  237.   _Nop();  
  238.   SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
  239.   _Nop();
  240.   _Nop();   
  241. }


  242. /*******************************************************************
  243. ADC发送字节[命令]数据函数               
  244. *******************************************************************/
  245. bit ISendByte(uchar sla,uchar c)
  246. {
  247.    Start_I2c();              //启动总线
  248.    SendByte(sla);            //发送器件地址
  249.    if(ack==0)return(0);
  250.    SendByte(c);              //发送数据
  251.    if(ack==0)return(0);
  252.    Stop_I2c();               //结束总线
  253.    return(1);
  254. }

  255. /*******************************************************************
  256. ADC读字节数据函数               
  257. *******************************************************************/
  258. uchar IRcvByte(uchar sla)
  259. {  
  260.    uchar c;
  261.    Start_I2c();          //启动总线
  262.    SendByte(sla+1);      //发送器件地址
  263.    if(ack==0)return(0);
  264.    c=RcvByte();          //读取数据0
  265.    Ack_I2c(1);           //发送非就答位
  266.    Stop_I2c();           //结束总线
  267.    return(c);
  268. }

  269. //        字符显示函数
  270. void Display()
  271. {
  272.         LCD1602_write_com(0x80);                        //指针设置,指向1602液晶第一行第一列
  273. ……………………

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

所有资料51hei提供下载:
基于89C51 LCD1602 PCF8591有毒气体浓度报警器.zip (104.05 KB, 下载次数: 146)


评分

参与人数 1黑币 +5 收起 理由
hickey + 5 很给力!

查看全部评分

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

使用道具 举报

沙发
ID:274493 发表于 2018-1-11 13:25 | 只看该作者
附件里硬件图都没有,光能找到个程序,没啥用
回复

使用道具 举报

板凳
ID:273715 发表于 2018-4-13 13:09 | 只看该作者
proteus 仿真就是硬件图哦
回复

使用道具 举报

地板
ID:86862 发表于 2018-5-11 22:22 | 只看该作者
很好的设计 急需
回复

使用道具 举报

5#
ID:86862 发表于 2018-5-11 22:32 | 只看该作者
这个设计很有借鉴意义
回复

使用道具 举报

6#
ID:540768 发表于 2019-5-17 16:00 来自手机 | 只看该作者
附件在哪里
回复

使用道具 举报

7#
ID:502682 发表于 2019-5-17 18:54 | 只看该作者
学到了东西
回复

使用道具 举报

8#
ID:543817 发表于 2019-5-21 15:08 | 只看该作者
真的很有用啊!!!
回复

使用道具 举报

9#
ID:557774 发表于 2019-6-13 01:55 来自手机 | 只看该作者
为什么不是12864显示呢?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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