ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于51单片机的烟雾报警器设计:多传感器融合防误报

基于51单片机的烟雾报警器设计:多传感器融合防误报 简介基于51单片机的烟雾报警自动设计毕业资料包面向单片机学习者、电子竞赛备赛学生与毕业设计选题者也适合课程设计与项目实践。资源以51单片机为控制核心结合模数转换配合DS18B20温度传感器与MQ-2烟雾传感器展示多传感器信息融合及声光报警系统完整设计链路。包内共45个文件、约2.2MB主要包含论文文档、单片机源程序、原理图文件、工程文件、烧录文件以及备份归档文件其中论文文档提供毕业设计参考源程序覆盖主控逻辑与传感器驱动烧录文件便于直接验证原理图适合仿真改版。已有3749人学习下载。通过该包可获得可直接参考的论文范文、完整可编译代码及配套原理图适合从方案论证、硬件搭建到程序调试的完整学习链路尤其便于快速理解烟雾报警系统的硬件选型、软件流程、程序烧录与整体调试方法。1. 基于51单片机的烟雾报警器先解决误报再谈报警如果把 MQ-2 烟雾传感器的输出直接接到比较器上超过阈值就拉响蜂鸣器厨房炒菜和浴室水蒸气会让报警器毫无价值地叫起来。这个基于 AT89S52、AD0809 和 DS18B20 的烟雾报警设计把烟雾浓度、环境温度、报警输出三条链路放到同一个 51 程序里做联合判断而不是单纯比大小。资源包里有两篇毕业设计论文、Keil C51 源码工程和 Proteus 仿真文件从 AD0809 的通道切换到 DS18B20 的 1-Wire 时序都给出了完整实现。适合正在做 51 单片机课程设计或想理清多传感器采集逻辑的人。下面按硬件接线、代码实现、信息融合、仿真排错四个方向拆开。2. 传感器信号链与 AT89S52 接线从 MQ-2 模拟量到 AD0809 数字量2.1 先看 MQ-2 的测量模型MQ-2 属于半导体气敏电阻内部加热丝把敏感层加热到 200℃ 左右表面吸附还原性气体后电导率升高等效电阻 Rs 下降。典型电路里MQ-2 与负载电阻 RL 串联分压传感器模块的 AOUT 引脚输出 Vout Vcc × RL / (Rs RL)。烟雾浓度越高Rs 越小Vout 越高。真实模块上 RL 常用 10kΩVcc 接 5V。这个输出不是线性关系在低浓度段变化明显再往上逐渐饱和所以不要指望用一个固定比例换算成“浓度百分比”。因为 AT89S52 内部没有 ADC所以必须外接 AD0809。AD0809 是 8 位逐次逼近型转换器满量程 5V 时分辨率约 19.6mV。8 位精度对烟雾报警够用因为报警点通常设在 1V3V 区间不需要 12 位。把 MQ-2 的 AOUT 接到 AD0809 的 IN0地线尽量靠近避免数字信号串扰。模块输出端与 IN0 之间加一个 100nF 电容到地可以滤掉加热丝带来的低频扰动这是实际项目里常见做法。信号传感器/器件单片机引脚说明烟雾浓度MQ-2 AOUTAD0809 IN005V 模拟输入AD 数据AD0809 D0D7P1.0P1.7并口输出通道选择AD0809 A/B/CP2.0/P2.1/P2.2000IN0启动AD0809 START/ALEP2.3/P2.4高电平启动转换结束AD0809 EOCP3.5低电平表示完成输出使能AD0809 OEP2.5高电平读数据温度DS18B20 DQP3.71-Wire 数据线报警蜂鸣器驱动P2.6高电平触发指示LED 报警灯P2.7低电平点亮这个表格里的引脚定义直接对应源码里的sbit声明。先画出引脚映射再写代码是为了避免三个外设抢 P1 口。ADC 数据总线、按键、显示模块最容易冲突声明宏之前确认一下每根引脚用途。#define ADC_DATA P1 sbit ADDA P2^0; // 通道地址最低位 sbit ADDB P2^1; sbit ADDC P2^2; sbit START P2^3; sbit ALE_AD P2^4; sbit OE P2^5; sbit EOC P3^5; sbit BEEP P2^6; sbit LED_ALARM P2^7; sbit DQ P3^7;这段定义把所有外设的 IO 都抽出来了。参数说明ADDA/ADDB/ADDC 是 AD0809 的通道地址IN0 时为 000源码里固定读 0 通道START和ALE_AD在代码中常用于启动转换P1 只读不写避免与蜂鸣器、LED 的引脚输出互相干扰。2.2 AD0809 的时钟与启动时序AD0809 需要外部时钟典型范围是 10kHz1.2MHz常用 500kHz 左右。AT89S52 的 ALE 引脚默认输出晶振频率的 1/612MHz 晶振下是 2MHz直接给 AD0809 偏快。常见做法是用 74LS74 做一次二分频ALE 接 D 触发器输入端Q 输出接 AD0809 的 CLK得到 1MHz这个频率仍在可接受范围。Proteus 仿真时直接放一个 500kHz 时钟源接 CLK 也可以硬件上再用二分频。启动一次转换的标准顺序是先把通道地址写到 A/B/C然后 ALE 延时后拉低锁存地址START 给出一个大于 100ns 的高电平脉冲之后等待 EOC 由高变低再拉高 OE 读取数据。对应的 C 代码在 3.1 节给出。要强调一个容易错的位置EOC 是开漏输出51 的 P3.5 是准双向口可以直接读但需要在外部接一个 4.7kΩ 上拉到 Vcc。仿真里不接也经常能通过真实电路不加上拉经常卡在while (EOC 0)里。2.3 DS18B20 温度读数的边界条件DS18B20 在这套设计里承担的是温度补偿和异常高温判定。1-Wire 总线只需要一根数据线但要严格遵守初始化、ROM 指令、功能指令三段时序。总线空闲时被 4.7kΩ 上拉到高电平主机先拉低 480μs 再释放随后读到的低电平表示设备应答。温度转换需要等待 750ms12 位分辨率如果程序里用delay_ms(750)会阻塞报警扫描。更稳妥的做法是启动转换后先做几轮 ADC 扫描再回来读温度让两种传感器并行工作。DS18B20 的测温范围是 -55℃125℃默认 12 位分辨率时值乘以 0.0625 就是实际温度。在 51 上算小数容易让新手懵实际做法是读取高字节和低字节拼成int再判断符号位。温度越高MQ-2 的基线输出会略有漂移这就是第 4 章要做温度补偿的原因。2.4 报警输出蜂鸣器别直接接引脚蜂鸣器工作电流约 20mAAT89S52 的灌电流能力比拉电流强直接驱动很容易让单片机发热。常见方案是用 S8050 三极管把蜂鸣器放在集电极发射极接地基极通过 1kΩ 接到 P2.6高电平导通。如果是蜂鸣器模块很多已经带驱动三极管只要接 IO 就能响。显示部分用共阳数码管加 74HC245 驱动或者 LCD1602资源里的工程在beep.c里已经包含了蜂鸣器控制仿真时只需要确认发光二极管限流电阻串在正确的一端。3. Keil C51 下的核心代码AD0809 采集、DS18B20 读取与阈值判断3.1 AD0809 驱动与电压换算先给一段可以直接放进 Keil 工程的基础采集函数unsigned char read_ad0809(unsigned char ch) { unsigned char ad_val; ADDA ch 0x01; // 通道地址低三位 ADDB (ch 1) 0x01; ADDC (ch 2) 0x01; ALE_AD 1; // 锁存通道地址 START 1; // 启动转换 _nop_(); _nop_(); // 保持至少 100ns START 0; ALE_AD 0; while (EOC 0); // 等待转换完成 OE 1; ad_val ADC_DATA; // 读取 8 位结果 OE 0; return ad_val; } unsigned int get_smoke_mv(void) { unsigned int ad read_ad0809(0); // IN0 通道 return (unsigned int)(ad * 5000UL / 255); }read_ad0809先设置通道再给 ALE 和 START 一个高电平脉冲。EOC 是 AD0809 发给单片机的状态信号转换开始后 EOC 变高转换结束变低所以用while (EOC 0)等待。读数据前必须拉高 OE否则数据总线是高阻态。get_smoke_mv把 0255 的采样值换算成 05000mV这一步对后面设报警阈值很关键否则阈值无从谈起。参数说明ch传 0 表示 IN0。如果硬件里把 MQ-2 接到了 IN1就改成 1。5000UL是 5V 满量程如果实际供电 4.8V换算时应该改 4800不要照抄。采样值不是真实电压只有经过这个线性映射才能和传感器曲线对标。如果发现读取结果总是满量程或者全 0先检查 EOC 是否接对再把ADC_DATA改成整型加一个短暂延时再看。3.2 DS18B20 的 1-Wire 时序代码DS18B20 的代码比 ADC 容易踩坑因为每个写时隙、读时隙都要求微秒级精确。bit ds18b20_reset(void) { bit presence; DQ 0; delay_us(500); // 复位脉冲 480us 以上 DQ 1; delay_us(60); presence DQ; // 应答脉冲0存在 delay_us(420); return presence; } unsigned char ds18b20_read_byte(void) { unsigned char i, value 0; for (i 0; i 8; i) { value 1; DQ 0; // 启动读时隙 _nop_(); _nop_(); DQ 1; if (DQ) value | 0x80; // 读到 1 delay_us(60); } return value; } void ds18b20_write_byte(unsigned char byte) { unsigned char i; for (i 0; i 8; i) { DQ 0; _nop_(); DQ byte 0x01; // 先写最低位 delay_us(60); DQ 1; byte 1; } }ds18b20_reset是总线上唯一的握手信号主机拉低 480μs 再释放从机会在 1560μs 内拉低总线表示设备在线。读到presence为 0 表示连接正常为 1 表示没接对或线上短路。read_byte与write_byte的每个时隙至少 60μs周期约 120μs。延时函数在 12MHz 晶振下需要微调如果换到 11.0592MHzdelay_us里的空循环次数要重新校准。温度读取完整流程int read_temperature(void) { unsigned char temp_msb, temp_lsb; int temp; ds18b20_reset(); ds18b20_write_byte(0xCC); // 跳过 ROM 匹配 ds18b20_write_byte(0x44); // 启动温度转换 delay_ms(750); ds18b20_reset(); ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // 读暂存寄存器 temp_lsb ds18b20_read_byte(); temp_msb ds18b20_read_byte(); temp (temp_msb 8) | temp_lsb; if (temp 0x8000) // 负温补码 { temp ~temp 1; return -temp * 100 / 16; } return temp * 100 / 16; // 返回温度*100保留两位 }这里把温度乘了 100是为了在 LCD 或数码管上直接显示 XX.XX 度避免引入浮点库。0xCC 是跳过 ROM 指令适用于总线上只有一个 DS18B20如果有多个设备需要按序列号匹配。delay_ms(750)是阻塞延时课程设计演示可以接受实际产品建议换成定时器扫描。3.3 基础阈值判断建议先把采到的烟雾电压打印出来观察正常环境和报警环境下的数值差异。把 500mV 设为预警1000mV 设为报警都比直接拍一个 2000mV 更有余地。基础判断代码很短unsigned int smoke get_smoke_mv(); if (smoke 1000) { BEEP 1; LED_ALARM 0; // 低电平点亮 } else { BEEP 0; LED_ALARM 1; }这是最朴素的阈值报警能应付大部分答辩演示。但一旦把环境温度从 20℃ 升到 40℃MQ-2 的输出电压会跟着上涨可能在没火的情况下直接触发。BEEP 1是高电平驱动如果用的是低电平有效的蜂鸣器模块需要取反。LED 那一路我是按灌电流接法列的低电平点亮实际板子方向不同就反着写。4. 多传感器信息融合与报警状态机单阈值误报的解法4.1 MQ-2 的温度漂移与水蒸气干扰MQ-2 对乙醇、甲烷、油烟和香烟烟雾都有响应热的水蒸气也会让电导率变化。把 AD0809 采集到的电压直接和固定阈值比最容易遇到两个问题梅雨季节湿度高电压持续偏高误报警冬天开暖气温度升高引起基线漂移预警指示灯常亮。要修正这些就得引入 DS18B20 的温度读数再做动态阈值。一个常用做法是threshold base (temp - 25) * temp_coeff。temp_coeff是温度补偿系数单位 mV/℃。不同厂家的 MQ-2 模块差异很大需要开机稳定 5 分钟后用加热源改变环境温度来标定。常见做法是取 1050mV/℃ 范围内的整数在代码里用宏定义方便实验时快速修改。条件烟雾电压温度输出正常 base 70℃不报警烟雾 threshold任何报警高温异常任意≥ 70℃报警预警 base 且 threshold 70℃LED 闪烁这个矩阵控制了一个事实温度超过 70℃ 时无论有没有烟雾电压都要触发报警。因为在火灾现场温度陡增往往早于烟雾扩散。用 DS18B20 作为第二确认信号可以有效防止厨房水汽单独触发。4.2 用变化率识别快速燃烧静态阈值只判断“现在有多大”但火灾初期的特征不只数值高还有上升速度快。每次采样时存下上一次的电压值计算差值delta smoke - last_smoke。如果delta 100mV且持续 50ms说明浓度在快速上涨即使当前值还没到报警阈值也可以先进入预警状态。慢速漏气不会触发这个条件漏气交给阈值判断这样既能响应快速火情又不会对缓慢漂移过度敏感。#define BASE_MV 300 #define ALARM_MV 1000 #define TEMP_ALARM 70 #define DELTA_FAST 100 unsigned int last_smoke 0; unsigned char state 0; void alarm_process(void) { unsigned int smoke get_smoke_mv(); int temp read_temperature() / 100; unsigned int threshold; if (temp 25) threshold ALARM_MV (temp - 25) * 20; else threshold ALARM_MV; if (smoke threshold || temp TEMP_ALARM) state 2; else if (smoke threshold - 200 || (smoke last_smoke smoke - last_smoke DELTA_FAST)) state 1; else state 0; last_smoke smoke; set_alarm_output(state); }threshold随温度线性抬高让同样浓度的烟雾在高温环境下用更高的电压触发这是对基线漂移的补偿。threshold - 200是预警带比正式报警阈值低 200mVsmoke - last_smoke DELTA_FAST捕获电压跳跃。条件里加了smoke last_smoke避免无符号变量计算负数造成溢出。set_alarm_output根据状态控制蜂鸣器和 LED是预处理逻辑和最终输出之间的隔离层。4.3 报警状态机防抖与手动恢复火苗闪烁、人挡在传感器前面都会让电压瞬间升高又回落。如果每次都立刻响铃体验很差。把“持续多少毫秒”纳入条件用定时器中断做时基每 10ms 调用一次alarm_tick()只有状态连续保持 500ms 才切换。#define STATE_NORMAL 0 #define STATE_WARN 1 #define STATE_ALARM 2 unsigned char state STATE_NORMAL; unsigned char stable_ticks 0; void alarm_tick(void) { unsigned char new_state judge_state(); if (new_state state) { if (stable_ticks 50) stable_ticks; if (stable_ticks 50) { apply_output(state); } } else { stable_ticks 0; state new_state; } }这段代码比直接判断阈值多了一个稳定计时器。50 个 tick 对应 500ms如果出现一个毛刺状态马上回到正常计时器清零报警输出不会成立。state只在变化时更新输出只写一次避免频繁拉负载。stable_ticks是 unsigned char最大 25550 次没问题如果时基改为 1ms这里就要用 unsigned int否则会溢出。5. Proteus 仿真与实际排错从源码包到稳定报警的验证5.1 仿真连线与元件放置打开资源里的烟雾传感器.DSN可以看到完整连线。如果从零搭顺序是先放 AT89S52、AD0809、DS18B20、LCD1602 或数码管、蜂鸣器、LED。AD0809 的 CLK 在仿真里直接放一个 500kHz 时钟源地址线 A/B/C 接 P2.0P2.2数据线接 P1EOC 接 P3.5OE 接 P2.5。MQ-2 在 Proteus 中没有集成模型时用一个 10kΩ 电位器替代中心抽头接 AD0809 的 IN0上端接 5V下端接地。旋转电位器就能模拟烟雾浓度升高。编译源码时在 Keil 的 Options for Target - Output 里勾选 Create HEX File。烧录步骤双击 AT89S52 元件在 Program File 里选择beep.hex或sense.hex时钟频率设 12MHz。播放仿真后先旋转电位器观察 ADC 读数变化再按住按键模拟手动测试报警输出。5.2 几个常见的仿真坑第一个坑是 AD0809 的 EOC 不加上拉仿真里有时能通过换真实芯片会一直卡在等待转换完成。第二个坑是 DS18B20 时序太短会在读温度时返回 85℃。这个 85℃ 是 DS18B20 的复位值说明 ROM 指令没被识别调大delay_us的循环参数再试。第三个坑是蜂鸣器直接接在 P2.6驱动能力不够仿真里虽然响但实际音量小加三极管后要共地。故障现象检查点处理ADC 电压全 0EOC 是否上拉 / OE 是否拉高检查延时与位定义温度恒为 85℃1-Wire 时序太短增大延时用示波器看时隙电压满量程 255模拟输入悬空给 IN0 接确定电平报警不恢复状态机计数溢出把 ticks 类型改为 unsigned int5.3 下载后验证的关键一招把 hex 烧到实际板子后不要直接拿打火机测试。先用万用表量 AD0809 的 VREF 和 VCC确认都是 5V。再用手捏住 MQ-2 的网罩看输出电压有没有缓慢变化没有变化就检查模块上的电位器是否调到合适位置。如果上述正常再用打火机气体靠近传感器观察报警 LED 是否在预设的 500ms 防抖之后点亮。通过调整BASE_MV、ALARM_MV和温度补偿系数这三个宏让它在正常空气下稳定运行 5 分钟不报警报警测试两次都能在 1 秒内响应这套基于 51 单片机的自动报警装置才算真正进入可交付状态。本文还有配套的精品资源点击获取
返回列表