找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于51单片机的火灾报警器设计

  [复制链接]
跳转到指定楼层
楼主
ID:367198 发表于 2019-6-15 16:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本设计采用ADC0832对火焰传感器和烟雾传感器获取到的数据进行转采集,并通过单片机将采集到的数据和设定值进行比较,从而决定是否报警。
各个报警值都可通过按键进行设置,各数据都是用LCD1602液晶进行显示的,简单易懂。

火灾报警器的原理图如下:

部分程序如下:
#include <REGX51.H>      //调用51单片机头文件
#include <Define.c>      //调用定义变量的C文件
#include <DS18B20.c>  //调用DS18B20驱动C文件
#include <ADC.c>      //调用ADCO832驱动C文件
#include <LCD1602.c>  //调用LCD1602显示屏的驱动C文件
#include <display.c>  //调用各种模式的显示C文件
#include <key.c>      //调用按键C文件,其中包含关于各按键的函数
/***************定时器0中断初始化函数****************/
void Timer0_Init(void) //使用定时器中断0
{
    TMOD = 0x01;//使用模式0
    TH0 = (65536 - 2000) / 256;//定时器装入初始值2ms
    TL0 = (65536 - 2000) % 256;
    ET0 = 1; //定时器0初始化
    TR0 = 1;
    EA = 1;    //总中断
}
/***************定时器1中断初始化函数****************/
void Timer1_Init()      //使用定时器中断1
{
    TMOD |= 0x10;             //使用模式1
    TH1 = (65536-2000)/256;    //定时器装入初始值2ms
    TL1 = (65536-2000)%256;
    ET1 = 1;//定时器1初始化
    TR1 = 1;
    EA = 1;  //总中断
}
/***************定时器0中断服务函数****************/
void Timer0_isr(void)interrupt 1      
{
    TH0 = (65536 - 2000) / 256;      //定时器装入初始值2ms
    TL0 = (65536 - 2000) % 256;
    cp++;
    if(cp >= 100)                                                                     
    {
        temp_num = Read_Temperature();//获取实时温度                                                   
        cp = 0;                                                
    }
    key();    //调用key.c中的按键函数     
}
/***************定时器1中断服务函数****************/
void time1_isr(void)interrupt 3
{
    TH1=(65536-2000)/256;         //定时器装入初始值2ms
    TL1=(65536-2000)%256;
    cp1++;
    if(cp1 >= 100)
    {
        AD_smok = (GetAD0832(0)*100)/255;      //获取烟雾浓度
    //*由于传感器的AD输出的特殊原因,这里用255减去输出值以遍显示的时候可以从0%到100%增加*//
        AD_fire = ((255 - GetAD0832(1))*100)/255;       //获取火光亮度,        
        cp1 = 0;
    }
}
void main(void)
{   
    Init_LCD1602();     //LCD1602初始化
    Timer0_Init();     //定时器0初始化
    Timer1_Init();     //定时器1初始化
    LED1 = 0;    //关闭LED1
    LED2 = 0;    //关闭LED2
    LED3 = 0;    //关闭LED3
   
    while(1)
    {
        exchange();        //将各变量转换为十进制进行显示
        if(dis_mode == 0)display0();     //正常显示
        if(dis_mode == 1)display1();     //进入修改界面   
        if(temp_num >=  Temp_alam)LED1 = 1;      //当温度超过警报值时,打开红色的LED
        else LED1 = 0;
        if(AD_smok >= S_alam)LED2 = 1;      //当烟雾浓度超过警报值时,打开黄色的LED
        else LED2 = 0;
        if(AD_fire >= F_alam)LED3 = 1;    //当火光亮度超过警报值时,打开蓝色的LED
        else LED3 = 0;
        if((AD_fire >= F_alam)&&(AD_smok >= S_alam))Beep = 0;    //当检测到的三个值中有两个超过警报值,则认为有火灾发生,启动声音报警      
        if((AD_fire >= F_alam)&&(temp_num >= Temp_alam))Beep = 0;
        if((temp_num >= Temp_alam)&&(AD_smok >= S_alam))Beep = 0;
        if((AD_fire < F_alam)&&(AD_smok < S_alam)&&(temp_num < Temp_alam))Beep = 1;     //当三个值都降到警报值以下时,声音报警关闭
    }
}



