基于51单片机的烟雾报警器设计
1. 功能需求
制作一个烟雾报警器,通过按键模拟烟雾检测传感器输出状态,通过数码管和LED显示系统状态,通过按键查询报警时刻。
如无报警,数码管熄灭,无显示。如有烟雾信号,则启动LED闪烁报警,并在四个数码管上显示报警时刻。以单片机启动记作0分0秒,报警时刻为xx分xx秒,显示为xx.xx。按取消报警按键后,关闭报警LED的闪烁。按下查询按键,显示上次报警时刻为xx.xx,如未发生过报警,则显示–.–。
按键功能如下:
(1)K0:模拟烟雾报警信号,按此键后,表示有烟雾。
(2)K1:取消报警按键,按此键后,烟雾报警取消,报警LED熄灭,数码管熄灭。
(3)K2:报警查询按键,按此键后,数码管显示上次报警时刻,松开该键后,查询结果消失,数码管熄灭。
2. 需求分析及设计思路
-
中断:使用外部中断0来获取报警信号,配置为下降沿触发。P3.2/INTO(非)引脚接K0,当有报警信号信号时,触发中断。
-
定时器:使用定时器0,配置为模式1,载入初值FC66H,实现1ms定时功能,以此作为系统时基。
-
I/O口:
使用P3.1、P3.3作为输入口,读取K1、K2状态;
使用P0.0—P0.7作为输出口,输出段码以供数码管显示;
使用P2.0口作为输出口,控制LED闪烁;
使用P2.2、P2.3和P2.4作为输出口,输出位选信号,经74138译码后来控制数码管显示位;
3. 硬件设计
硬件设计由以下几部分构成:
- 最小系统:最小系统主要由时钟电路、复位电路和电源组成。时钟电路选择内部时钟方式,晶振与外围电容构成了自激振荡器,其中晶振采用11.0592MHz。复位电路同时具备上电复位和手动复位功能。
- 按键电路:当按键按下时P口读取的输入状态为0,不按时为1。
- LED报警电路:LED阳极接+5V电源,阴极通过限流电阻接P2.0口,以此来提高驱动能力。P2.0口输出0时LED亮,输出1时LED灭。
- 数码管显示电路:该部分主要用到两个芯片74138、74245以及四位共阴数码管。74138为3-8译码器,输入端接P2.2—P2.4,输出端接数码管位选,将单片机输出的位选信号译码后送往数码管的位选端,以便通过单片机来控制数码管所显示的位。74245为高速CMOS总线收发器,输入端接P0.0—P0.7,输出端接数码管a—f、cp,以此来增加单片机P0口的驱动能力。
4. 软件流程设计
4.1 主函数main
主函数中主要进行初始化以及报警标志alarm_flag和K1、K2的检测,若标志生效,则执行相应操作。检测工作在while(1)中循环进行。
4.2 定时器0中断服务函数Timer0_Routine()
在定时器0中断服务函数中,首先进行赋初值操作,接下来主要完成对系统时基分和秒的个、十位计数。
4.3 报警功能函数alarm_fun()
在 alarm_fun()中,首先调用nixie_show()显示报警第一时刻的时间,接下来控制LED以每200ms亮灭一次频率闪烁。
4.4 数码管显示函数nixie_show()
在数码管显示函数nixie_show()中,首先根据alarm_empty是否为0判断之前有无报警。若之前发生过报警,则将上次报警时间送往P0口显示;若从未发生过报警,则显示“-”。要使数码管第二位带小数点显示,只要让数码管位置变量digp=1时,显示带小数点的段码即可。
5. 程序设计
#include <reg51.h>
#define NIXIEPOSTIMER 1
sbit LED = P2^0; //报警LED
sbit P2_2 = P2^2; //数码管位选,74HC138_A
sbit P2_3 = P2^3; //数码管位选,74HC138_B
sbit P2_4 = P2^4; //数码管位选,74HC138_C
sbit K1 = P3^3; //报警解除按键
sbit K_query = P3^1; //报警时刻查询按键
bit flag = 0; //报警触发标志
unsigned int led_time = 0; //led闪烁时长
unsigned char systime_s0 = 0;
unsigned char systime_s1 = 0;
unsigned char systime_m0 = 0;
unsigned char systime_m1 = 0;
unsigned char first_time = 0;
unsigned char nixiepostimer =0;
bit first_flag = 1; //报警第一时刻标志,进入报警状态的第一时刻才为1,后续报警时刻为0,按消除报警按键置1
bit flag1 = 0;
bit query = 0;
unsigned char NixieTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x40}; //共阴段码
unsigned char digdata[4]={0}; //数码管需要显示的数据
unsigned char digp = 0;
void Timer0Init(void); //定时器0初始化函数声明
void nixie_show(void);
void nixie_showblank(void);
void nixie_pos(unsigned char pos);
void main()
{
IT0 = 1; //外部中断0,下降沿触发
EX0 = 1; //外部中断0,允许
EA = 1; //总中断允许
Timer0Init(); //定时器0初始化
P0 = 0x00; //数码管全暗
P2 = 0xff; //LED全灭
while(1)
{
if(flag == 1) //K0按下,进入中断后flag置1
{
if(nixiepostimer > NIXIEPOSTIMER)
{
nixie_show();
}
if(led_time >= 300) //进入报警状态后,led每300ms亮灭一次
{
led_time = 0;
LED = ~LED;
}
flag1 = 1;
}
if(K1 == 0) //检测K1是否按下,解除报警
{
P2 = 0xff; //LED全灭
P0 = 0x00; //数码管全暗
flag = 0; //flag清0,报警解除
first_flag = 1; //第一时刻标志置1,为下次报警做准备,若进入下次报警则显示第一时刻时间
}
if(K_query == 0)
{
if(flag1 == 1)
{
if(nixiepostimer > NIXIEPOSTIMER)
{
nixie_show();
}
}
else
{
nixie_showblank();
}
if(K_query == 1)
{
P0 = 0x00;
}
}
}
}
void int_0() interrupt 0 //INT0中断
{
flag = 1; //flag置1
digdata[0] = systime_m1;
digdata[1] = systime_m0;
digdata[2] = systime_s1;
digdata[3] = systime_s0;
}
void Timer0Init(void) //1毫秒@11.0592MHz,定时器0初始化
{
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器0中断打开
}
void Timer0_Routine() interrupt 1 //定时器0中断服务函数,1ms
{
static unsigned int T0_count0 = 0;
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0_count0++;
led_time++;
nixiepostimer++;
if(T0_count0==1000) //1s==1000ms
{
T0_count0 = 0;
systime_s0++;
if(systime_s0 == 10)
{
systime_s0 = 0;
systime_s1++;
if(systime_s1 >= 6)
{
systime_s1 = 0;
systime_m0++;
if(systime_m0 >= 10)
{
systime_m0 = 0;
systime_m1++;
if(systime_m1 >= 6)
{
systime_m1 = 0;
}
}
}
}
}
}
void nixie_show(void)
{
nixiepostimer=0;
nixie_pos(digp);
P0 = NixieTable[digdata[digp]];
P0 = 0x00;
digp++;
digp &= 0x0B;
}
void nixie_showblank(void)
{
nixiepostimer=0;
nixie_pos(digp);
P0 = NixieTable[10];
P0 = 0x00;
digp++;
digp &= 0x0B;
}
void nixie_pos(unsigned char pos)
{
switch (pos)
{
case 0 : P2_4 = 1; P2_3 = 1; P2_2 = 1; break;
case 1 : P2_4 = 1; P2_3 = 1; P2_2 = 0; break;
case 2 : P2_4 = 1; P2_3 = 0; P2_2 = 1; break;
case 3 : P2_4 = 1; P2_3 = 0; P2_2 = 0; break;
}
}
6. 功能展示
1. 单片机启动后,数码管全暗,LED全灭:
2. 此时按下查询键K2,显示“–.–”,松开后停止显示:
3. 按下报警按键K0后,LED闪烁报警,数码管显示报警第一时刻时间:

4. 按下解除报警按键K1,数码管全暗,LED全灭,报警解除:
5. 此时按下查询键K2,显示上次报警时间“XX.XX”, 松开后停止显示:
