news 2026/9/11 19:02:32

基于AT89C51的烟雾浓度与温度检测火灾报警系统设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于AT89C51的烟雾浓度与温度检测火灾报警系统设计

简介:这是一份基于AT89C51单片机的温度烟雾火灾报警系统设计方案,面向单片机初学者与电子设计竞赛参赛者。系统具备火情探测、灯光报警、蜂鸣器报警和阈值调节等核心功能。烟雾采集选用MQ-2传感器,输出模拟信号,经ADC0832转换后送单片机;温度采集用DS18B20,通过单总线与单片机相连。显示设备采用数码管,实时显示烟雾浓度值和温度值。报警模块由蜂鸣器和LED组成,检测元素超标即鸣叫。此外,系统提供三个按键调节报警阈值,并增加一个手动报警按键。压缩包约4.93MB,包含设计相关文件,便于对照原理图与代码理解流程。目前已有354人学习浏览,覆盖传感器选型、数据转换、显示与报警联动等关键环节,对掌握单片机火灾监测应用有参考价值。

1. AT89C51 双路传感器的火警数据链路解析

当年实验室的防火监控需要在可见烟雾出现前就预警,温度探头和烟雾传感器往往很难在同一个 MCU 上有序工作。MQ-2 的模拟输出需要外接 ADC,而 DS18B20 又是一条完全不同的单总线协议,再加上数码管轮流刷新,很多团队在调试时节拍会乱——显示一卡,温度跳变,报警又误触发。这套系统把 AT89C51 作为主控,让 ADC0832 承担烟雾信号的模数转换,DS18B20 直接上报温度,数码管显示实时状态,蜂鸣器和 LED 负责多级警报。在入门 51 平台上,这种组合能充分利用端口资源,是性价比最高的经典做法。对于正在做课设、嵌入式入门或者是想把实物完整跑起来的人来说,这套线路覆盖了传感器采集、总线时序、按键阈值校准和报警联动四个核心环节,值得从实物可复现的角度逐步拆解。

2. 硬件连接:AT89C51 怎么同时挂上 ADC0832 和 DS18B20

在入门 51 上,同时使用 ADC0832 和 DS18B20 最大的问题是端口资源占用。多数人设计时会先拨 P0 做数码管段选,P2 做位选,再把 P1 口的一部分划给传感器。常见做法是 P1.0 接 MQ-2 的模拟输出到 ADC0832 的 CH0,P1.1 接 DS18B20 的数据线,另外 P1.3~P1.5 接三个按键,P2.7 接蜂鸣器,P2.0、P2.1 接 LED。这种安排保证了 ADC0832 时钟和数据线不会与数码管动态扫描互相干扰。

2.1 MQ-2 的模拟输出与 ADC0832 的采样电路

MQ-2 的敏感体是二氧化锡,还原性气体浓度升高时导电性变强,输出到负载电阻的电压随之抬高。这个输出电压一般在 0~5V 之间摆动,普通 51 内部没有 ADC 无法直接读取,所以要把信号送到 ADC0832 的 CH0 通道。ADC0832 是 8 位串行逐次逼近型 ADC,256 级分辨率对 MQ-2 这种趋势性信号完全够用:烟雾浓度从 200ppm 升到 1000ppm 时,电压差异远大于一个 LSB。转换时钟由单片机机器周期分频得到,一般取 250kHz 上下比较稳妥。

实际接线时有两个细节容易出问题。第一,MQ-2 的 DO 引脚是内部比较器输出的数字信号,很多设计者误把 DO 直接接单片机,结果烟雾浓度线性区域表现很差,正确做法是取 AO 模拟输出接 ADC0832 的 CH0。第二,ADC0832 的 CS 要拉低才能启动转换,片选若和数码管位选共用一个端口,扫描瞬间会产生采集噪声;改到独立 IO 后基本能消除。下面给出一份建议接线:

信号MCU 端口说明
ADC0832.DI/DOP1.0数据输入输出复用脚
ADC0832.CLKP1.1串行时钟输入
ADC0832.CSP1.2片选,低电平有效
DS18B20.DQP3.7单总线数据线,需接 4.7k 上拉
蜂鸣器P2.7经 NPN 三极管驱动
LED1(烟雾报警)P2.0烟雾超阈值点亮
LED2(温度报警)P2.1温度超阈值点亮
按键 S1~S3P1.3~P1.5阈值加减与确认

表里把 ADC0832 和 DS18B20 的端口彻底分开,数码管又占用 P0 和 P2 的高位,这种分配在后续调试时可以避免总线驱动电平竞争。