/********初始化函数********/
void Init_DS18B20(void)                                            //基本操作函数1
{
    unsigned char x = 255;
    DQ = 1;                                                        //先让DQ置1
    DQ = 0;                                                        //单片机将DQ拉低
    delay(80);                                                    //延时480-960us
    DQ = 1;                                                        //释放总线
    while(DQ && x--);                                            //等待返回的低电平响应 如果没有响应,则做适量延时自动往下执行
    delay(20);
}
/********从DS18B20中读一个字节********/
unsigned char Read_OneChar(void)    //DS18B20开始发送RAM数据依次从0~8字节,且低位在前                                    //基本操作函数2
{
    unsigned char i = 0;
    unsigned char dat = 0;
    for (i=8;i>0;i--)
    {
          DQ = 0;                                                    //发送启动信号
          dat >>= 1;                                          
          DQ = 1;                                                    //释放总线
          if(DQ)                                                    //判断总线是否为高电平
          dat |= 0x80;                                            //如果是高电平,则把dat的最高位置1,如果不是,默认置0
          delay(10);
    }
    return(dat);
}
/********向18B20中写一个字节********/
void Write_OneChar(unsigned char dat)                                    //基本操作函数3
{
    unsigned char i=0;
    for (i=8; i>0; i--)
    {
        DQ = 0;
        DQ = dat & 0x01;    //先写入数据的最低位                                    //取dat的最低位
        delay(10);
        DQ = 1;
        dat >>= 1;            //再依次写入数据的低二位,低三位
    }
    delay(8);
}
/********读取温度********/
unsigned char a,b,c;
unsigned char Read_Temperature(void)                                    //应用操作函数1
{
    unsigned char t;
    Init_DS18B20();
    Write_OneChar(0xcc);    // 1100 1100  主机写CCH跳过ROM操作                                    // 跳过读序号列号的操作
    Write_OneChar(0x44);    // 0100 0100                                    // 启动温度转换
    Init_DS18B20();
    Write_OneChar(0xcc);    // 1100 1100                                    //跳过读序号列号的操作
    Write_OneChar(0xbe);    // 1011    1110   主机写BBH读出RAM数据                                //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
    a = Read_OneChar();                                            //读取温度值低位
    b = Read_OneChar();                                            //读取温度值高位
    c = 0x0f & a;            // 0000 1111 &                                     //得到小数部分
    a = a >> 4;                                                    //低位右移4位
    b = b << 4;                                                    //高位左移4位
    t = a | b;                                                    //得到8位温度的整数部分,最高1位为符号位
    return(t);
}


