找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于51单片机的山体环境监测程序(DHT11,火焰传感器,MQ-2烟雾传感,5110显示屏)

[复制链接]
跳转到指定楼层
楼主
该项目主要是对山体环境进行监控,监控环境中的温湿度,火灾发生时火焰监测,以及燃烧所产生的烟雾进行监测报警,将所有监测到的数据以及火灾报警通过5110显示屏进行显示。

所用到的硬件及传感器:
1.STC12最小系统板
2.火焰监测模块
3.MQ-2烟雾报警器
4.DHT11
5.诺基亚5110显示屏

功能如下:
1.DHT11温湿度采集
2.火焰传感器的火焰监测(模块输入的高低电平)
3.51单片机ADC采集MQ-2的AD输出
4.5110显示温湿度,烟雾传感器的AD值,火焰传感器是否进行报警显示

STC12单片机最小系统原理图如下:


首先是DHT11的驱动程序,其采用的是单线通信,单片机驱动程序如下:
  1. #include <STC12C5A60S2.H>
  2. #include "dht11.h"
  3. #include "intrins.h"

  4. #define ulong unsigned long
  5. #define uchar unsigned char
  6. #define uint unsigned int

  7. unsigned char status;
  8. unsigned char DHT11T_Data_H, DHT11T_Data_L, DHT11RH_Data_H, DHT11RH_Data_L,CheckData_temp;//存放五字节数据
  9. /*可在其他的文件引用温湿度值,实际是温度的整数的10倍如dht11读回的温度是26,则wendu = 260, 湿度同理*/



  10. void Delay_ms(uint ms)
  11. {                     
  12.         unsigned char i, j;
  13.         while(ms)
  14.         {
  15.                 _nop_();
  16.                 i = 11;
  17.                 j = 190;
  18.                 do
  19.                 {
  20.                         while (--j);
  21.                 } while (--i);
  22.                 ms--;
  23.         }

  24. }

  25. void Delay_us(uint us)                //2us
  26. {
  27.         while(us)
  28.         {
  29.                         _nop_();
  30.                 us--;
  31.         }
  32. }
  33. unsigned char start_DHT11(unsigned int *temperature, unsigned int *RH)
  34. {
  35.   unsigned char TData_H_temp,TData_L_temp,RHData_H_temp,RHData_L_temp,checktemp;
  36.   unsigned char presence,flag = 0;
  37.   unsigned int count;
  38.   
  39.   DHT11_OUTPUT;
  40.   DHT11_L;    //拉低18ms以上
  41.   Delay_ms(20);
  42.   DHT11_H;
  43.   
  44.   DHT11_INPUT;
  45.   Delay_us(30);
  46.   presence=DHT11_IN;
  47.   
  48.   if(!presence)
  49.   {
  50.     count=2;
  51.     while((!DHT11_IN)&&count++);//等待低电平
  52.     count=2;
  53.     while((DHT11_IN)&&count++);//等待高电平
  54.    
  55.     RHData_H_temp = DHT11_ReadChar();
  56.     RHData_L_temp = DHT11_ReadChar();
  57.     TData_H_temp = DHT11_ReadChar();
  58.     TData_L_temp = DHT11_ReadChar();
  59.     CheckData_temp = DHT11_ReadChar();
  60.       
  61.     DHT11_OUTPUT;
  62.     DHT11_H;
  63.       
  64.     checktemp = RHData_H_temp + RHData_L_temp + TData_H_temp + TData_L_temp;
  65.       
  66.     if ((checktemp == CheckData_temp) && (CheckData_temp != 0))
  67.     {
  68.        DHT11RH_Data_H = RHData_H_temp;
  69.        DHT11RH_Data_L = RHData_L_temp;
  70.        DHT11T_Data_H = TData_H_temp;
  71.        DHT11T_Data_L = TData_L_temp;
  72.                          *temperature = TData_H_temp;
  73.        *RH = RHData_H_temp;
  74.        flag=1;
  75.     }
  76.    }
  77.    return flag;
  78. }
  79. uchar DHT11_ReadChar(void)
  80. {
  81.   unsigned char dat;
  82.   unsigned int count;     //计数防止死等
  83.   unsigned char i;
  84.   for(i=0;i<8;i++)
  85.   {
  86.     count=2;
  87.     DHT11_INPUT;
  88.     while((!DHT11_IN)&&count++);     //等待50us低电平结束
  89.     Delay_us(40); //40us
  90.     dat <<= 1;        //50us低电平+28us高电平表示'0'
  91.     if(DHT11_IN)    //50us低电平+70us高电平表示'1'
  92.     dat |= 1;
  93.     count=2;
  94.     while((DHT11_IN)&&count++);
  95.     if(count==1)break;      //超时则跳出for循环      
  96.    }
  97.    return dat;   
  98. }
