找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于单片机的火灾报警器设计参考文档 附程序PCB文件

  [复制链接]
跳转到指定楼层
楼主
随着现代家庭用火、用电量的增加,家庭火灾发生的频率越来越高。火灾报警器也随之被广泛应用于各种场合。
本课题所研究的无线多功能火灾报警器采用STC89C51为核心控制器,利用气体传感器MQ-2、ADC0832模数转换器、DS18B20温度传感器等实现基本功能。通过这些传感器和芯片,当环境中可燃气体浓度或温度等发生变化时系统会发出相应的灯光报警信号和声音报警信号,以此来实现火灾报警,智能化提示。


目录
摘要        0
Abstract        1
目录        2
1 绪论        3
1.1 课题的研究背景        3
1.2 课题的研究目的与意义        4
1.3 火灾报警器的发展与现状        4
1.4课题的研究内容        5
2 火灾报警器的总体方案设计        6
2.1系统的功能要求        6
2.2 系统的技术要求        6
2.3 系统的组成及方案设计        7
3 系统的硬件设计        8
3.1 主控电路        9
3.2 烟雾探测电路的设计        12
3.2.1 MQ-2介绍        12
3.2.2 ADC0832介绍        14
3.3 液晶显示电路设计        15
3.4 声光报警提示电路        18
3.4.1 灯光提示电路        18
3.4.2 声音报警电路        19
3.5 温度采集电路        20
3.5.1 DS18B20概述        20
3.5.2 DS18B20引脚介绍        21
3.5.3 DS18B20的内部结构        22
3.5.4 DS18B20的程序流程图        22
3.6 按键电路        23
4 系统的软件设计        24
4.1 软件介绍        24
4.2 系统程序流程图        27
5火灾报警器的测试结果及结论        28
5.1 调试        28
5.2 结论        28
致谢        30
参考文献        31
源程序        32