#define LCD1602_DB P0    //LCD1602数据总线
/*=================================================
*函数名称:Read_Busy
*函数功能:判断1602液晶忙,并等待
=================================================*/
void Read_Busy()
{
    uchar busy;
    LCD1602_DB = 0xff;//复位数据总线
    LCD1602_RS = 0;      //拉低RS
    LCD1602_RW = 1;      //拉高RW读
    do
    {
        LCD1602_EN = 1;//使能EN
        busy = LCD1602_DB;//读回数据
        LCD1602_EN = 0;     //拉低使能以便于下一次产生上升沿
    }while(busy & 0x80); //判断状态字BIT7位是否为1,为1则表示忙,程序等待
}
/*=================================================
*函数名称:LCD1602_Write_Cmd
*函数功能:写LCD1602命令
*调用:Read_Busy();
*输入:cmd:要写的命令
=================================================*/
void LCD1602_Write_Cmd(uchar cmd)
{
    Read_Busy();     //判断忙,忙则等待
    LCD1602_RS = 0;
    LCD1602_RW = 0;    //拉低RS、RW操作时序情况1602课件下中文使用说明基本操作时序章节
    LCD1602_DB = cmd;//写入命令
    LCD1602_EN = 1;     //拉高使能端 数据被传输到LCD1602内
    LCD1602_EN = 0;     //拉低使能以便于下一次产生上升沿
}
/*=================================================
*函数名称:LCD1602_Write_Dat
*函数功能:写LCD1602数据
*调用:Read_Busy();
*输入:dat:需要写入的数据
=================================================*/
void LCD1602_Write_Dat(uchar dat)
{
    Read_Busy();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_EN = 1;
    LCD1602_EN = 0;
}
/*=================================================
*函数名称:LCD1602_Dis_OneChar
*函数功能:在指定位置显示一个字符
*调用:LCD1602_Write_Cmd(); LCD1602_Write_Dat();   
*输入:x:要显示的横坐标取值0-40,y:要显示的行坐标取值0-1(0为第一行,1为第二行)
        dat:需要显示的数据以ASCLL形式显示
=================================================*/
void LCD1602_Dis_OneChar(uchar x, uchar y,uchar dat)
{
    if(y)    x |= 0x40;
    x |= 0x80;
    LCD1602_Write_Cmd(x);
    LCD1602_Write_Dat(dat + 0x30);
            
}
/*=================================================
*函数名称:LCD1602_Dis_Str
*函数功能:在指定位置显示字符串
*调用:LCD1602_Write_Cmd(); LCD1602_Write_Dat();
*输入:x:要显示的横坐标取值0-40,y:要显示的行坐标取值0-1(0为第一行,1为第二行)
        *str:需要显示的字符串
=================================================*/
void LCD1602_Dis_Str(uchar x, uchar y, uchar *str)
{
    if(y) x |= 0x40;
    x |= 0x80;
    LCD1602_Write_Cmd(x);
    while(*str != '\0')
    {
        LCD1602_Write_Dat(*str++);
    }
}
/*=================================================
*函数名称:Init_LCD1602
*函数功能:1602初始化
*调用:    LCD1602_Write_Cmd();
=================================================*/
void Init_LCD1602()
{
    LCD1602_Write_Cmd(0x38); //    设置16*2显示,5*7点阵,8位数据接口
    LCD1602_Write_Cmd(0x0c); //开显示
    LCD1602_Write_Cmd(0x06); //读写一字节后地址指针加1
    LCD1602_Write_Cmd(0x01); //清除显示
}



/***********按键函数*************/
void key(void)
{
    if(key1 == 0)
    {
        delay(200);      //按键消抖
        if(key1 == 0)
        {
            if(dis_mode == 0)
            {
                dis_mode = 1;
                Temp_set = Temp_alam;        //设置温度报警值
                Fire_set = F_alam;            //设置火光报警值
                Smok_set = S_alam;            //设置烟雾报警值
            }
            else if(dis_mode == 1)
            {
                set_mode++;               //设置标志位加
                if(set_mode >= 4)set_mode = 0;
                        
            }            
        }
        while(key1 == 0);
    }

    if(key2 == 0)
    {
        delay(200);            
        if(key2 == 0)
        {
            if((dis_mode == 1)&&(set_mode == 1))  //警报值加
            Temp_set++;
            if((dis_mode == 1)&&(set_mode == 2))
            Fire_set++;
            if((dis_mode == 1)&&(set_mode == 3))
            Smok_set++;
        }
        while(key2 == 0);
    }

    if(key3 == 0)
    {
        delay(200);               //按键消抖
        if(key3 == 0)
        {
            if((dis_mode == 1)&&(set_mode == 1))  //警报值减
            Temp_set--;
            if((dis_mode == 1)&&(set_mode == 2))
            Fire_set--;
            if((dis_mode == 1)&&(set_mode == 3))
            Smok_set--;
        }
        while(key3 == 0);
    }

    if(key4 == 0)
    {
        delay(200);               //按键消抖
        if(key4 == 0)
        {
            dis_mode = 0;       //将显示标志位置0
            set_mode = 0;       //将设置标志位置0
            Temp_alam = Temp_set;  //设置的警报值生效
            F_alam = Fire_set;
            S_alam = Smok_set;
        }
        while(key4 == 0);
    }
    if(Temp_set >= 255)Temp_set = 255;         //上限值
    if(Fire_set >= 100)Fire_set = 100;         //上限值
    if(Smok_set >= 100)Smok_set = 100;         //上限值
    if(Temp_set <= 0)Temp_set = 0;             //下限值
    if(Fire_set <= 0)Fire_set = 0;             //下限值
    if(Smok_set <= 0)Smok_set = 0;             //下限值
}