2.2 DS18B20 单总线接法在强电环境下要注意什么

DS18B20 的一线总线协议全靠单根线上的时序高低电平传递,上拉电阻必须选 4.7k。报警器周围如果存在继电器或其他感性负载模块,线上毛刺很容易把复位脉冲误判成数据帧,所以布局里要尽量把传感器线缩短,并在 VCC 和 GND 之间加一个 0.1uF 去耦电容。我做过一次实物调试时踩过这个坑:扎带把 DS18B20 数据线与继电器驱动线绑在一起,断电瞬间温度读数直接变成 -55 或 125 两个极端值。而 AT89C51 的 P3.7 上电默认状态是准双向口,读引脚前要先置 1,这个特性在代码里必须时刻记住,后面时序部分会再展开。

如果打板而不是洞洞板飞线,建议把 DS18B20 用 3PIN 排针引出,地线和信号线间距至少 2mm。传感器离主板超过 30cm 时,屏蔽线情况下总线电容应控制在 200pF 以内,否则上升沿变缓,程序可能一直卡在转换等待。

注意:DS18B20 的 VCC 不要从 MQ-2 的加热回路取电,加热丝瞬间压降会导致温度芯片复位。

2.3 显示、按键和报警执行电路参数推荐

数码管选用 4 位共阴即可,P0 口经 200Ω 排阻限流做段选,P2.3~P2.6 做位选,通过 8550 三极管驱动公共端。蜂鸣器选择 5V 有源蜂鸣器,经 S8050 接到 P2.7,严禁直接接 IO 口,AT89C51 拉电流上限约 20mA,直接驱动会拉低端口电平甚至烧毁引脚。按键部分若用板上微动,直接接 10k 上拉,并配 100nF 电容滤波,程序内再补一次消抖。这套设计的供电能力完全依托 51 基本盘展开:P0 段选 + P2 位选 + P1 传感器输入,各外设之间没有共用同一组总线的尴尬。

若使用外部电源适配器,建议 7805 输入侧留一个 470uF 电解电容。MQ-2 加热丝启动瞬间电流可达 150mA 以上,电压跌落会造成单片机复位,这是实物调试中非常隐蔽的偶发故障。

3. 固件实现:AD 值、温度值到稳定显示的转换过程

硬件链路搭建完成后,固件核心分为三块:ADC0832 的时序读取、DS18B20 的时序读取、数码管动态扫描刷新。三者放在同一个主循环里时要特别注意时序占用,因为 DS18B20 转换期间要求数据线保持稳定,而 ADC0832 的串行时钟又不能被中断拖得太久。以下是我在 12MHz 晶振下的实现思路。

3.1 ADC0832 驱动与连续采样消抖

#include <reg52.h> #include <intrins.h> sbit ADC_CS = P1^2; sbit ADC_CLK = P1^1; sbit ADC_DIO = P1^0; /* 读取 ADC0832 指定通道的 8 位转换结果 */ unsigned char read_adc0832(unsigned char channel) { unsigned char i, dat1 = 0, dat2 = 0; ADC_CS = 1; ADC_CLK = 0; ADC_CS = 0; /* 片选拉低,启动转换 */ ADC_DIO = 1; ADC_CLK = 1; _nop_(); ADC_CLK = 0; /* 第一个下降沿写入起始位 */ ADC_DIO = 1; ADC_CLK = 1; _nop_(); ADC_CLK = 0; /* 第二个下降沿写入 SGL/DIFF 位 */ ADC_DIO = channel; /* 0 选 CH0,1 选 CH1 */ ADC_CLK = 1; _nop_(); ADC_CLK = 0; /* 第三个下降沿写入通道号 */ ADC_DIO = 1; /* 释放数据线,准备读取 */ ADC_CLK = 1; _nop_(); ADC_CLK = 0; for (i = 0; i < 8; i++) { ADC_CLK = 1; ADC_CLK = 0; if (ADC_DIO) dat1 |= (0x80 >> i); /* 高位在前收集数据 */ } for (i = 0; i < 8; i++) /* 读取后半段校验数据 */ { dat2 >>= 1; if (ADC_DIO) dat2 |= 0x80; ADC_CLK = 1; ADC_CLK = 0; } ADC_CS = 1; return dat1; }

