基于51单片机的烟雾报警器设计

基于51单片机的烟雾报警器设计

1. 功能需求

制作一个烟雾报警器,通过按键模拟烟雾检测传感器输出状态,通过数码管和LED显示系统状态,通过按键查询报警时刻。

如无报警,数码管熄灭,无显示。如有烟雾信号,则启动LED闪烁报警,并在四个数码管上显示报警时刻。以单片机启动记作0分0秒,报警时刻为xx分xx秒,显示为xx.xx。按取消报警按键后,关闭报警LED的闪烁。按下查询按键,显示上次报警时刻为xx.xx,如未发生过报警,则显示–.–。

按键功能如下:

(1)K0:模拟烟雾报警信号,按此键后,表示有烟雾。

(2)K1:取消报警按键,按此键后,烟雾报警取消,报警LED熄灭,数码管熄灭。

(3)K2:报警查询按键,按此键后,数码管显示上次报警时刻,松开该键后,查询结果消失,数码管熄灭。

2. 需求分析及设计思路

  1. 中断:使用外部中断0来获取报警信号,配置为下降沿触发。P3.2/INTO(非)引脚接K0,当有报警信号信号时,触发中断。

  2. 定时器:使用定时器0,配置为模式1,载入初值FC66H,实现1ms定时功能,以此作为系统时基。

  3. I/O口

    使用P3.1、P3.3作为输入口,读取K1、K2状态;

    使用P0.0—P0.7作为输出口,输出段码以供数码管显示;

    使用P2.0口作为输出口,控制LED闪烁;

    使用P2.2、P2.3和P2.4作为输出口,输出位选信号,经74138译码后来控制数码管显示位;

3. 硬件设计

image-20250402215731943

硬件设计由以下几部分构成:

  1. 最小系统:最小系统主要由时钟电路、复位电路和电源组成。时钟电路选择内部时钟方式,晶振与外围电容构成了自激振荡器,其中晶振采用11.0592MHz。复位电路同时具备上电复位和手动复位功能。
  2. 按键电路:当按键按下时P口读取的输入状态为0,不按时为1。
  3. LED报警电路:LED阳极接+5V电源,阴极通过限流电阻接P2.0口,以此来提高驱动能力。P2.0口输出0时LED亮,输出1时LED灭。
  4. 数码管显示电路:该部分主要用到两个芯片74138、74245以及四位共阴数码管。74138为3-8译码器,输入端接P2.2—P2.4,输出端接数码管位选,将单片机输出的位选信号译码后送往数码管的位选端,以便通过单片机来控制数码管所显示的位。74245为高速CMOS总线收发器,输入端接P0.0—P0.7,输出端接数码管a—f、cp,以此来增加单片机P0口的驱动能力。

4. 软件流程设计

4.1 主函数main

image-20250402220126399

主函数中主要进行初始化以及报警标志alarm_flag和K1、K2的检测,若标志生效,则执行相应操作。检测工作在while(1)中循环进行。

4.2 定时器0中断服务函数Timer0_Routine()

image-20250402220259601

在定时器0中断服务函数中,首先进行赋初值操作,接下来主要完成对系统时基分和秒的个、十位计数。

4.3 报警功能函数alarm_fun()

image-20250402220321148

在 alarm_fun()中,首先调用nixie_show()显示报警第一时刻的时间,接下来控制LED以每200ms亮灭一次频率闪烁。

4.4 数码管显示函数nixie_show()

image-20250402220334841

在数码管显示函数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全灭:

image-20250402220750394

2. 此时按下查询键K2,显示“–.–”,松开后停止显示:

image-20250402220851720

3. 按下报警按键K0后,LED闪烁报警,数码管显示报警第一时刻时间:

4. 按下解除报警按键K1,数码管全暗,LED全灭,报警解除:

image-20250402221048325

5. 此时按下查询键K2,显示上次报警时间“XX.XX”, 松开后停止显示:

image-20250402221119888
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月月如常

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值