51单片机空气质量检测系统设计:从MQ传感器到Proteus仿真
发布时间:2026/9/12 12:36:17 作者:尧图编辑部 阅读量:1,286

简介一套基于51单片机的空气质量检测系统资料包面向单片机课程设计、毕业设计及环境监测项目开发人群。系统以 STC89C51 为控制核心集成温湿度、硫化氢、氨气、甲烷、一氧化碳传感器配合 A/D 转换、按键、液晶显示与声光报警模块可实时采集并显示气体浓度对温湿度越限给出报警适用于污水处理厂等场景的电子鼻设计。资源共 60 个文件压缩包约 1.56MB涵盖 C 源码主程序、DHT11、ADC0832、LCD1602 驱动、Proteus 仿真工程、原理图、流程图、元件清单及 PDF 预览等其中位图流程图直观展示了 LCD1602、ADC0832 和主程序的执行逻辑目录区分明确便于对照学习。已有 152 人学习下载。使用者可借此快速复现完整功能理解多传感器数据采集与单片机处理流程也可根据原理图和清单自行搭建硬件进行二次开发。1. 基于51单片机的空气质量检测系统在课程设计里到底难在哪很多人看到这个标题第一反应是“接线多、代码长”但真正卡住进度的不是这些。MQ系列气体传感器输出的是毫伏级模拟电压51单片机内部没有ADC你得先把信号调理和采集通道设计出来Proteus元件库里又根本没有MQ-7、MQ-136这些现成模型仿真时只能找替身DHT11的单总线时序在仿真环境里经常跑不通。所以这个项目从原理图到源代码走的是一条“先搭采集通道、再做传感器仿真替代、最后标定显示”的路线。下面从传感器选型开始把这个方案一步步拆开讲适合正在做51单片机课程设计的人也适合要在Proteus里做多路模拟量采集的工程师参考。2. 传感器选型与原理图设计MQ系列输出的是模拟量不是数字量2.1 六路检测对象和对应的传感器选型先明确检测对象温湿度、H2S、NH3、CH4、CO一共六路信号。温湿度用DHT11单总线数字输出一根线搞定五种气体全部来自MQ系列半导体传感器。选型对照如下检测对象传感器型号输出类型典型量程功耗特点温度/湿度DHT11单总线数字量0-50℃20-90%RH低功耗H2SMQ-136模拟电压1-200ppm加热功耗约0.9WNH3MQ-137模拟电压5-500ppm加热功耗约0.9WCH4MQ-4模拟电压300-10000ppm加热功耗约1WCOMQ-7模拟电压需脉冲加热20-2000ppm高低温循环加热选型理由很直接MQ系列在Proteus仿真里没有模型但在实物制作中最容易买到驱动电路简单一个电阻分压加一个ADC就能读。需要注意MQ-7比较特殊它的加热丝需要高低温交替供电低温1.4V加热60秒、高温5V加热90秒固定5V会带来较大的零点漂移。课程设计里如果不做加热控制测出来的CO浓度只能看趋势不能当绝对值用这一点要在文档里写清楚。2.2 MQ系列传感器信号调理电路的设计要点MQ传感器的经典电路是一个分压结构传感器内部的敏感电阻Rs与负载电阻RL串联RL两端电压就是输出信号。原理图设计时三个参数最容易错。第一加热回路和检测回路必须分开走线。传感器的1、2脚加热丝单独接加热电源3、4脚敏感体接RL分压网络两个回路共地但在PCB上要靠近传感器引脚处汇合避免加热电流脉动干扰取样电压。第二RL的取值决定了输出电压量程。RL越小负载电压越低分辨率越差RL太大传感器分压不足输出容易饱和。MQ系列典型RL取1kΩ到4.7kΩ建议原理图上画成可调电阻调试时先用10k电位器把洁净空气下的输出电压调到0.15V到0.3V之间再换成固定电阻。给一个实用取值表传感器RL推荐值洁净空气下输出电压Vcc5VMQ-1362.2kΩ0.1-0.3VMQ-1371kΩ0.15-0.35VMQ-44.7kΩ0.3-0.6VMQ-71kΩ0.1-0.2V低温和高温段均值第三如果用带LM393比较器的传感器模块输出端是TTL电平只能判断“超没超阈值”读不到连续浓度值。标题要求做空气质量检测、显示浓度所以必须从模块的模拟输出端AO取信号原理图上标识清楚“接ADC通道”。2.3 用CD4051扩展ADC采集通道五个气体通道怎么接51单片机没有内置ADC常见的做法是外接ADC0832但ADC0832只有两个模拟输入通道五个气体传感器不够用。我一般用CD4051做8选1模拟开关把五路传感器输出分时切换到ADC0832的CH0上P1.0到P1.2三个IO口做通道地址选择。CD4051地址C/B/A选通通道接入信号000X0MQ-136H2S001X1MQ-137NH3010X2MQ-4CH4011X3MQ-7CO100X4备用/扩展101X5备用H2S是X0开机默认采这一路方便自检。CD4051的INH禁止脚接地VEE接-5V或直接接地。如果输入信号可能到5VVEE接地时输入范围是0到VDD够用要处理负电压信号才需要负电源。CD4051导通阻抗约80Ω对后级ADC0832的输入阻抗影响不大但在信号线上串一个100Ω电阻加100nF电容做RC滤波能明显降低采样抖动。2.4 DHT11温湿度、LCD1602和报警电路的工程化接线DHT11数据线接P3.7数据线和VCC之间接4.7kΩ上拉电阻连接线尽量短于20cm。LCD1602标准接法RS接P2.5、RW接P2.6、EN接P2.7、D0-D7接P0.0-P0.7P0口必须接10kΩ排阻上拉否则LCD花屏。液晶的VO脚对比度串一个10k电位器到GND这个电位器在仿真里容易被忽略但在实物上不加屏幕经常显示不出字。报警电路用有源蜂鸣器接一个PNP三极管S8550驱动。基极串1kΩ电阻接P2.0发射极接VCC集电极接蜂鸣器负极蜂鸣器正极接VCC。这比直接接IO口靠谱因为蜂鸣器工作电流20mA左右超过单片机IO口安全范围。每路气体阈值对应一个LED指示灯LED串470Ω电阻接P2.1到P2.4哪一路超标就亮哪一盏方便快速定位是哪路气体报警。3. 软件框架与核心代码从主流程到C51源码的落地3.1 主程序流程设计采集、标定、显示、报警四件事主程序不需要操作系统一个while循环加一个定时器中断就够了。流程设计成四步循环第一步切换CD4051通道并延时等待信号稳定第二步读取ADC0832转换结果每一路连续采16次去掉最大最小值再取平均第三步把平均后的AD值换算成浓度并与阈值比较决定继电器或蜂鸣器状态第四步刷新LCD1602显示然后进入下一路采集。整个轮询周期控制在200ms左右按键扫描放在主循环的空闲位置用软件消抖。这个流程里有一个容易写错的细节CD4051切换通道后不能立刻读ADC模拟开关的导通建立时间加上传感器输出端的RC滤波时间常数大概需要5到10ms。如果切换后立刻采样读到的还是上一个通道的残留电压。做法是在切换函数里加一个10ms延时或者把通道切换放在上次显示刷新之前让延时被其他任务吃掉。3.2 ADC0832读取函数与CD4051通道切换代码这是整套源代码里最核心的部分。下面这段C51代码可以直接拷贝进Keil工程芯片选AT89C52或STC89C52都可以。#include reg52.h sbit ADC_CS P1^3; // ADC0832片选低有效 sbit ADC_CLK P1^4; // ADC0832时钟 sbit ADC_DAT P1^5; // ADC0832数据线DI/DO复用 sbit MUX_A P1^0; // CD4051地址位A sbit MUX_B P1^1; // CD4051地址位B sbit MUX_C P1^2; // CD4051地址位C // 读取ADC0832指定通道ch: 0CH0, 1CH1 unsigned char read_adc0832(unsigned char ch) { unsigned char i, dat 0; ADC_CS 0; ADC_CLK 0; ADC_DAT 1; // Start位 ADC_CLK 1; ADC_CLK 0; ADC_DAT 1; // SGL位单通道模式 ADC_CLK 1; ADC_CLK 0; ADC_DAT ch; // 通道选择0或1 ADC_CLK 1; ADC_CLK 0; ADC_DAT 1; // 释放总线之后由DO驱动 for (i 0; i 8; i) { ADC_CLK 1; dat 1; if (ADC_DAT) dat | 0x01; ADC_CLK 0; } ADC_CS 1; return dat; } // 切换CD4051通道并等待输出稳定ch: 0~7 void switch_mux(unsigned char ch) { unsigned char i; MUX_A ch 0x01; MUX_B (ch 1) 0x01; MUX_C (ch 2) 0x01; for (i 0; i 20; i); // 空延时等待稳定 }代码逻辑是先给CD4051三条地址线赋值选通对应传感器通道再启动ADC0832串行转换。ADC0832的数据读取顺序是从最高位开始的串行时钟产生方式是把P1.4拉高再拉低每次上升沿数据线上出现一位数据。DI和DO共用一根线时读取阶段要把P1.5配置成输入模式51的准双向IO口可以直接读不需要切换方向的语句。参数上需要注意三点。第一ADC_CS低电平保持时间不能太短两个转换周期之间至少间隔50μs所以read_adc0832调用频率不要超过5kHz。第二ADC_CLK高低电平时间由空指令延时决定12MHz晶振下约1μs符合ADC0832的时钟上限。第三CD4051延时函数里的空循环是20条指令实际延时约7μs实测够用如果传感器输出端RC滤波电容加得大这里要加到100以上。3.3 气体浓度标定与报警判断AD值怎么变成ppmADC读回来是0到255的数字量对应0到5V电压但用户要看到的是ppm浓度中间隔了一条标定曲线。MQ系列传感器在双对数坐标下传感器电阻Rs与浓度近似线性关系直接用线性公式算会越往高浓度偏差越大。课程设计里没有标准气体常见做法是查表法加线性插值。查表法逻辑预先在原理图上通过电位器模拟几个已知电压点记录对应的AD值和标称浓度做成两个数组。程序里先判断当前AD值落在哪两个标定点之间再做比例插值。这样比用一个固定的拟合公式灵活换传感器批次时只需要改表的数值。// 标定表AD值与对应浓度ppm以MQ-136 H2S为例 unsigned char code adc_table[] { 10, 40, 80, 130, 200 }; unsigned int code ppm_table[] { 0, 5, 30, 80, 160 }; unsigned int calc_ppm(unsigned char adc_val) { unsigned char i; unsigned long ppm; if (adc_val adc_table[0]) return ppm_table[0]; if (adc_val adc_table[4]) return ppm_table[4]; for (i 0; i 4; i) { if (adc_val adc_table[i 1]) { // 线性插值公式 ppm (unsigned long)(ppm_table[i 1] - ppm_table[i]) * (adc_val - adc_table[i]) / (adc_table[i 1] - adc_table[i]); return ppm ppm_table[i]; } } return 0; }插值用的是整数运算先乘后除避免精度丢失。查表法比直接套公式更贴合传感器的实际曲线代价是标定点越多越费ROM五个标定点对大多数气体检测够用。报警判断放在浓度算完之后P2.0蜂鸣器、P2.1到P2.4四个LED对应四路气体哪路浓度大于等于对应阈值就输出低电平点亮蜂鸣器用软件延时做1秒断续鸣叫不要一直长鸣否则现场噪音太吵。3.4 DHT11温湿度采集和显示刷新的两个常见坑DHT11单总线协议是以微妙级延时为基石的51单片机在仿真里延时和实物不一致最常见的问题就是读出来永远是0或255。写采集代码时延时函数要用普通循环不要用NOP因为仿真器的指令周期计算和Keil里看到的周期数一致但不同版本的Proteus对延时精度模拟不一样所以代码里要在读完数据后加一个50ms的采集间隔。// DHT11读数在Proteus里的常见调试点 // 1. 起始信号低电平必须保持18ms以上 // 2. 读每一位时先等IO拉低再等40us后读高电平持续时间 // 3. 仿真不通过时把延时整体乘以1.5或者2试试显示刷新策略也不要每路都刷新LCD1602写一次要几十微秒如果50ms内写六路数据主循环一半时间耗在写屏上。做法是维护一个显示缓冲数组采集完一轮数据后一次性把六路数值格式化字符串写入再调用LCD显示函数。这样按键响应速度会快很多实测按键延时在100ms左右感觉不到卡顿。4. Proteus仿真与排错气体传感器模型怎么搭出来4.1 Proteus里没有MQ传感器用电压源和电位器替代Proteus元件库翻遍了也找不到MQ-136、MQ-137、MQ-4、MQ-7的现成模型这是所有做这个课程设计的人都会卡住的地方。仿真替代方案很成熟用直流电压源加电位器模拟传感器输出电压因为单片机和ADC关心的就是那个0到5V的模拟信号传感器本身只是一个电压源。具体做法是拖一个DC POWER SOURCE用POT-HG或POT-LIN电位器分压电位器滑动端接CD4051的X0到X3输入端。调整电位器阻值比例输出不同电压就等于模拟不同浓度气体环境。电位器的数值换算法输出电压等于VCC乘以电位器比例比如5V供电下要模拟1V就把比例调到20%。这样仿真代码写完后可以通过转动电位器验证ADC采样、浓度换算和报警阈值三个环节。4.2 DHT11元件在不同Proteus版本里的差异DHT11在Proteus 8.9及以上版本自带的库里有模型直接搜DHT11能搜到。坑在旧版本和某些精简版里没有此时替换方案是用DS18B20先验证温度采集流程因为两个器件都是单总线协议代码结构相似。替换时注意三点DS18B20引脚定义和DHT11不同VCC和GND要重新接DS18B20只出温度湿度通道在程序里保留但显示固定值读时序的延时时间要按DS18B20的规范改两个器件严格来说时序不同。仿真原理图里DHT11的数据线要加上拉电阻很多同学在仿真里忘记画这个4.7kΩ上拉导致数据线上没有默认高电平逻辑分析仪看波形全是乱的。4.3 仿真共地、时钟频率和ADC参考电压的坑Proteus仿真最容易出的问题集中在共地上。电压源、传感器模拟源、单片机和LCD1602必须共用一个GND网络如果有两个地网络没有连在一起ADC采集到的电压就是悬浮的读数像抽风一样跳。检查方法是点击右下角的电压探针分别量传感器输出点和ADC输入端两点电压不一致问题肯定出在CD4051和ADC0832之间的连线上。第二个坑是晶振频率。Proteus里双击单片机可以改时钟频率很多人默认是12MHz在跑但代码里延时都是按12MHz调的如果改成了11.0592MHz串口时序会变定时器中断周期也会偏。这个项目里串口只用来看日志11.0592MHz和12MHz都行但LCD和DHT11的延时算法在两种频率下表现不同建议整个仿真和实物统一用12MHz。第三个坑是ADC参考电压。ADC0832的参考电压就是VCC引脚如果仿真里VCC用了5V电压源ADC满量程对应5V但CD4051输入的模拟电压如果超过5VADC读数会饱和到255。仿真时把电位器滑动端电压控制在0到4.5V范围内别接近满量程。4.4 用Proteus虚拟工具验证采集链路的正确性仿真不出来的问题时不要来回来去改代码用虚拟示波器和电压探针定位。接好电路后把电位器调到0V运行程序看LCD显示的H2S浓度是否接近0再调电位器到0.5V看AD值是否在25左右0.5除以5乘以255。如果AD值有变化但浓度显示不对问题在标定表如果AD值根本没变化问题在CD4051地址切换或ADC0832时序。Proteus的虚拟示波器接在ADC_CLK和ADC_DAT引脚上能看到串行数据波形。正常工作时CS拉低后CLK上应该有八个上升沿DAT线上有一位一位跳动的数据。如果CLK没有波形是ADC_CS没有拉低如果DAT不动是DI和DO方向配置错了。这一套检查流程下来10分钟内能定位大多数仿真问题。5. 让检测结果更可信标定、老化与零点漂移处理5.1 没有标准气体用电压等效法做标定记录实验室没有标准气体很正常但不代表不能做定量标定。电压等效法的思路是已知MQ传感器在某个浓度下的输出压大致范围用精密电位器或信号发生器直接输出那个电压让系统记录下对应的AD值建立“电压等效浓度”标定表。这套做法做出来的数据虽然不能直接对标真实ppm但能完整验证软件的量程、分辨率和报警阈值是否合理答辩时能拿出数据和曲线比空口说“传感器太贵没标定”有说服力得多。实际操作步骤在CD4051的X2通道输入端接一个精密电压源从0.2V开始每增加0.3V记录一次液晶显示值做成表格输入电压(V)ADC读数显示浓度(ppm)理论浓度(ppm)0.210000.841651.68231302.41227980发现实测显示值和理论值偏差在10%以内说明标定表建得合理偏差太大就重新调整adc_table和ppm_table不要直接改系数强行拟合。5.2 在代码里预留零点和量程校准入口标定表写死在code区里没问题但实物上每个传感器个体差异明显建议程序里留两个可校准参数零点偏移量zero_offset和满量程修正系数k_scale。每次计算完ppm后做一个线性修正unsigned int corrected_ppm(unsigned int raw_ppm) { // zero_offset: 洁净空气下的零点偏移 // k_scale: 满量程修正系数默认100表示不修正 unsigned long temp; if (raw_ppm zero_offset) temp (unsigned long)(raw_ppm - zero_offset) * k_scale / 100; else temp 0; return (unsigned int)temp; }这两个参数通过按键加P2.5进入校准模式长按按键3秒进入零点校准此时自动读取当前通道值作为零点再按一次进入量程校准用电压源输入标准电压按键调整k_scale直到显示值匹配。这样换传感器时不用改代码重新走一遍校准流程就行。5.3 整机老化与长期运行时的零点漂移控制MQ传感器有个特性刚上电时读数会漂移特别是MQ-7高低温循环交替加热状态下一开始的零点能漂移0.5V以上。程序里要在主循环开始前加一个预热延时常见的做法是把预热计时做进主循环读取次数累计30秒内不显示浓度只显示初始化的WAIT标志。预热期间同时采集零点并取平均值作为零点参考。老化是物理层面的处理。新传感器首次使用前建议通电老化24到48小时让敏感材料表面达到稳定状态。老化期间不要接单片机采集直接用5V电源给加热丝供电即可。稳定后再做电压等效标定标定值才能长期保留。如果发现同一电压下标定值和三天前差距超过15%优先检查传感器的加热电压是否异常而不是急着改标定曲线。本文还有配套的精品资源点击获取