复制代码
然后是5110的驱动程序,通信方式采用的是SPI:
  1. #include "LCD_5110_Font.h"
  2. #include "LCD_5110.h"
  3. #include "delay.h"

  4. /*******************************************************************************
  5. * 函 数 名         : LCD_write_byte
  6. * 函数功能                     : 使用SPI接口写数据到LCD
  7. * 输    入         : 写数据/命令选择;
  8. * 输    出         : 无
  9. *******************************************************************************/
  10. void LCD_write_byte(unsigned char dt, unsigned char command)
  11. {
  12.     unsigned char i;
  13.     LCD_5110_CSN = 0;//  片选
  14.     LCD_5110_dc=command;
  15.     for(i=0; i<8; i++)
  16.     {
  17.         if(dt&0x80)
  18.             LCD_5110_sdin=1;
  19.         else
  20.             LCD_5110_sdin=0;
  21.         dt=dt<<1;
  22.         LCD_5110_sclk=0;
  23.         Delay1us(1);
  24.         LCD_5110_sclk=1;
  25.     }
  26.     LCD_5110_dc=1;
  27.     Delay1us(1);
  28.     LCD_5110_CSN = 1;
  29.     Delay1us(1);
  30.     LCD_5110_sdin=1;
  31. }
  32. /*******************************************************************************
  33. * 函 数 名         : LCD_init
  34. * 函数功能                                     : LCD初始化函数
  35. * 输    入         : 无
  36. * 输    出         : 无
  37. * 说    明         : 如果5110,显示全黑或者,模糊,可以调节初始化程序中,//设定液晶偏置电压
  38. *******************************************************************************/
  39. void LCD_init(void)
  40. {
  41.     P0M0 = 0x04;
  42.     LCD_5110_res=0;
  43.     Delay1ms(2);
  44.     LCD_5110_res=1;
  45.     LCD_write_byte(0x21,0);                        //初始化Lcd,功能设定使用扩充指令
  46. //    LCD_write_byte(0xA5,0);                        //设定液晶偏置电压
  47. //    LCD_write_byte(0x20,0);                        //使用基本指令
  48. //    LCD_write_byte(0x0C,0);                        //设定显示模式,正常显示
  49.         LCD_write_byte(0xC5,0);                        //设定液晶偏置电压
  50.         LCD_write_byte(0x06, 0);        // 温度校正
  51.           LCD_write_byte(0xC5, 0);        // 1:48
  52.         LCD_write_byte(0x20,0);                        //使用基本指令
  53.         LCD_write_byte(0x0C,0);                        //设定显示模式,正常显示
  54.     LCD_clear();                                                                //清屏
  55.     LCD5110_Light = 1;                                        //
  56. }

  57. /*******************************************************************************
  58. * 函 数 名         : LCD_set_XY
  59. * 函数功能                     : 设置LCD坐标函数
  60. * 输    入         : 0-83  Y:0-5
  61. * 输    出         : 无
  62. *******************************************************************************/
  63. void LCD_set_XY(unsigned char X, unsigned char Y)
  64. {
  65.     LCD_write_byte(0x40 | Y, 0);// column
  66.     LCD_write_byte(0x80 | X, 0);// row
  67. }
  68. /*******************************************************************************
  69. * 函 数 名         : LCD_clear
  70. * 函数功能                     : LCD清屏函数
  71. * 输    入         : 无
  72. * 输    出         : 无
  73. *******************************************************************************/
  74. void LCD_clear(void)
  75. {
  76.     unsigned char t;
  77.     unsigned char k;
  78.     LCD_set_XY(0,0);
  79.     for(t=0; t<6; t++)
  80.     {
  81.         for(k=0; k<84; k++)
  82.         {
  83.             LCD_write_byte(0x00,1);
  84.         }
  85.     }
  86. }


  87. /*******************************************************************************
  88. * 函 数 名         : LCD_write_Zifu
  89. * 函数功能                     : 显示8(宽)*16(高)点阵列数字字母符号等半角类
  90. * 输    入         : c:显示的字符 row:列 page:页
  91. * 输    出         : 无
  92. *******************************************************************************/
  93. //void LCD_write_Zifu(unsigned char row, unsigned char page,unsigned char c)
  94. //{
  95. //    unsigned char i;
  96. //    c = c-32;
  97. //    LCD_set_XY(row*8, page);// 列,页
  98. //    for(i=0; i<8; i++)
  99. //    {
  100. //        LCD_write_byte(Zifu[c*16+i],1);
  101. //    }

  102. //    LCD_set_XY(row*8, page+1);// 列,页
  103. //    for(i=8; i<16; i++)
  104. //    {
  105. //        LCD_write_byte(Zifu[c*16+i],1);
  106. //    }
  107. //}




  108. /*******************************************************************************
  109. * 函 数 名         : LCD_write_hanzi
  110. * 函数功能                     : 显示16(宽)*16(高)点阵列汉字等半角类
  111. * 输    入         : c:显示的字符 row:列 page:页
  112. * 输    出         : 无
  113. *******************************************************************************/
  114. void LCD_write_hanzi(unsigned char row, unsigned char page,unsigned char c)
  115. {
  116.     unsigned char i;

  117.     LCD_set_XY(row*8, page);        // 列,页
  118.     for(i=0; i<16; i++)
  119.     {
  120.         LCD_write_byte(hanzi[c*32+i],1);
  121.     }

  122.     LCD_set_XY(row*8, page+1);        // 列,页
  123.     for(i=16; i<32; i++)
  124.     {
  125.         LCD_write_byte(hanzi[c*32+i],1);
  126.     }
  127. }
  128. /*******************************************************************************
  129. * 函 数 名         : Init_LCD5110
  130. * 函数功能                      : 应用型初始化
  131. * 输    入         : 无
  132. * 输    出         : 无
  133. *******************************************************************************/
  134. void Init_LCD5110(void)
  135. {
  136.     unsigned char k;
  137.     LCD_5110_res=0;
  138.     for(k=0; k<250; k++);
  139.     LCD_5110_res=1;
  140. //如果5110,显示全黑或者,模糊,可以调节初始化程序中,//设定液晶偏置电压
  141.     LCD_init();                                  //初始化LCD模块
  142.     LCD_clear();                                 //清屏幕
  143.     LCD5110_Light = 1;
  144. }

  145. /*******************************************************************************
  146. * 函 数 名         : Test_LCD
  147. * 函数功能                     : 5110液晶测试程序
  148. * 输    入         : 无
  149. * 输    出         : 无
  150. *******************************************************************************/
  151. void Test_LCD(void)
  152. {
  153.     unsigned char k;
  154.     LCD_5110_res=0;
  155.     for(k=0; k<250; k++);
  156.     LCD_5110_res=1;
  157.     LCD_init();                                  //初始化LCD模块
  158.     LCD_clear();                                 //清屏幕
  159.     LCD_write_hanzi(1,0,0);          //山
  160.     LCD_write_hanzi(3,0,1);          //体
  161.     LCD_write_hanzi(5,0,2);          //检
  162.     LCD_write_hanzi(7,0,3);          //测

  163.            LCD_ShowString(0, 2, "R: %", 16);
  164.         LCD_ShowString(42, 2, "T: C", 16);
  165.         LCD_ShowString(0, 4, "M:  ", 16);
  166.     //LCD_write_hanzi(9,0,4);          //检
  167. //    LCD_write_hanzi(4,2,5);          //测
  168. //    LCD_write_hanzi(6,2,6);          //预
  169. //        
  170. //                LCD_write_hanzi(6,2,7);          //预
  171. //                LCD_write_hanzi(6,2,8);          //预
  172. //                LCD_write_hanzi(6,2,9);          //预
  173. ////    LCD_ShowString(0,4,"CUIT",16);
  174. //    LCD_write_hanzi(4,4,10);          //张
  175. //    LCD_write_hanzi(6,4,11);          //媛
  176. //    LCD_write_hanzi(8,4,11);          //媛

  177. }

  178. //在指定位置显示一个字符,包括部分字符

  179. //mode:0,反白显示;1,正常显示
  180. //size:选择字体 16/12
  181. void LCD_ShowChar(unsigned char x,unsigned char y,unsigned char chr, unsigned char font_size)
  182. {
  183.     unsigned char c=0,i=0;
  184.     c=chr-' ';//得到偏移后的值
  185.     if(x>Max_Column-1) {
  186.         x=0;
  187.         y=y+2;
  188.     }
  189.     if(font_size ==16)
  190.     {
  191.         LCD_set_XY(x,y);

  192.         if((chr<='9')&&(chr >= '0'))
  193.         {
  194.             for(i=0; i<6; i++)
  195.                 LCD_write_byte(F8X16[c*16+i],LCD_DATA);
  196.             LCD_set_XY(x,y+1);
  197.             for(i=0; i<6; i++)
  198.                 LCD_write_byte(F8X16[c*16+i+8],LCD_DATA);
  199.         }
  200.         else
  201.         {
  202.             for(i=0; i<8; i++)
  203.                 LCD_write_byte(F8X16[c*16+i],LCD_DATA);
  204.             LCD_set_XY(x,y+1);
  205.             for(i=0; i<8; i++)
  206.                 LCD_write_byte(F8X16[c*16+i+8],LCD_DATA);
  207.         }
  208.     }
  209.     else {
  210.         LCD_set_XY(x,y);
  211.         for(i=0; i<6; i++) {
  212.             LCD_write_byte(F6x8[c][i],LCD_DATA);
  213.         }

  214.     }
  215. }

  216. //显示一个字符号串
  217. void LCD_ShowString(unsigned char x,unsigned char y,unsigned char *chr, unsigned char font_size)
  218. {
  219.     unsigned char j=0;
  220.     while (chr[j]!='\0')
  221.     {
  222.         LCD_ShowChar(x,y,chr[j], font_size);
  223.         if(font_size == 16)
  224.         {
  225.             if((chr[j] >= '0')&&(chr[j] <= '9'))
  226.             {
  227.                 x+=5;
  228.             } else
  229.                 x+=8;
  230.             if(x>72) {
  231.                 x=0;
  232.                 y+=2;
  233.             }
  234.         }
  235.         else
  236.         {
  237.             x+=6;
  238.             if(x>78) {
  239.                 x=0;
  240.                 y+=1;
  241.             }
  242.         }
  243.         j++;
  244.     }
  245. }

  246. //m^n函数
  247. unsigned long oled_pow(unsigned char m,unsigned char n)
  248. {
  249.     unsigned long result=1;
  250.     while(n--)result*=m;
  251.     return result;
  252. }

  253. //显示2个数字
  254. //x,y :起点坐标
  255. //len :数字的位数
  256. //size:字体大小
  257. //mode:模式        0,填充模式;1,叠加模式
  258. //num:数值(0~4294967295);
  259. void LCD_ShowNum(unsigned char x,unsigned char y,unsigned long num,unsigned char len)
  260. {
  261.     /* unsigned char t,temp;
  262.      unsigned char enshow=0;
  263.      for(t=0; t<len; t++)
  264.      {
  265.          temp=(num/oled_pow(10,len-t-1))%10;
  266.          if(enshow==0&&t<(len-1))
  267.          {
  268.              if(temp==0)
  269.              {
  270.     //                                LCD_ShowChar(x+(size/2)*t,y,' ');
  271.                  LCD_ShowChar(x+6*t,y,'0', 6);
  272.                  continue;
  273.              } else enshow=1;

  274.          }
  275.     //                 LCD_ShowChar(x+(size/2)*t,y,temp+'0');
  276.          LCD_ShowChar(x+6*t,y,temp+'0', 6);
  277.      }
  278.             */
  279.     ////////////////////
  280.     unsigned char t,temp;
  281.     unsigned char enshow=0;
  282.     for(t=0; t<len; t++)
  283.     {
  284.         temp=(num/oled_pow(10,len-t-1))%10;
  285.         if(enshow==0&&t<(len-1))
  286.         {
  287.             if(temp==0)
  288.             {
  289.                 LCD_ShowChar(x+6*t,y,' ',6);
  290.                 continue;
  291.             } else enshow=1;

  292.         }
  293.         LCD_ShowChar(x+6*t,y,temp+'0',6);
  294.     }
  295. }

  296. void LCD_ugm3(unsigned char x,unsigned char y)
  297. {
  298.     unsigned i;
  299.     LCD_set_XY(x,y);
  300.     for(i = 0; i < 13; i++)
  301.     {
  302.         LCD_write_byte(ugm3[0][i],LCD_DATA);
  303.     }
  304.     LCD_set_XY(x,y+1);
  305.     for(i = 0; i < 13; i++)
  306.     {
  307.         LCD_write_byte(ugm3[1][i],LCD_DATA);
  308.     }
  309. }

  310. void System_runing(unsigned char x,unsigned char y)
  311. {
  312.     static bit temp = 0;
  313.     temp = ~temp;
  314.     LCD_set_XY(x,y);
  315.     if(temp)
  316.         LCD_write_byte(0x80, LCD_DATA);
  317.     else
  318.         LCD_write_byte(0x00, LCD_DATA);
  319. }

  320. void Show_Back(void)
  321. {
  322.     LCD_clear();                                                                //清屏
  323.     LCD_ShowString(0, 1, "T:   ", 1);
  324.     LCD_ShowString(18, 1, "C  ", 1);
  325.     LCD_ShowString(27, 1, "CH2O:  ", 1);
  326.     LCD_ShowString(0, 3, "R:  ", 1);
  327.     LCD_ShowString(6, 3, ":   ", 1);
  328.     LCD_ShowString(18, 3, "%  ", 1);
  329.     LCD_ShowString(27, 3, "PM2.5:   ", 1);
  330.     LCD_ShowString(47, 3, "5:   ", 1);
  331.     LCD_ugm3(70,0);
  332.     LCD_ugm3(70,2);
  333. }
