ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

51单片机+ADC0809+MQ2无线烟雾报警器完整设计与实现

51单片机+ADC0809+MQ2无线烟雾报警器完整设计与实现 简介本资源是一套基于单片机的无线烟雾报警器完整开发资料面向嵌入式初学者、课程设计学生及智能安防项目实践者解决烟雾浓度实时采集、阈值判断与无线报警触发等核心问题。压缩包共26个文件涵盖C语言源程序.c、编译输出.hex/.lst/.m51、Keil工程文件.uvproj/.uvopt、原理图设计.sch/.pdf/.ddb及元件库.lib辅以多个备份文件.bak和预览文件.schpreview全面支撑从代码编写、仿真调试到硬件设计的全流程学习。资源大小为436KB结构清晰模块划分明确含ADC0809模数转换驱动、MQ2传感器信号采集、烟雾浓度判据逻辑及基础无线报警控制框架便于理解模拟传感信号处理与单片机中断响应机制。目前已有269人学习下载适合开展电子设计实训、毕业设计原型开发或物联网安全类课程实验。 做烟雾报警器设计十个里头九个会选MQ2便宜、灵敏度够、资料满天飞。但这个题不一样的地方在于它点名要ADC0809还要求报警信息通过无线方式送出去最终落成一个无线烟雾报警器。我第一反应是这搭配不是老课程设计吗后来仔细捋了一遍发现这个组合其实把单片机入门的几个硬骨头全串起来了——MQ2负责把烟雾浓度变成模拟电压ADC0809负责把模拟电压量化成8位数字量51单片机负责读数据、判报警、走无线三个环节正好对应模拟采集、并行时序、串口通信。如果你正在准备课程设计或者毕设手上就有一块51单片机开发板这篇文章可以帮你从原理到实物完整走一遍。下文里要讲的接线、代码、调试经验都是按AT89S52/STC89C52这种传统8051内核单片机来写的别拿STM32那套来套毕竟这俩的出发点和难度完全不一样。1. 先拆解需求这套无线烟雾报警器到底要解决什么问题1.1 MQ2传感器的输出信号和你想象的不一样MQ2不是什么精密传感器它本质上是一颗二氧化锡半导体气敏电阻。内部有一条加热丝把敏感材料加热到工作温度导电率会随周围还原性气体浓度变化洁净空气里电导率很低遇到烟雾、液化气、天然气、酒精蒸汽时电导率明显上升。如果你买的是模块版板上已经有一颗LM393比较器和一个可调电位器会引出两个输出脚AO是模拟电压输出DO是数字电平输出。DO口的阈值由电位器调新手很容易拧了半天电位器发现AO读数纹丝不动因为AO根本不受那个电位器控制电位器只改比较器的翻转点。AO输出范围一般是0到VCC。模块内部用负载电阻把传感器的电阻变化转换成电压典型接法是传感器一端接VCC另一端串联一个4.7k到10k的负载电阻到GND从传感器与负载电阻的连接点取电压。洁净空气时这个点电压可能只有0.1到0.3V烟雾靠近后可能飙到1.5V以上。如果直接用裸传感器而不是模块必须自己外接负载电阻否则输出脚悬空信号没法读。注意MQ2的响应是非线性的浓度低的时候电压变化缓慢浓度高一点以后电压上升很快。所以后面单片机判报警时不能指望它像温湿度传感器那样有漂亮的线性曲线更多时候是设一个合适的电压门槛越过门槛就报。1.2 51单片机没有内置ADC这就是ADC0809出场的原因51单片机里最经典的STC89C52内部没有ADC模块。AT89S52也没有。想让单片机认识MQ2送出来的模拟电压有两条路换一颗带ADC的型号比如STC12C5A60S2、STC15系列直接用内置ADC或者外扩一颗独立的ADC芯片。题目既然点名ADC0809基本就走第二条路。ADC0809是一颗8位逐次逼近型ADC8路模拟输入并行8位数据输出单电源5V转换时间在100微秒左右。8位分辨率换算下来在5V参考电压下每1个LSB大约是19.53mV对烟雾报警来说完全够用。它最典型的特点是需要外部提供时钟信号最高时钟约1280kHz推荐范围500到640kHz。这一点很多资料写得含糊实际调试时很多人就在这里卡住。选择ADC0809的好处是你能把51单片机的并行数据总线、片选控制、状态查询这些基础操作完整练一遍。它不像I2C那样一根线串到底也不像SPI那样要模拟时序而是标准的“地址锁存、启动转换、查询结束、并行读数据”流程非常适合理解CPU和外部设备是怎么打交道的。1.3 无线模块怎么选直接决定下位机程序的复杂度标题里“无线”两个字没有指定具体方案于是很多人第一反应是NRF24L01。NRF24L01确实便宜但它在51平台上不算好伺候3.3V供电需要电平转换SPI时序要靠IO口模拟寄存器配置一大堆天线和电源滤波没做好还会出现近距离通信反而丢包的问题。对课程设计来说不是不能做而是调试周期容易被拉长。我自己的推荐是HC-12无线串口模块。它本质是RF透传单片机只需要把它当普通串口设备用发什么它就发什么接收端串口收到的就是原始字节。HC-12供电范围3.2到5.5VTTL电平和51单片机直接连问题不大空旷环境通信距离号称能到一公里实际室内隔两堵墙也有几十米对烟雾报警器这种场景绰绰有余。缺点是一对模块只能点对点通信不支持一对多组网但咱们这个项目本来就是单发射端对单接收端没什么影响。如果非要选NRF24L01也能做但程序里要多一整套SPI驱动和寄存器初始化后面无线帧解析的复杂度也会上升。我下面主线的硬件方案用HC-12调试思路同样适用于其他无线模块差异只在底层收发函数。2. 硬件连接方案从MQ2到ADC0809再到无线模块的完整链路2.1 MQ2与ADC0809的模拟量接入MQ2模块的AO输出直接接到ADC0809的IN0通道也就是第26脚。ADC0809一共有IN0到IN7八个模拟输入通道这里只用IN0其他通道接地防干扰。Vref接5VVref-接GND这样输入电压范围就是0到5V。如果用精密基准源可以接到Vref让采样更稳定但要注意基准电压不能高于MQ2模块的最大输出电压否则高浓度信号会被削顶8位分辨率也会浪费掉一部分。MQ2的AO输出内阻不算低而ADC0809的输入端等效电阻很大直接连接不会明显拉低信号。但如果你的MQ2是裸传感器不能直接接ADC0809必须先用负载电阻分压成电压信号再送进IN0。分压电阻取4.7k到10k都行阻值越小输出电压越低灵敏度也越低具体可以根据实验调整。2.2 ADC0809与51单片机的时序型接口ADC0809与51单片机的连接是这块电路的核心引脚分配我建议这样接ADC0809引脚接单片机引脚作用D0-D7P0.0-P0.78位并行数据输出IN0MQ2模块AO模拟烟雾信号输入ADDA/ADDB/ADDCP2.4/P2.5/P2.6通道地址选择IN0对应000ALEP2.0地址锁存控制STARTP2.1启动转换控制EOCP2.2转换结束状态输出OEP2.3输出使能控制CLKP1.0外部时钟输入需要500kHz左右ADC0809的时序动作是先把通道地址放到ADDA/ADDB/ADDC上ALE给一个正脉冲锁存地址然后START给一个正脉冲启动转换。转换期间EOC变低转换完成后EOC变高。单片机读到EOC变高后把OE拉高ADC0809就把8位数据送到D0-D7此时从P0口读到的就是当前烟雾浓度对应的数字量。STC89C52的P0口没有内部上拉作为输入读取前最好先执行P00xFF虽然ADC0809的OE使能后数据线由芯片驱动但养成这个习惯能少踩很多坑。ALE和START可以接同一个IO口给一个正脉冲同时完成锁存和启动很多原理图都这么画实际工作也没问题。2.3 无线报警链路与现场执行电路发射端单片机串口TXD接HC-12的RXDRXD接HC-12的TXD两个模块共地CH引脚悬空即可。HC-12默认波特率9600出厂模块之间的信道和参数已经配对如果不是一套模块需要通过USB转TTL进入AT指令模式重新设置信道两条模块的ATCH值必须一致否则收不到。接收端就是另一个51最小系统加一个HC-12外加一颗有源蜂鸣器。蜂鸣器不建议直接焊在IO口上就完事一定要用三极管或者ULN2003驱动。MQ2加热丝电流本身就不小HC-12在发射时峰值电流能到100mA以上蜂鸣器再直接吃IO口电流很容易把5V电源拉出纹波。我习惯的做法是蜂鸣器接一个NPN三极管基极串1k电阻接单片机IO集电极接蜂鸣器负极蜂鸣器正极接VCC这样IO口只负责给基极电流压力小得多。如果希望报警时顺便启动排风扇或者电磁阀在接收端加一个继电器模块用PNP或NPN三极管驱动继电器线圈注意继电器线圈要反向并联一个1N4007二极管吸收反向电动势否则关断瞬间可能打坏单片机。3. 单片机程序核心驱动、采样、判定、发送四段式3.1 时钟从哪来用定时器给ADC0809一个稳定的500kHzADC0809没有内部时钟必须外部提供。最省事的错误做法是把51单片机的ALE脚直接引过去分频——12MHz晶振下ALE输出2MHz超过芯片允许范围转换结果可能完全错误。用74LS74二分频得到1MHz仍然略高而且多一颗芯片多一份布线麻烦。我的方案是拿定时器T0产生方波。推荐晶振用11.0592MHz不要用12MHz。原因很实际串口9600波特率在11.0592MHz下能精确分频12MHz会引入不可忽略的波特率误差。虽然12MHz下T0定时很方便机器周期刚好1微秒但和串口精度比起来这点方便不值得。T0设置为方式2也就是8位自动重装定时器晶振11.0592MHz机器周期大约是1.085微秒。每溢出一次中断里翻转一次P1.0输出方波频率大约460kHz落在ADC0809推荐工作范围内。代码很短void Timer0_Init(void) { TMOD 0xF0; TMOD | 0x02; // T0方式28位自动重装 TH0 0xFF; TL0 0xFF; // 最大计数初值溢出率约460.8kHz ET0 1; TR0 1; EA 1; } void Timer0_ISR(void) interrupt 1 { ADC_CLK ~ADC_CLK; }别小看这段代码T0中断函数里只做一件事翻转引脚整个系统频率调度不会受影响。如果你非要省一个定时器也可以用两个IO口软件延时翻转产生方波但主循环一忙起来时钟频率就不稳ADC转换结果会跟着飘不建议。3.2 读取ADC0809的完整流程一个函数搞定ADC0809的读取函数是整套程序的基石。完整流程是选通道锁存地址启动转换等EOC先变低再变高最后打开OE读数据。这里有个容易被忽略的细节EOC初始状态是高的启动转换后才会变低转换完成再变高。如果代码一上来就while(!EOC)很可能EOC还没反应过来已经被当作“转换完成”跳过所以要先等EOC变低再等它变高。uchar ADC0809_Read(uchar channel) { uchar val; ADC_ADDA channel 0x01; ADC_ADDB (channel 0x02) ? 1 : 0; ADC_ADDC (channel 0x04) ? 1 : 0; ADC_ALE 0; ADC_START 0; P0 0xFF; // P0口输入前画电平防浮空 ADC_ALE 1; ADC_START 1; // 锁存地址并启动转换 _nop_(); _nop_(); ADC_START 0; ADC_ALE 0; while (ADC_EOC 1); // 等待EOC变低确认转换开始 while (ADC_EOC 0); // 等待EOC变高转换完成 ADC_OE 1; _nop_(); _nop_(); val P0; ADC_OE 0; return val; }这个函数每次调用大约耗时100多微秒对烟雾报警这种秒级响应场景完全够用。如果你想读取多于一路信号把ADDA/ADDB/ADDC改成通道号就行IN0到IN7一一对应。3.3 滤波与报警判定防止误报漏报的关键算法MQ2输出的模拟信号噪声不小尤其旁边有继电器、电机这类干扰源时单次采样的抖动经常能达到好几个LSB。我习惯用去极值平均滤波连采8次去掉最大和最小剩下6次求平均。这样既抑制了尖峰脉冲又不会像全平均那样被异常值拖偏。uchar Get_MQ2_Value(void) { uchar i, val, maxv, minv; uint sum 0; for (i 0; i 8; i) { val ADC0809_Read(0); sum val; if (i 0) { maxv val; minv val; } else { if (val maxv) maxv val; if (val minv) minv val; } } return (uchar)((sum - maxv - minv) / 6); }报警判定不能做一个“当前值超过阈值就报警”的简单比较否则只要有人点根烟飘过来一下蜂鸣器就响个不停。我的做法是连续确认连续5次采样都超过阈值才真正进入报警状态只要有一次低于阈值计数清零。采集周期按200毫秒算大约需要1秒的持续超标才会报警既过滤了瞬时干扰又不会拖慢响应。阈值本身建议做成一个可以宏定义的参数项目初期先用一个估计值跑通后面再根据实测数据微调。3.4 无线数据帧设计让接收端知道谁在报警、浓度多少HC-12是串口透传MCU只需要把数据字节从串口发出去。但直接裸发一个字节没有任何容错能力电磁干扰、接触不良都可能让接收端收到错误数据。我的帧格式非常简单帧头两个字节0xAA 0x55然后是长度、浓度值、报警标志最后加一个校验和。校验和用前面所有字节的异或值接收端重新算一遍对不上就丢弃这一帧继续等下一帧。void Transmit_Status(uchar smoke, bit alarm) { uchar check 0xAA ^ 0x55 ^ 0x03 ^ smoke ^ (alarm ? 0x01 : 0x00); UART_SendByte(0xAA); UART_SendByte(0x55); UART_SendByte(0x03); // 后面数据长度 UART_SendByte(smoke); // 烟雾浓度ADC值 UART_SendByte(alarm ? 0x01 : 0x00); // 报警标志 UART_SendByte(check); // 校验和 }这里把报警标志放在数据帧里而不是让接收端单独判断浓度阈值是因为阈值标定在本文还有配套的精品资源点击获取
返回列表