本设计采用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设计,拿到之后可以直接使用。
|