这段代码的核心时序是:CS 拉低后连续送四个时钟,依次写入起始位、通道选择位、单端输入标志位;随后方向从 DI 切换为 DO,在后续 8 个时钟的下降沿逐位读出结果。dat1 保存第一次读到的 8 位数据,dat2 保存第二组读出的数据,两者若相差超过 1,说明通信线上有干扰,我一般会丢弃本次结果并重新触发采样。ADC0832 是 8 位精度,返回 0~255 对应 0~5V 电压,程序里做阈值比较时直接使用这个原始 AD 值即可。

配合 MQ-2 使用有个常见问题:传感器上电前 30 秒输出电压会先冲高到接近 5V,然后缓慢回落到静态值。如果单片机上电后立刻采样,容易误判为高浓度烟雾触发报警。解决办法是上电后先延时 60 秒再进入采样循环,或者连续读 10 次去掉最大最小值取平均。

3.2 DS18B20 单总线时序驱动

sbit DQ = P3^7; void ds18b20_reset(void) { DQ = 0; delay_us(480); /* 主机拉低 480us 以上产生复位脉冲 */ DQ = 1; delay_us(60); /* 释放总线,等待器件应答 */ } unsigned char ds18b20_read_bit(void) { unsigned char bit; DQ = 0; _nop_(); /* 拉低 1us 后释放 */ DQ = 1; _nop_(); bit = DQ; /* 在 15us 窗口内采样 */ delay_us(50); return bit; } unsigned char ds18b20_read_byte(void) { unsigned char i, dat = 0; for (i = 0; i < 8; i++) { dat >>= 1; if (ds18b20_read_bit()) dat |= 0x80; } return dat; } void ds18b20_write_byte(unsigned char dat) { unsigned char i; for (i = 0; i < 8; i++) { DQ = 0; _nop_(); DQ = dat & 0x01; /* 数据位从低位开始写入 */ delay_us(60); DQ = 1; dat >>= 1; } } unsigned char get_temperature(void) { unsigned char low, high; ds18b20_reset(); ds18b20_write_byte(0xCC); /* 跳过 ROM,单点测温 */ ds18b20_write_byte(0x44); /* 启动温度转换 */ while (!DQ); /* 转换完成 DQ 被释放拉高 */ ds18b20_reset(); ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); /* 读取暂存器数据 */ low = ds18b20_read_byte(); high = ds18b20_read_byte(); /* 12 位分辨率下拼接整数部分,忽略小数位 */ return (high << 4) | (low >> 4); }

DS18B20 的通信分为初始化、ROM 命令、功能命令三个层次。rst后通过拉低 480us 产生复位脉冲,器件会回一个 60~240us 的低电平应答;接着写 0xCC 跳过 ROM 寻址,0x44 启动转换,等待 DQ 引脚释放后重新复位,再发 0xBE 读取暂存器前两个字节。返回的是带符号补码,比如 0x0032 代表 50°C,0xFFCE 代表 -50°C,判断温度超限时直接与阈值比较。

提示:DS18B20 的延时函数不要用带中断的 delay,建议用_nop_()组合或关闭中断的定时查询,否则中断服务函数会破坏单总线时序。

3.3 数码管 4 位动态扫描与数据缓冲

unsigned char code seg_code[10] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F }; unsigned char disp_buf[4]; unsigned char disp_pos = 0; void timer0_isr(void) interrupt 1 { TH0 = 0xFC; TL0 = 0x18; /* 12MHz 下定时 2ms */ P0 = 0x00; /* 消隐,防止拖影 */ P2 &= 0x0F; P0 = seg_code[disp_buf[disp_pos]]; P2 |= (0x10 << disp_pos); /* 选中当前位 */ if (++disp_pos >= 4) disp_pos = 0; }

显示部分放在定时器中断里,每 2ms 切换一位数码管,四位数码管 8ms 完成一轮刷新,人眼看不到闪烁。主循环只需维护 disp_buf 数组:显示温度时,disp_buf[0] 和 disp_buf[1] 放温度十位和个位,disp_buf[2] 放 0x40 作为分隔符号;显示 AD 值时,把 0~255 映射成两位十进制。P2 高四位用作位选,切换前先 P0=0 消隐。这样做的收益是显示刷新与采样时序解耦,DS18B20 转换期间定时器中断照常发生,但因为中断服务函数只有显示逻辑,不会碰到 DQ 引脚,所以不会破坏单总线时序。

3.4 按键消抖与长按连续调阈值

按键 S1 加一、S2 减一、S3 确认是这类系统最常见的交互方式。阈值初始化时烟雾阈值设为 150,温度阈值设为 50°C。按键消抖不做软件延时死等,而是利用主循环扫描周期,连续两次读到同一电平才认为稳定,10ms 后再进入分支。长按 S1 或 S2 超过 60 次扫描后,把计数器阈值设为 3,实现连续快速加减,不需要一次次按。