因为篇幅有限,更多资料,请在附件中下载,(包含,原理图、pcb图、程序源码、文档)
  1. #include <reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  2. #include "intrins.h"                                                                                          

  3. #define     u8                          unsigned char
  4. #define     u16                   unsigned int
  5. #define     uchar                          unsigned char
  6. #define     uint                   unsigned int

  7. uchar yushe_wendu=50;                                //温度预设值
  8. uchar yushe_yanwu=45;                                //烟雾预设值
  9. uint wendu;                                                                 //温度值全局变量
  10. uchar yanwu;                                                                 //用于读取ADC数据

  11. //运行模式  
  12. uchar Mode=0;                                                                 //=1是设置温度阀值  =2是设置烟雾阀值        =0是正常监控模式
  13. //管脚声明
  14. sbit Led_Reg                 =P2^2;                                 //红灯
  15. sbit Led_Yellow  =P2^4;                                 //黄灯
  16. sbit Buzzer             =P2^0;                                 //蜂鸣器
  17. sbit Fan                      =P3^3;                                 //


  18. /********************************************************************
  19. * 名称 : delay_1ms()
  20. * 功能 : 延时1ms函数
  21. * 输入 : q
  22. * 输出 : 无
  23. ***********************************************************************/
  24. void delay_ms(uint q)
  25. {
  26.         uint i,j;
  27.         for(i=0;i<q;i++)
  28.                 for(j=0;j<110;j++);
  29. }
  30. /***********************************************************************************************************
  31. LCD1602相关函数
  32. ***********************************************************************************************************/

  33. //LCD管脚声明 (RW引脚实物直接接地,因为本设计只用到液晶的写操作,RW引脚一直是低电平)
  34. sbit LCDRS = P2^7;
  35. sbit LCDEN = P2^6;
  36. sbit D0                 = P0^0;
  37. sbit D1                 = P0^1;
  38. sbit D2                 = P0^2;
  39. sbit D3                 = P0^3;
  40. sbit D4                 = P0^4;
  41. sbit D5                 = P0^5;
  42. sbit D6                 = P0^6;
  43. sbit D7                 = P0^7;



  44. //LCD延时
  45. void LCDdelay(uint z)                  //该延时大约100us(不精确,液晶操作的延时不要求很精确)
  46. {
  47.   uint x,y;
  48.   for(x=z;x>0;x--)
  49.     for(y=10;y>0;y--);
  50. }
  51. void LCD_WriteData(u8 dat)         
  52. {
  53.         if(dat&0x01)D0=1;else D0=0;
  54.         if(dat&0x02)D1=1;else D1=0;
  55.         if(dat&0x04)D2=1;else D2=0;
  56.         if(dat&0x08)D3=1;else D3=0;
  57.         if(dat&0x10)D4=1;else D4=0;
  58.         if(dat&0x20)D5=1;else D5=0;
  59.         if(dat&0x40)D6=1;else D6=0;
  60.         if(dat&0x80)D7=1;else D7=0;
  61. }
  62. //写命令
  63. void write_com(uchar com)
  64. {
  65.   LCDRS=0;                                 
  66.         LCD_WriteData(com);
  67. //  DAT=com;
  68.   LCDdelay(5);
  69.   LCDEN=1;
  70.   LCDdelay(5);
  71.   LCDEN=0;
  72. }
  73. //写数据
  74. void write_data(uchar date)
  75. {
  76.   LCDRS=1;
  77.         LCD_WriteData(date);
  78. //  DAT=date;
  79.   LCDdelay(5);
  80.   LCDEN=1;
  81.   LCDdelay(5);
  82.   LCDEN=0;
  83. }

  84. /*------------------------------------------------
  85.               选择写入位置
  86. ------------------------------------------------*/
  87. void SelectPosition(unsigned char x,unsigned char y)
  88. {     
  89.         if (x == 0)
  90.         {     
  91.                 write_com(0x80 + y);     //表示第一行
  92.         }
  93.         else
  94.         {      
  95.                 write_com(0xC0 + y);      //表示第二行
  96.         }        
  97. }
  98. /*------------------------------------------------
  99.               写入字符串函数
  100. ------------------------------------------------*/
  101. void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
  102. {     
  103.         SelectPosition(x,y) ;
  104.         while (*s)
  105.         {     
  106.                 write_data( *s);     
  107.                 s ++;     
  108.         }
  109. }
  110. //========================================================================
  111. // 函数: void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
  112. // 应用: LCD_Write_Char(0,1,366,4) ;
  113. // 描述: 在第0行第一个字节位置显示366的后4位,显示结果为 0366
  114. // 参数: x:行,y:列,s:要显示的字,l:显示的位数
  115. // 返回: none.
  116. // 版本: VER1.0
  117. // 日期: 2013-4-1
  118. // 备注: 最大显示65535
  119. //========================================================================
  120. void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
  121. {     
  122.         SelectPosition(x,y) ;

  123.         if(l>=5)
  124.                 write_data(0x30+s/10000%10);        //万位
  125.         if(l>=4)
  126.                 write_data(0x30+s/1000%10);                //千位
  127.         if(l>=3)
  128.                 write_data(0x30+s/100%10);                //百位
  129.         if(l>=2)
  130.                 write_data(0x30+s/10%10);                        //十位
  131.         if(l>=1)
  132.                 write_data(0x30+s%10);                //个位

  133. }
  134. /*1602指令简介
  135.   write_com(0x38);//屏幕初始化
  136.   write_com(0x0c);//打开显示 无光标 无光标闪烁
  137.   write_com(0x0d);//打开显示 阴影闪烁
  138.   write_com(0x0d);//打开显示 阴影闪烁
  139. */
  140. //1602初始化
  141. void Init1602()
  142. {
  143.   uchar i=0;
  144.   write_com(0x38);//屏幕初始化
  145.   write_com(0x0c);//打开显示 无光标 无光标闪烁
  146.   write_com(0x06);//当读或写一个字符是指针后一一位
  147.   write_com(0x01);//清屏
  148.       
  149. }

  150. void Display_1602(yushe_wendu,yushe_yanwu,c,temp)
  151. {
  152.         //显示预设温度
  153.         LCD_Write_Char(0,6,yushe_wendu,2) ;
  154.       
  155.         //显示预设烟雾
  156.         LCD_Write_Char(0,13,yushe_yanwu,3) ;
  157.       
  158.         //时时温度
  159.         LCD_Write_Char(1,6,c/10,2) ;
  160.         write_data('.');
  161.         LCD_Write_Char(1,9,c%10,1) ;
  162.       
  163.         //时时烟雾
  164.         LCD_Write_Char(1,13,temp,3) ;
  165. }



  166. /***********************************************************************************************************
  167. ADC0832相关函数
  168. ***********************************************************************************************************/
  169. sbit ADCS         =P1^5; //ADC0832 片选
  170. sbit ADCLK  =P1^2; //ADC0832 时钟
  171. sbit ADDI         =P1^3; //ADC0832 数据输入                /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,
  172. sbit ADDO         =P1^3; //ADC0832 数据输出                /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上



  173. //========================================================================
  174. // 函数: unsigned int Adc0832(unsigned char channel)
  175. // 应用:                 temp=Adc0832(0);
  176. // 描述: 读取0通道的AD值
  177. // 参数: channel:通道0和通道1选择
  178. // 返回: 选取通道的AD值
  179. // 版本: VER1.0
  180. // 日期: 2015-05-29
  181. // 备注:
  182. //========================================================================
  183. unsigned int Adc0832(unsigned char channel)
  184. {
  185.         uchar i=0;
  186.         uchar j;
  187.         uint dat=0;
  188.         uchar ndat=0;
  189.         uchar  Vot=0;

  190.         if(channel==0)channel=2;
  191.         if(channel==1)channel=3;
  192.         ADDI=1;
  193.         _nop_();
  194.         _nop_();
  195.         ADCS=0;//拉低CS端
  196.         _nop_();
  197.         _nop_();
  198.         ADCLK=1;//拉高CLK端
  199.         _nop_();
  200.         _nop_();
  201.         ADCLK=0;//拉低CLK端,形成下降沿1
  202.         _nop_();
  203.         _nop_();
  204.         ADCLK=1;//拉高CLK端
  205.         ADDI=channel&0x1;
  206.         _nop_();
  207.         _nop_();
  208.         ADCLK=0;//拉低CLK端,形成下降沿2
  209.         _nop_();
  210.         _nop_();
  211.         ADCLK=1;//拉高CLK端
  212.         ADDI=(channel>>1)&0x1;
  213.         _nop_();
  214.         _nop_();
  215.         ADCLK=0;//拉低CLK端,形成下降沿3
  216.         ADDI=1;//控制命令结束
  217.         _nop_();
  218.         _nop_();
  219.         dat=0;
  220.         for(i=0;i<8;i++)
  221.         {
  222.                 dat|=ADDO;//收数据
  223.                 ADCLK=1;
  224.                 _nop_();
  225.                 _nop_();
  226.                 ADCLK=0;//形成一次时钟脉冲
  227.                 _nop_();
  228.                 _nop_();
  229.                 dat<<=1;
  230.                 if(i==7)dat|=ADDO;
  231.         }
  232.         for(i=0;i<8;i++)
  233.         {
  234.                 j=0;
  235.                 j=j|ADDO;//收数据
  236.                 ADCLK=1;
  237.                 _nop_();
  238.                 _nop_();
  239.                 ADCLK=0;//形成一次时钟脉冲
  240.                 _nop_();
  241.                 _nop_();
  242.                 j=j<<7;
  243.                 ndat=ndat|j;
  244.                 if(i<7)ndat>>=1;
  245.         }
  246.         ADCS=1;//拉低CS端
  247.         ADCLK=0;//拉低CLK端
  248.         ADDO=1;//拉高数据端,回到初始状态
  249.         dat<<=8;
  250.         dat|=ndat;

  251.         return(dat);            //return ad data
  252. }

  253. /***********************************************************************************************************
  254. DS18B20相关函数
  255. ***********************************************************************************************************/

  256. sbit DQ = P1^0;                                 //ds18b20的数据引脚



  257. /*****延时子程序:该延时主要用于ds18b20延时*****/
  258. void Delay_DS18B20(int num)
  259. {
  260.   while(num--) ;
  261. }
  262. /*****初始化DS18B20*****/
  263. void Init_DS18B20(void)
  264. {
  265.   unsigned char x=0;
  266.   DQ = 1;         //DQ复位
  267.   Delay_DS18B20(8);    //稍做延时
  268.   DQ = 0;         //单片机将DQ拉低
  269.   Delay_DS18B20(80);   //精确延时,大于480us
  270.   DQ = 1;         //拉高总线
  271.   Delay_DS18B20(14);
  272.   x = DQ;           //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
  273.   Delay_DS18B20(20);
  274. }
  275. /*****读一个字节*****/
  276. unsigned char ReadOneChar(void)
  277. {
  278.   unsigned char i=0;
  279.   unsigned char dat = 0;
  280.   for (i=8;i>0;i--)
  281.   {
  282.     DQ = 0;     // 给脉冲信号
  283.     dat>>=1;
  284.     DQ = 1;     // 给脉冲信号
  285.     if(DQ)
  286.     dat|=0x80;
  287.     Delay_DS18B20(4);
  288.   }
  289.   return(dat);
  290. }
  291. /*****写一个字节*****/
  292. void WriteOneChar(unsigned char dat)
  293. {
  294.   unsigned char i=0;
  295.   for (i=8; i>0; i--)
  296.   {
  297.     DQ = 0;
  298.     DQ = dat&0x01;
  299.     Delay_DS18B20(5);
  300.     DQ = 1;
  301.     dat>>=1;
  302.   }
  303. }
  304. /*****读取温度*****/
  305. unsigned int ReadTemperature(void)
  306. {
  307.   unsigned char a=0;
  308.   unsigned char b=0;
  309.   unsigned int t=0;
  310.   float tt=0;
  311.   Init_DS18B20();
  312.   WriteOneChar(0xCC);  //跳过读序号列号的操作
  313.   WriteOneChar(0x44);  //启动温度转换
  314.   Init_DS18B20();
  315.   WriteOneChar(0xCC);  //跳过读序号列号的操作
  316.   WriteOneChar(0xBE);  //读取温度寄存器
  317.   a=ReadOneChar();     //读低8位
  318.   b=ReadOneChar();    //读高8位
  319.   t=b;
  320.   t<<=8;
  321.   t=t|a;
  322.   tt=t*0.0625;
  323.   t= tt*10+0.5;     //放大10倍输出并四舍五入
  324.   return(t);
  325. }
  326. //=====================================================================================
  327. //=====================================================================================
  328. //=====================================================================================


  329. /*****校准温度*****/
  330. u16 check_wendu(void)
  331. {
  332.         u16 c;
  333.         c=ReadTemperature()-5;                          //获取温度值并减去DS18B20的温漂误差
  334.         if(c<1) c=0;
  335.         if(c>=999) c=999;
  336.         return c;
  337. }

  338. /***********************************************************************************************************
  339. 按键检测相关函数
  340. ***********************************************************************************************************/
  341. //按键
  342. sbit Key1=P1^6;                                 //设置键
  343. sbit Key2=P1^7;                                 //加按键
  344. sbit Key3=P3^2;                                 //减按键



  345. #define KEY_SET                 1                //设置
  346. #define KEY_ADD                        2                //加
  347. #define KEY_MINUS                3                //减


  348. //========================================================================
  349. // 函数: u8 Key_Scan()
  350. // 应用: temp=u8 Key_Scan();
  351. // 描述: 按键扫描并返回按下的键值
  352. // 参数: NONE
  353. // 返回: 按下的键值
  354. // 版本: VER1.0
  355. // 日期: 2015-05-29
  356. // 备注: 该函数带松手检测,按下键返回一次键值后返回0,直至第二次按键按下
  357. //========================================================================
  358. u8 Key_Scan()
  359. {         
  360.         static u8 key_up=1;//按键按松开标志
  361.         if(key_up&&(Key1==0||Key2==0||Key3==0))
  362.         {
  363.                 delay_ms(10);//去抖动
  364.                 key_up=0;
  365.                 if(Key1==0)                        return 1;
  366.                 else if(Key2==0)return 2;
  367.                 else if(Key3==0)return 3;
  368.         }
  369.         else if(Key1==1&&Key2==1&&Key3==1)
  370.                 key_up=1;            
  371.         return 0;// 无按键按下
  372. }



  373. void main (void)
  374. {
  375.         u8 key;
  376.         wendu=check_wendu();                  //初始化时调用温度读取函数 防止开机85°C
  377.         Init1602();                          //调用初始化显示函数
  378.         LCD_Write_String(0,0,"SET T:00   E:000");  //开机界面
  379.         LCD_Write_String(1,0,"NOW T:00.0 E:000");  
  380.         delay_ms(1000);
  381.         wendu=check_wendu();                  //初始化时调用温度读取函数 防止开机85°C
  382.         while (1)                                                //主循环
  383.         {
  384.                 key=Key_Scan();                                        //按键扫描
  385.                 yanwu=Adc0832(0);                                //读取烟雾值
  386.                 wendu=check_wendu();          //读取温度值
  387.                
  388.                 if(key==KEY_SET)
  389.                 {
  390.                         Mode++;
  391.                 }
  392.                
  393.                 switch(Mode)                                                //判断模式的值
  394.                 {
  395.                         case 0:                                                                //监控模式
  396.                         {
  397.                                 Display_1602(yushe_wendu,yushe_yanwu,wendu,yanwu);  //显示预设温度,预设烟雾,温度值,烟雾值
  398.                                 if(yanwu>=yushe_yanwu)          //烟雾值大于等于预设值时
  399.                                 {
  400.                                         Led_Reg=0;                                          //烟雾指示灯亮
  401.                                         Fan=0;
  402.                                         Buzzer=0;                                                  //蜂鸣器报警
  403.                                 }
  404.                                 else                                                                                  //烟雾值小于预设值时
  405.                                 {
  406.                                         Led_Reg=1;                                          //关掉报警灯
  407.                                         Fan=1;
  408.                                 }
  409.                                 if(wendu>=(yushe_wendu*10))          //温度大于等于预设温度值时(为什么是大于预设值*10:因为我们要显示的温度是有小数点后一位,是一个3位数,25.9°C时实际读的数是259,所以判断预设值时将预设值*10)
  410.                                 {
  411.                                         Buzzer=0;                                                  //打开蜂鸣器报警
  412.                                         Led_Yellow=0;                                          //打开温度报警灯
  413.                                 }
  414.                                 else                                                                                  //温度值小于预设值时
  415.                                 {
  416.                                         Led_Yellow=1;                                          //关闭报警灯
  417.                                 }
  418.                                 if((yanwu<yushe_yanwu)&&(wendu<(yushe_wendu*10)))          //当烟雾小于预设值并且温度也小于预设值时 (&&:逻辑与,左右两边的表达式都成立(都为真,也就是1)时,该if语句才成立)
  419.                                 {
  420.                                         Buzzer=1;                                                  //停止报警
  421.                                 }
  422.                                 break;
  423.                         }
  424.                         case 1://预设温度模式
  425.                         {
  426.                                 SelectPosition(0,5) ;                                        //指定位置
  427.                            write_com(0x0d);                                                        //阴影闪烁
  428.                                 if(key==KEY_ADD)                                                        //加键按下
  429.                                 {
  430.                                         yushe_wendu++;                                            //预设温度值(阀值)加1
  431.                                         if(yushe_wendu>=99)                                         //当阀值加到大于等于99时
  432.                                         yushe_wendu=99;                                                         //阀值固定为99
  433.                                         LCD_Write_Char(0,6,yushe_wendu,2) ;//显示预设温度
  434.                                 }
  435.                                 if(key==KEY_MINUS)                                                 //减键按下
  436.                                 {
  437.                                         if(yushe_wendu<=1)                                        //当温度上限值减小到1时
  438.                                         yushe_wendu=1;                          //固定为1
  439.                                         yushe_wendu--;                                                        //预设温度值减一,最小为0
  440.                                         LCD_Write_Char(0,6,yushe_wendu,2) ;//显示预设温度
  441.                                 }
  442.                                 break;                                                                                          //执行后跳出switch
  443.                         }
  444.                         case 2:                                //预设烟雾模式
  445.                         {
  446.                                 SelectPosition(0,12) ;                                //指定位置      
  447.                            write_com(0x0d);                                                        //打开显示 无光标 光标闪烁
  448.                                 if(key==KEY_ADD)                                                        //加键按下
  449.                                 {
  450.                                         if(yushe_yanwu>=255)        //当阀值加到大于等于255时
  451.                                         yushe_yanwu=254;            //阀值固定为254
  452.                                         yushe_yanwu++;                                            //预设烟雾值(阀值)加1,最大为255
  453.                                         LCD_Write_Char(0,13,yushe_yanwu,3) ;//显示预设烟雾
  454.                                 }
  455.                                 if(key==KEY_MINUS)                                                //减键按下
  456.                                 {
  457.                                         if(yushe_yanwu<=1)                                        //当烟雾上限值减小到1时
  458.                                                 yushe_yanwu=1;                  //固定为1
  459.                                         yushe_yanwu--;                                                        //预设温度值减一,最小为0         
  460.                                         LCD_Write_Char(0,13,yushe_yanwu,3) ;//显示预设烟雾
  461.                                 }
  462.                                 break;
  463.                         }
  464.                         default        :      
  465.                         {
  466.                                 write_com(0x38);//屏幕初始化
  467.                                 write_com(0x0c);//打开显示 无光标 无光标闪烁
  468.                                 Mode=0;                        //恢复正常模式
  469.                                 break;
  470.                         }
  471.                 }
  472.                
  473.         }

  474. }
复制代码



全部资料51hei下载地址:
烟雾报警器资料.7z (463.98 KB, 下载次数: 269)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏7 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:694218 发表于 2020-2-18 11:45 | 只看该作者
调不出来啊
回复

使用道具 举报

板凳
ID:694218 发表于 2020-2-18 12:28 | 只看该作者
图和程序不对应吧,程序中引脚用的AT89C51吧?
回复

使用道具 举报

地板
ID:737540 发表于 2020-4-26 11:38 | 只看该作者
源程序有错误吧
回复

使用道具 举报

5#
ID:519059 发表于 2020-5-5 10:12 | 只看该作者
压缩文件里怎么没有文档呀?
回复

使用道具 举报

6#
ID:742435 发表于 2020-5-5 11:17 | 只看该作者
请问电源应该接哪几个端口
回复

使用道具 举报

7#
ID:758429 发表于 2020-5-22 16:00 | 只看该作者
为什么压缩包调不出来
回复

使用道具 举报

8#
ID:785091 发表于 2020-6-26 17:49 | 只看该作者
Fan是什么意思
回复

使用道具 举报

9#
ID:790946 发表于 2020-6-27 14:34 | 只看该作者
猛呀
大神级的操作
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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