复制代码
MQ-2烟雾传感器模块的驱动代码主要是通过12单片机自带的ADC采集读取模块所输出的AD值进而判断是否有烟雾生成
  1. /********************* 做一次ADC转换 *******************/
  2. uint        adc10_start(uchar channel)        //channel = 0~7
  3. {
  4.         uint        adc;
  5.         uchar        i;

  6.         ADC_RES = 0;
  7.         ADC_RESL = 0;

  8.         ADC_CONTR = (ADC_CONTR & 0xe0) | ADC_START | channel;

  9.         i = 250;
  10.         do{
  11.                 if(ADC_CONTR & ADC_FLAG)
  12.                 {
  13.                         ADC_CONTR &= ~ADC_FLAG;
  14.                         adc = (uint)ADC_RES;
  15.                         adc = (adc << 2) | (ADC_RESL & 3);
  16.                         return        adc;
  17.                 }
  18.         }while(--i);        //超时检测
  19.         return        1024;
  20. }
复制代码
火焰传感器监测比较简单,即通过读取模块输出的高低电平进行判断即可知道模块是否监测到火光。
主函数如下,主要显示所采集的传感器数据,然后对火焰传感器的是否监测到火警进行判断,显示当前是安全还是火警
  1. /********************* 主函数 *************************/
  2. void main(void)
  3. {
  4.         uchar        i;
  5.         uint        j;                  //烟雾浓度缓存
  6.         char show_temp[20] = {0};                          //液晶显示缓存
  7.         unsigned int Temp1, RH1;                                //温度、湿度缓存

  8.         Uart1_Init();                                                                 //串口初始化
  9.          LCD_init();                                                                        //lcd初始化
  10.     Test_LCD();                                                                        //开机界面
  11.         //Show_Back();

  12.         //PrintString("****** STC12C5A60S2系列ADC程序 2011-02-27 ******\r\n");        //上电后串口发送一条提示信息
  13.         P1ASF = 0xff;                        //12C5A60AD/S2系列模拟输入(AD)选择
  14.         ADC_CONTR = ADC_360T | ADC_ON;
  15.          
  16.         while(1)
  17.         {
  18.            start_DHT11(&Temp1, &RH1);                   //读取DHT11温湿度值
  19.            j = adc10_start(1);                                   //读取烟雾浓度值
  20.            sprintf(show_temp, "%d",j);
  21.        LCD_ShowString(13, 4, show_temp, 16);           //显示烟雾浓度
  22.            sprintf(show_temp, "%d",RH1);
  23.        LCD_ShowString(12, 2, show_temp, 16);           //显示湿度
  24.        sprintf(show_temp, "%d",Temp1);
  25.        LCD_ShowString(55, 2, show_temp, 16);                //显示温度
  26.            if (beep == 0)                                                                //火焰报警
  27.            {
  28.                       LCD_ShowString(48, 4, "Fire", 16);
  29.            }
  30.            else
  31.            {
  32.                      LCD_ShowString(48, 4, "Safe", 16);
  33.            }
  34. //           start_DHT11(&Temp1, &RH1);
  35. //           sprintf(show_temp, "%02d",Temp1);
  36. //           UART1_SendString(show_temp);
  37. //           UART1_SendString("\r\n");
  38. //           sprintf(show_temp, "%02d",RH1);
  39.            //UART1_SendData(j);
  40.            UART1_SendData(j/1000 + '0');
  41.            UART1_SendData(j%1000/100 + '0');
  42.            UART1_SendData(j%100/10 + '0');
  43.            UART1_SendData(j%10 + '0');
  44.            UART1_SendString("\r\n");
  45.                 delay_dms(250);
  46.         }
  47. }
复制代码

此项目还可以进行物联网改造实现远程对环境进行监测,若后续有条件会进一步开发(采用4g或者NB-IOT模块,在手机安卓端做监测APP实现远程监控)

上图Keil代码工程下载:
程序.zip (118.6 KB, 下载次数: 54)

评分

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

查看全部评分

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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