【基于51单片机的火灾报警系统仿真】
一、设计任务
在工业生产中,由于各种原因而引起的火灾对人身安全、仪器设备和生产产品造成的后果是不可逆的,因此在生产中及时的检测火灾隐患必不可少。由于单一因素偶然性过大,因此本设计采用同时检测烟雾值、湿度和温度(烟雾值和温度值小于设定阈值且湿度值大于设定阈值时为正常)以达到及时报警的目的。要求系统:
- 通过按键设定各项指标的阈值(其中,K1选择模式:mode1调节烟雾值阈值,mode2调节湿度阈值,mode3调节温度阈值。K2为数值加一。K3为数值减一,其中烟雾值为0-255,湿度0-99,温度0-99)。
- 运用烟雾传感器(在仿真中用滑变电阻与AD转化器模块代替),和温湿度传感器(DHT11)对外界实时指标进行测量。
- 液晶显示屏实时显示各项指标阈值(第一行)和实际测量值(第二行):顺序为烟雾值 湿度值 温度值。
- 报警环节:任何一项指标不合格则蜂鸣器响,同时烟雾值超出设定红灯亮,湿度值低于设定蓝灯亮,温度值高于设定绿灯亮。
- 串口的发送接收任务:由虚拟串口向单片机发送信息,单片机储存信息并回复“I received.”给PC机。
二、硬件设计图
三、软件部分代码
/*按键设置烟雾阈值、湿度阈值、温度阈值*/
//mode=1设置烟雾阈值 mode=2湿度 mode=3温度
void Key1(){
if(K1==0){
if(mode<3)
mode++;
else
mode=1;
}
}
//Key2为加一
void Key2(){
if(K2==0){
if(mode==1)
if(set_yanwu<255){
set_yanwu++;
}
else{
set_yanwu=0;
}
if(mode==2)
if(set_shidu<99){
set_shidu++;
}
else{
set_shidu=0;
}
if(mode==3)
if(set_wendu<99){
set_wendu++;
}
else{
set_wendu=0;
}
}
}
//Key3为减一
void Key3(){
if(K3==0){
if(mode==1)
if(set_yanwu>0){
set_yanwu--;
}
else{
set_yanwu=255;
}
if(mode==2)
if(set_shidu>0){
set_shidu--;
}
else{
set_shidu=99;
}
if(mode==3)
if(set_wendu>0){
set_wendu--;
}
else{
set_wendu=99;
}
}
}
void Key(){
Key1();
Key2();
Key3();
}
/*将设置的阈值存入显示数组*/
void dis_set(){
uchar i;
set_num[0]=(set_yanwu/100)+0x30;
set_num[1]=(set_yanwu/10)%10+0x30;
set_num[2]=((set_yanwu%100)%10)+0x30;
set_num[3]=' ';
set_num[4]=set_shidu/10+0x30;
set_num[5]=set_shidu%10+0x30;
set_num[6]='R';
set_num[7]='H';
set_num[8]=' ';
set_num[9]=set_wendu/10+0x30;
set_num[10]=set_wendu%10+0x30;
set_num[11]='C';
}
/*与液晶显示1602相关的函数*/
void LCDdelay(uint x) //该延时大约100us(不精确,液晶操作的延时不要求很精确)
{
uchar i;
while(x--)
for(i=0;i<120;i++);
}
//写命令
void write_com(uchar lcdcom)
{
lcdrs=0;
P1=lcdcom;
LCDdelay(5);
lcden=1;
LCDdelay(5);
lcden=0;
}
//写数据
void write_data(uchar lcddate)
{
lcdrs=1;
P1=lcddate;
LCDdelay(5);
lcden=1;
LCDdelay(5);
lcden=0;
}
//1602初始化
void Init1602()
{
uchar i;
lcden=0;
write_com(0x38);//屏幕初始化
write_com(0x0c);//打开显示 无光标 无光标闪烁
write_com(0x06);//当读或写一个字符是指针后一一位
write_com(0x01);//清屏
write_com(0x80);
for(i=0;i<4;i++){
write_data(Set[i]);
}
write_com(0x80+0x40);
for(i=0;i<4;i++){
write_data(Rel[i]);
}
}
/*模数转换器相关函数*/
uchar ADC(uint x){ //形参为通道地址,返回值为转换值
uchar dat;
XBYTE[x]=0x00; //启动AD0809
while(EOC!=0); //查询等待
dat=XBYTE[x]; //读取A/D转换值
return dat; //返回ADC值
}
void samp(){
uchar i;
total = 0;
for(i=0;i<50;i++)
total=total+ADC(0x7FF8); //求和
total=total/50; //均值滤波
rel_yanwu=total;
}
void deal(){
uchar x;
x=(uchar) total;
dis[0]=total%10;//求个位显示值
total=total/10;
dis[1]=total%10;//求十位显示值
dis[2]=total/10; //求百位显示值
}
/*温湿度传感器相关函数*/
void DHT11_delay_us(uchar n){ //延时us
while(--n);
}
void DHT11_delay_ms(uint z){ //延时ms
uint i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
void DHT11_start(){
Data=1;
DHT11_delay_us(2);
Data=0;
DHT11_delay_ms(30); //延时18ms以上
Data=1;
DHT11_delay_us(30);
}
uchar DHT11_rec_byte(){ //接收一个字节
uchar i,dat=0;
for(i=0;i<8;i++){ //从高到低依次接收8位数据
while(!Data); 等待50us低电平过去
DHT11_delay_us(8); //延时60us,如果还为高则数据为1,否则为0
dat<<=1; //移位使正确接收8位数据,数据为0时直接移位
if(Data==1) //数据为1时,使dat加1来接收数据1
dat+=1;
while(Data); //等待数据线拉低
}
return dat;
}
void DHT11_receive(){ //接收40位的数据
uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise;
DHT11_start();
if(Data==0){
while(Data==0); //等待拉高
DHT11_delay_us(40); //拉高后延时80us
R_H=DHT11_rec_byte(); //接收湿度高八位
R_L=DHT11_rec_byte(); //接收湿度低八位
T_H=DHT11_rec_byte(); //接收温度高八位
T_L=DHT11_rec_byte(); //接收温度低八位
revise=DHT11_rec_byte(); //接收校正位
DHT11_delay_us(25); //结束
if((R_H+R_L+T_H+T_L)==revise){ //校正
RH=R_H;
RL=R_L;
TH=T_H;
TL=T_L;
}
/*数据处理,方便显示*/
rec_dat[0]='0'+(RH/10);
rec_dat[1]='0'+(RH%10);
rec_dat[2]='R';
rec_dat[3]='H';
rec_dat[4]=' ';
rec_dat[5]='0'+(TH/10);
rec_dat[6]='0'+(TH%10);
rec_dat[7]='C';
}
}
/*显示函数*/
void display() {
uchar i;
DHT11_delay_ms(100); //DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令
DHT11_receive();
dis_set();
write_com(0x80+4);//显示设定阈值
for(i=0;i<12;i++){
write_data(set_num[i]);
}
write_com(0x80+0x40+4); //实测烟雾值
write_data(dis[2]+0x30);
write_data(dis[1]+0x30);
write_data(dis[0]+0x30);
write_com(0x80+0x40+8); //实测温湿度
for(i=0;i<8;i++){
write_data(rec_dat[i]);
}
LCDdelay(1000);
}
/*比较设定阈值与实际测量值,给出响应*/
void comp(){
rel_shidu=(rec_dat[0]-0x30)*10+(rec_dat[1]-0x30);
rel_wendu=(rec_dat[5]-0x30)*10+(rec_dat[6]-0x30);
if(rel_yanwu>set_yanwu)
red_LED=0;
else
red_LED=1;//烟雾值过高红灯亮
if(rel_shidu<set_shidu)
blue_LED=0;
else
blue_LED=1;//湿度过低蓝灯亮
if(rel_wendu>set_wendu)
green_LED=0;
else
green_LED=1;//温度过高绿灯亮
if((rel_yanwu<set_yanwu)&&(rel_shidu>set_shidu)&&(rel_wendu<set_wendu))
bee=1;
else
bee=0;//只要有一项不合标准则蜂鸣器报警
}
/*串口通信*/
//初始化串口 (设置串口,开启串口中断)
void init_uart(void)
{
SCON = 0x50; // SCON: 方式 1, 8-bit, 允许接收数据
TMOD |= 0x20; // TMOD: 设置定时器1工作在方式2, 8-bit 自动重装
TH1 = 0xFD; // TH1: 初始值为0xFD 波特率:9600 晶振频率:11.0592MHz
TL1 = 0x0;
TR1 = 1; // TR1: 开启定时器1
EA = 1; //打开总中断
ES = 1; //打开串口中断
}
// 发送一个字节数据
void uart_send_byte(unsigned char dat)
{
SBUF = dat; // 将数据送到发送缓冲寄存器SBUF,一位一位的发送
while(!TI); // 等待发送完毕 (发送完毕TI硬件置1)
TI = 0;// 将TI清零,表示可以发送下一字节数据。
}
// 发送字符串
void uart_send_str(unsigned char *s)
{
while(*s != '\0')// '\0':字符串结束标志
{
uart_send_byte(*s);// 发送1个字节数据,1个字符占8位,1字节
s++;// 指向下一个字符
}
}
// 串口中断处理函数 (串口接收到数据,发送数据完毕都可以引起串口中断)
void uart_interrupt(void) interrupt 4 //也叫串行中断服务程序
{
unsigned char recv_data;// 用来存放接收到的数据
unsigned char send_data[] = "I received.\n";// 要发送的信息
if(RI) //接收数据(1字节)完毕,RI会被硬件置1
{
RI = 0; // 将 接收中断标志位 清零(让串口可以继续接收数据)
recv_data = SBUF; //读取接收到的数据,并存放到data
uart_send_str(send_data); //收到数据之后,发送字符串"I received."给对方
}
if(TI)// 发送数据(1字节)完毕
{
TI = 0;// 将 发送中断标志位 清零(让串口可以继续发送数据)
}
}
基于以上可以完成在火灾报警器中对于温湿度的采集的模拟以及报警,全部代码及仿真文件下载链接:https://download.csdn.net/download/creampang/85766276