主循环骨架如下:

while (1) { smoke_val = read_adc0832(0); temp_val = get_temperature(); /* ADC 值在 0~255 之间,与阈值直接比较 */ if (smoke_val > smoke_limit) led_smoke_on(); if (temp_val > temp_limit) led_temp_on(); if (smoke_val > smoke_limit || temp_val > temp_limit) buzzer_on(); else buzzer_off(); scan_key(); /* 消抖 + 长按检测 */ update_display_mode(); /* 3 秒交替显示 */ }

主循环中不建议把 ADC 和 DS18B20 采样放进中断。尤其是 DS18B20 的 while 等待,一旦中断优先级配置不当,很可能导致传感器应答位丢失。更好的做法是把采样放在主循环顺序执行,数码管刷新放在定时器中断里,两者互不打扰。

4. 阈值调节与手动报警:从按键到报警状态的联动

阈值按键和手动报警按键是这套设计里最能体现交互细节的部分。如果按键逻辑写得太简单,会出现设置状态下误触报警、手动报警无法撤销等问题。这一章把这些交互边界逐一理清。

4.1 阈值设置的进入、修改与保存

阈值调整不应在正常监控模式下直接响应 S1/S2,否则现场人员擦拭面板就会误改参数。常见做法是同时按住 S3 超过 1 秒进入阈值设置模式,数码管第一位显示 S 代表烟雾阈值,后两位显示当前 AD 阈值;再按 S3 切换到 T 代表温度阈值;S1/S2 修改数值;长按 S3 退出并写入保存。如果用 24C02 EEPROM 保存阈值,写操作约 5ms,期间按键扫描会被阻塞,所以保存动作应在退出设置时统一执行,而不是每按一次 S1 写一次 EEPROM。

阈值修改后要检查合法性:烟雾阈值范围限制在 30~250,温度阈值限制在 30~85°C。低于下限会导致开机瞬间误报警,高于上限则报警功能形同虚设。不少课设同学把阈值随意设在 0 或 255,恰好踩中 MQ-2 上电脉冲的峰值,这种问题在初版代码里非常常见。

4.2 手动报警与自动报警的优先级设计

手动报警按钮的存在意义是:系统阈值未超标但人已闻到焦味时,提供一个强制的报警入口。单片机读取到该按键拉低后,应立即进入独立报警分支,不依赖任何阈值判断。S3 必须长按 2 秒才能消除,避免误触或小孩乱按后无法复位。报警状态的真值表如下:

场景蜂鸣器LED 状态
温度超限鸣叫红色 LED 亮
烟雾超限鸣叫黄色 LED 亮
温度和烟雾同时超限鸣叫双 LED 亮
手动报警鸣叫,不依赖阈值双 LED 闪烁
无异常关闭绿色 LED 慢闪

手动报警分支的优先级最高,自动报警判断在其之后执行。消除手动报警的唯一入口是 S3 长按 2 秒,期间数码管显示H提示手动报警状态。这个设计比简单的一键消除更符合实际安防产品习惯——消除操作需要刻意且明确。

4.3 显示模式自动轮换与缓冲区写入

显示内容分为温度模式和烟雾模式,主循环通过一个 3 秒计数器切换。在阈值设置界面下,显示缓冲区强制写入设置值而非实时采样值,避免用户调阈值时看到数字不停跳动。计数器声明时必须加 volatile,否则 keil 优化后可能出现判断条件被内联掉导致显示永不切换的情况。实际实现中我用一个 16 位计数器,每次主循环自增,达到阈值就取反显示标志并清零。显示缓冲区只在主循环中写入,定时器中断只读取,这样不会出现数据竞争。

5. 实物调试的关键动作:从时序到阈值漂移的排错顺序

5.1 上电先量静态电平,再抓总线时序

拿到实物板子后不要急着烧录程序。先测三组电压:DS18B20 的 DQ 引脚静态电平应接近 5V,低于 2V 说明传感器未接好或已经短路;MQ-2 的 AO 引脚静态电压应在 0.3~1V 之间,刚上电会偏高,等 60 秒再量;蜂鸣器驱动三极管基极电压应为 0V 或用万用表二极管档确认无击穿。之后用示波器观察 DQ 线上的复位脉冲,正常能看到 480us 低电平和紧随的 80us 应答脉冲。没有示波器时,在 ds18b20_reset 后读 DQ,读到 1 直接返回 0xFF 错误码,通过串口区分通信断裂与传感器断开。

