找回密码
 立即注册

QQ登录

只需一步,快速开始

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

检测烟雾灰尘浓度并报警的单片机源程序

[复制链接]
跳转到指定楼层
楼主
ID:192119 发表于 2017-4-21 19:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
单片机检测烟雾灰尘浓度小程序分享,看有什么改进的地方
完整源码下载:
新建 Microsoft Word 文档.docx (14.83 KB, 下载次数: 37)


  1. #include <reg52.h>
  2. #include <intrins.h>

  3. #define uchar unsigned char                // 以后unsigned char就可以用uchar代替
  4. #define uint  unsigned int                // 以后unsigned int 就可以用uint 代替

  5. sfr ISP_DATA  = 0xe2;                        // 数据寄存器
  6. sfr ISP_ADDRH = 0xe3;                        // 地址寄存器高八位
  7. sfr ISP_ADDRL = 0xe4;                        // 地址寄存器低八位
  8. sfr ISP_CMD   = 0xe5;                        // 命令寄存器
  9. sfr ISP_TRIG  = 0xe6;                        // 命令触发寄存器
  10. sfr ISP_CONTR = 0xe7;                        // 命令寄存器

  11. sbit LcdRs_P  = P2^7;     // 1602液晶的RS管脚      
  12. sbit LcdRw_P  = P2^6;     // 1602液晶的RW管脚
  13. sbit LcdEn_P  = P2^5;     // 1602液晶的EN管脚
  14. sbit Key1_P   = P3^2;                        // 减按键
  15. sbit Key2_P   = P3^3;                        // 加按键
  16. sbit Buzzer_P = P1^0;                        // 蜂鸣器


  17. uint  gAlarm ;                                                // 报警值
  18. uchar gIndex=0;                                                // 串口接收索引
  19. uint  Value[20]={0};                        // 串口数据缓存区


  20. /*********************************************************/
  21. // 单片机内部EEPROM不使能
  22. /*********************************************************/
  23. void ISP_Disable()
  24. {
  25.         ISP_CONTR = 0;
  26.         ISP_ADDRH = 0;
  27.         ISP_ADDRL = 0;
  28. }


  29. /*********************************************************/
  30. // 从单片机内部EEPROM读一个字节,从0x2000地址开始
  31. /*********************************************************/
  32. unsigned char EEPROM_Read(unsigned int add)
  33. {
  34.         ISP_DATA  = 0x00;
  35.         ISP_CONTR = 0x83;
  36.         ISP_CMD   = 0x01;
  37.         ISP_ADDRH = (unsigned char)(add>>8);
  38.         ISP_ADDRL = (unsigned char)(add&0xff);
  39.         ISP_TRIG  = 0x46;           
  40.         ISP_TRIG  = 0xB9;
  41.         _nop_();
  42.         ISP_Disable();
  43.         return (ISP_DATA);
  44. }


  45. /*********************************************************/
  46. // 往单片机内部EEPROM写一个字节,从0x2000地址开始
  47. /*********************************************************/
  48. void EEPROM_Write(unsigned int add,unsigned char ch)
  49. {
  50.         ISP_CONTR = 0x83;
  51.         ISP_CMD   = 0x02;
  52.         ISP_ADDRH = (unsigned char)(add>>8);
  53.         ISP_ADDRL = (unsigned char)(add&0xff);
  54.         ISP_DATA  = ch;
  55.         ISP_TRIG  = 0x46;
  56.         ISP_TRIG  = 0xB9;
  57.         _nop_();
  58.         ISP_Disable();
  59. }


  60. /*********************************************************/
  61. // 擦除单片机内部EEPROM的一个扇区
  62. // 写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除
  63. /*********************************************************/
  64. void Sector_Erase(unsigned int add)         
  65. {
  66.         ISP_CONTR = 0x83;
  67.         ISP_CMD   = 0x03;
  68.         ISP_ADDRH = (unsigned char)(add>>8);
  69.         ISP_ADDRL = (unsigned char)(add&0xff);
  70.         ISP_TRIG  = 0x46;
  71.         ISP_TRIG  = 0xB9;
  72.         _nop_();
  73.         ISP_Disable();
  74. }


  75. /*********************************************************/
  76. // 毫秒级的延时函数,time是要延时的毫秒数
  77. /*********************************************************/
  78. void DelayMs(uint time)
  79. {
  80.         uint i,j;
  81.         for(i=0;i<time;i++)
  82.                 for(j=0;j<112;j++);
  83. }


  84. /*********************************************************/
  85. // 1602液晶写命令函数,cmd就是要写入的命令
  86. /*********************************************************/
  87. void LcdWriteCmd(uchar cmd)
  88. {
  89.         LcdRs_P = 0;
  90.         LcdRw_P = 0;
  91.         LcdEn_P = 0;
  92.         P0=cmd;
  93.         DelayMs(2);
  94.         LcdEn_P = 1;   
  95.         DelayMs(2);
  96.         LcdEn_P = 0;        
  97. }


  98. /*********************************************************/
  99. // 1602液晶写数据函数,dat就是要写入的数据
  100. /*********************************************************/
  101. void LcdWriteData(uchar dat)
  102. {
  103.         LcdRs_P = 1;
  104.         LcdRw_P = 0;
  105.         LcdEn_P = 0;
  106.         P0=dat;
  107.         DelayMs(2);
  108.         LcdEn_P = 1;   
  109.         DelayMs(2);
  110.         LcdEn_P = 0;
  111. }


  112. /*********************************************************/
  113. // 1602液晶初始化函数
  114. /*********************************************************/
  115. void LcdInit()
  116. {
  117.         LcdWriteCmd(0x38);        // 16*2显示,5*7点阵,8位数据口
  118.         LcdWriteCmd(0x0C);        // 开显示,不显示光标
  119.         LcdWriteCmd(0x06);        // 地址加1,当写入数据后光标右移
  120.         LcdWriteCmd(0x01);        // 清屏
  121. }


  122. /*********************************************************/
  123. // 液晶光标定位函数
  124. /*********************************************************/
  125. void LcdGotoXY(uchar line,uchar column)
  126. {
  127.         // 第一行
  128.         if(line==0)        
  129.                 LcdWriteCmd(0x80+column);
  130.          // 第二行
  131.         if(line==1)        
  132.                 LcdWriteCmd(0x80+0x40+column);
  133. }


  134. /*********************************************************/
  135. // 液晶输出数字
  136. /*********************************************************/
  137. void LcdPrintNum(uint num)
  138. {
  139.         if(num>999)
  140.         {
  141.                 LcdWriteData(num/1000+48);                        // 如果有千位,则输出千位
  142.         }
  143.         else                                                                                                                        // 如果没有千位,则输出空格
  144.         {
  145.                 LcdWriteData(' ');
  146.         }
  147.         LcdWriteData(num%1000/100+48);                // 百位
  148.         LcdWriteData(num%100/10+48);                        // 十位
  149.         LcdWriteData(num%10+48);                                         // 个位
  150. }


  151. /*********************************************************/
  152. // 液晶输出字符串函数
  153. /*********************************************************/
  154. void LcdPrintStr(uchar *str)
  155. {
  156.         while(*str!='\0')
  157.                 LcdWriteData(*str++);
  158. }


  159. /*********************************************************/
  160. // 液晶显示内容初始化
  161. /*********************************************************/
  162. void LcdShowInit()
  163. {
  164.         LcdGotoXY(0,0);                                // 液晶光标定位到第0行第0列
  165.         LcdPrintStr("PM2.5:     ug/m3");
  166.         LcdGotoXY(1,0);                                // 液晶光标定位到第1行第0列
  167.         LcdPrintStr("Alarm:     ug/m3");
  168. }



  169. /*********************************************************/
  170. // 串口初始化
  171. /*********************************************************/
  172. void UartInit()
  173. {
  174.         TMOD = 0x20;
  175.         SCON = 0x50;
  176.         TH1  = 0xf4;
  177.         TL1  = 0xf4;
  178.         TR1  = 1;
  179.         REN  = 1;
  180.         EA   = 1;
  181.         ES   = 1;
  182. }


  183. /*********************************************************/
  184. // 按键扫描
  185. /*********************************************************/
  186. void KeyScanf()
  187. {
  188.         /* 减按键被按下 */
  189.         if(Key1_P==0)               
  190.         {
  191.                 if(gAlarm>1)                                                                                                // 只有报警值大于1,才能完成减操作
  192.                 {
  193.                         gAlarm--;                                                                                                        // 报警值减1
  194.                         LcdGotoXY(1,6);                                                                                // 液晶定位到第1行第6列
  195.                         LcdPrintNum(gAlarm);                                                        // 显示报警浓度值
  196.                         Sector_Erase(0x2000);                                                         // 存储之前必须先擦除
  197.                         EEPROM_Write(0x2000,gAlarm/100);        // 存储新的报警值
  198.                         EEPROM_Write(0x2001,gAlarm%100);        
  199.                 }
  200.         }
  201.         
  202.         /* 减按键被按下 */
  203.         if(Key2_P==0)
  204.         {
  205.                 if(gAlarm<1300)                                                                                        // 只有报警值小于1300,才能完成加操作
  206.                 {
  207.                         gAlarm++;                                                                                                        // 报警值加1
  208.                         LcdGotoXY(1,6);                                                                                // 液晶定位到第1行第6列
  209.                         LcdPrintNum(gAlarm);                                                        // 显示报警浓度值
  210.                         Sector_Erase(0x2000);                                                         // 存储之前必须先擦除
  211.                         EEPROM_Write(0x2000,gAlarm/100);        // 存储新的报警值
  212.                         EEPROM_Write(0x2001,gAlarm%100);        
  213.                 }
  214.         }
  215. }


  216. /*********************************************************/
  217. // 报警判断
  218. /*********************************************************/
  219. void AlarmJudge(uint num)
  220. {
  221.         if(num>gAlarm)        
  222.                 Buzzer_P=0;                // 开启蜂鸣器报警
  223.         else
  224.                 Buzzer_P=1;                // 停止蜂鸣器报警
  225. }


  226. /*********************************************************/
  227. // 主函数
  228. /*********************************************************/
  229. void main(void)
  230. {
  231.         uchar i;                                // 循环变量
  232.         uint ret;                                // 保存测量结果
  233.         
  234.         gAlarm=EEPROM_Read(0x2000)*100+EEPROM_Read(0x2001);                // 上电时,先读取报警值
  235.         if((gAlarm==0)||(gAlarm>999))                                                                                                        // 如果读取到的报警值异常,则重新赋值
  236.                 gAlarm=200;
  237.                
  238.         
  239.         LcdInit();                                            // 液晶功能初始化
  240.         LcdShowInit();                                        // 液晶显示初始化
  241.         UartInit();                                                        // 串口初始化

  242.         LcdGotoXY(1,6);                                        // 液晶定位到第1行第6列
  243.         LcdPrintNum(gAlarm);                // 显示报警浓度值
  244.         
  245.         while(1)
  246.         {
  247.                 ret=0;                                                                                        // 清零测量结果
  248.                 for(i=0;i<20;i++)                                                // 将最新的20个测量结果求和
  249.                 {
  250.                         ret=ret+Value[i];
  251.                 }
  252.                 ret=ret/20;                                                                        // 再除以20求得平均值
  253.                
  254.                 ret=((ret*5)/1024.0)*380;                // 将读取到的电压值转换为灰尘浓度值        
  255.                
  256.                 LcdGotoXY(0,6);                                                        // 液晶定位到第0行第6列
  257.                 LcdPrintNum(ret);                                                // 显示测量结果
  258.                
  259.                 AlarmJudge(ret);                                                // 判断是否需要报警
  260.                
  261.                 KeyScanf();                                                                        // 进行按键扫描,判断是否有按键按下
  262.         }
  263. }


  264. /*********************************************************/
  265. // 串口中断服务程序
  266. /*********************************************************/
  267. void UartInt(void) interrupt 4
  268. {
  269.         uchar dat1,dat2;
  270.         
  271.         if(RI==1)
  272.         {
  273.                 RI=0;
  274.                 if(SBUF==0xAA)
  275.                 {
  276.                         while(!RI);
  277.                         dat1=SBUF;
  278.                         RI=0;
  279.                         while(!RI);
  280.                         dat2=SBUF;
  281.                         RI=0;
  282.                         while(!RI);
  283.                         RI=0;
  284.                         while(!RI);
  285.                         RI=0;
  286.                         while(!RI);
  287.                         RI=0;
  288.                         while(!RI);
  289.                         RI=0;
  290.                         Value[gIndex]=dat1*256+dat2;
  291.                         gIndex++;


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


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

使用道具 举报

沙发
ID:497598 发表于 2020-3-27 22:37 | 只看该作者
怎么读取浓度的?
回复

使用道具 举报

板凳
ID:857301 发表于 2020-12-9 14:52 | 只看该作者
有原理图吗
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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