uchar GetAD0832(uint Channel)
{
    uchar i=0,Data1 =0,Data2 = 0;
    AD0832_CLK = 0 ; //时钟置低平
    AD0832_DI = 1 ; //开始信号为高电平
    AD0832_CS = 0 ; //片选信号置低,启动AD转换芯片
    AD0832_CLK = 1 ; //输入开始信号(构成一个正脉冲),时钟上升沿,输入开始信号
    AD0832_CLK = 0 ; //时钟下降沿
    //模拟信号输入模式选择(1:单模信号,0:双模差分信号)
    AD0832_DI = 1 ;
    AD0832_CLK = 1 ; //时钟上升沿,输入开始信号
    AD0832_CLK = 0 ; //时钟下降沿
    //模拟信号输入通道选择(1:通道CH1,0:通道CH0)
    AD0832_DI = Channel ; //选择通道0
    AD0832_CLK = 1 ; //时钟上升沿,输入开始信号
    AD0832_CLK = 0 ; //时钟下降沿
   
    AD0832_DI = 1 ; //数据线置高,准备接收数据
    for(i=0;i<8;i++) //从高位移入数据
      {
       AD0832_CLK = 1 ;
    AD0832_CLK = 0 ; //时钟下降沿,AD0832输出数据,高位(MSB)先
      Data1 = Data1<<1;
    if(AD0832_DI == 1)
        {Data1 = Data1 | 0x01;} //数据左移位,补0 ,如果数据为“1”,移入1, 如果数据为“0”,移入0,
   }
    for(i=0;i<8;i++) //从低位移入数据
    {
        Data2 = Data2>>1;
        if(AD0832_DI == 1)
            {  Data2 = Data2 | 0x80;} //数据右移位,补0,如果数据为“1”,移入1如果数据为“0”,移入0,
               AD0832_CLK = 1 ;
               AD0832_CLK = 0 ; //时钟下降沿,AD0832输出数据,高位(MSB)先
    }
        //数据线置高,释放总线,完成一次转换
    AD0832_CLK = 1 ;
    AD0832_DI = 1 ;
    AD0832_CS = 1 ;
    return (Data1==Data2)?Data1:0; //   如果相等输出data1  or  0
}



本设计包含程序、仿真已及PCB设计,拿到之后可以直接使用。


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

使用道具 举报

沙发
ID:1 发表于 2019-6-15 19:50 | 只看该作者
本帖需要重新编辑补全电路原理图,源码,详细说明与图片即可获得100+黑币(帖子下方有编辑按钮)
回复

使用道具 举报

板凳
ID:645035 发表于 2019-11-19 20:04 | 只看该作者
666  有完整代码吗
回复

使用道具 举报

地板
ID:736486 发表于 2020-4-23 23:31 | 只看该作者
尚子义 发表于 2019-11-19 20:04
666  有完整代码吗

不完整吗?
回复

使用道具 举报

5#
ID:736486 发表于 2020-4-23 23:33 | 只看该作者
想看完整代码
回复

使用道具 举报

6#
ID:736486 发表于 2020-4-24 22:15 | 只看该作者
有错误的
回复

使用道具 举报

7#
ID:832989 发表于 2021-1-4 23:58 来自手机 | 只看该作者
有原理图嘛
回复

使用道具 举报

8#
ID:1074288 发表于 2023-4-26 20:27 | 只看该作者
有温度传感器吗
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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