5.2 MQ-2 预热漂移与基准校准

MQ-2 数据手册给出的预热稳定时间是 24 小时,实际做实物时不可能等那么久。我一般在上电 2 分钟后连续采样 10 次取平均作为基准值,比如静态 AD 值 45,就把报警阈值设为基准值加固定增量 80,也就是 125。增量的大小按环境调整:厨房油烟大放 100,机房要求灵敏放 60。基准值每 30 秒做一次滑动平均更新,以消除凌晨和中午温湿度不同带来的基线漂移。

5.3 三条高频故障路径和对应解法

整理实物调试中最常见的问题。第一,ADC0832 的 CS 与数码管位选共用引脚,扫描瞬间转换结果跳变,表现为烟雾值每隔几百毫秒出现一个尖峰,解决办法是把 CS 挪到独立空闲 IO。第二,DS18B20 数据线过长或走线宽带不足,温度读数隔几次跳变一次,这是上升沿变缓导致采样窗口错位,缩短线长或换双绞线可解决。第三,蜂鸣器启动瞬间电源跌落导致单片机复位,现象是报警一响数码管熄灭又重启,检查 7805 输出端是否放置 100uF 电解电容,没有的话补上并把蜂鸣器供电单独加 10uF 去耦。

最后做一次完整的报警链路验证:用打火机气体靠近 MQ-2,3~5 秒内蜂鸣器应鸣叫,黄色 LED 点亮;用电烙铁靠近 DS18B20 加热,温度超过设定值时红色 LED 点亮,蜂鸣器再次鸣叫;按下手动报警键,无论当前采样值高低都应立即进入报警状态。整个过程中数码管上的 ADC 值和温度值实时变化,这正是这套基于 AT89C51 的设计最直接的验收标准。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 19:02:23

JAVA毕设选题推荐:基于 SpringBoot 的烘焙电商平台的设计与实现 基于 SpringBoot 技术的甜点商城系统【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/9/11 19:01:11

15%的补贴,为什么开始给人形机器人?

本文为政策机制研究&#xff0c;数据均来自公开来源&#xff08;官方披露/权威机构&#xff09;&#xff0c;仅作机制分析&#xff0c;不构成投资建议。全域财经深度研究 2026-09-09 发布一、政策换了名字&#xff0c;账本换了结构 2026年8月31日&#xff0c;商务部等七部门印…

作者头像 李华
网站建设 2026/9/11 18:59:26

MATLAB实现蔬菜定价数模:从数据清洗到需求预测与优化

简介&#xff1a;围绕2023年全国大学生数学建模竞赛C题“蔬菜定价”的RAR压缩包&#xff0c;内含可编辑Word论文和配套源代码&#xff0c;面向参赛学生、毕业设计者以及数据分析学习者&#xff0c;用于解决蔬菜定价中成本、供需、季节等多因素权衡问题。资源完整呈现了从数据清…

作者头像 李华
网站建设 2026/9/11 18:57:31

先进制造AI+BI试点:生产分析场景包的落地验证方法

导语 不少先进制造企业推进AIBI数字化转型&#xff0c;容易陷入两种误区&#xff1a;要么贪大求全&#xff0c;一上来就推进全工厂全链路落地&#xff0c;导致投入大、周期长&#xff0c;迟迟看不到验证效果&#xff1b;要么盲目试错&#xff0c;随便选个场景上线&#xff0c;验…

作者头像 李华
网站建设 2026/9/11 18:55:48

WSN时间同步原理与MATLAB仿真:时钟偏移估计与CRLB校验

简介&#xff1a;围绕无线传感器网络&#xff08;WSN&#xff09;时间同步仿真&#xff0c;MATLAB工程资源完整覆盖了算法实现、性能评估与结果分析环节。资源共18个文件&#xff0c;压缩包大小10.2MB&#xff0c;主要包含可直接运行的m脚本、保存仿真数据的mat文件、记录MSE与…

作者头像 李华
网站建设 2026/9/11 18:53:36

重庆旅游大数据平台:个性化推荐与3D可视化实践

1. 项目背景与核心价值重庆作为中国最受欢迎的旅游城市之一&#xff0c;每年吸引着数以千万计的游客。但面对山城复杂的地理环境和丰富的旅游资源&#xff0c;游客常常陷入"去哪玩""怎么玩"的决策困境。传统的旅游推荐方式存在三个明显痛点&#xff1a;信息…

作者头像 李华