ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

基于STM32的室内空气质量监测与自动换气系统设计

基于STM32的室内空气质量监测与自动换气系统设计 1. 从一颗传感器到一套闭环系统这个项目到底在做什么室内空气质量这件事很多人是搬进新装修的房子之后才开始在意的。甲醛超标、二氧化碳浓度过高、空气闷得让人头晕这些问题不像温度那样直观你很难靠体感判断当前空气到底行不行。所以做一套能实时盯着甲醛、CO2、温湿度并且超标了能自动换气、能报警提醒的小系统就成了单片机方向非常经典、也非常有实用价值的一个综合项目。这个项目的核心思路并不复杂用一颗主控单片机做大脑挂上几路传感器分别采集甲醛、二氧化碳、温度和湿度把数据在屏幕上显示出来同时根据预设的阈值做判断——一旦某项指标越界就驱动继电器去控制换气扇或者点亮警示灯、蜂鸣器提醒。听起来像是传感器加显示屏加继电器的简单堆叠但真正动手做下来你会发现难点根本不在接线而在于多路传感器的时序协调、模拟量传感器的标定、阈值判断的迟滞设计以及整套系统长时间运行的稳定性。我选的主控是 STM32F103C8T6也就是大家常说的最小系统板那颗芯片。选它的理由很实在72MHz 主频、64KB Flash、20KB SRAM资源跑这个项目绰绰有余外设齐全ADC、多个定时器、USART、I2C 都有最关键的是资料多、价格便宜、社区踩坑记录丰富遇到问题基本都能搜到答案。温湿度用 DHT11甲醛用 MQ-138二氧化碳用 MQ-135显示用 LCD1602 或者 OLED执行机构用继电器加换气扇警示用蜂鸣器加 LED。这套组合适合谁参考如果你正在做单片机课程设计、毕业设计或者想找一个能把采集—处理—显示—控制完整链路走一遍的练手项目这个方向非常合适。它不像点个灯那么简单也不至于复杂到劝退属于那种跳一跳够得着的难度。下面我会把整个系统的设计逻辑、选型理由、关键代码思路、标定方法和踩坑经验完整拆开讲尽量让你看完就能自己动手复现。2. 传感器选型背后的取舍为什么是 DHT11、MQ-138、MQ-1352.1 DHT11 的定位够用、便宜但别指望它精准DHT11 是一颗数字式温湿度传感器单总线通信一根数据线就能读出温度和湿度。它的标称精度是温度 ±2℃、湿度 ±5%RH测量范围温度 0~50℃、湿度 20~90%RH。很多人一上来就嫌弃它精度差但你要想清楚这个项目的需求室内空气质量监测温度湿度只是辅助参考用来判断闷不闷潮不潮±2℃ 的误差完全不影响你做换气决策。选 DHT11 而不是 DHT22 或者 SHT30核心原因是成本和上手难度。DHT11 几块钱一颗时序虽然对时间敏感但网上现成的驱动代码一抓一大把HAL 库、标准库、51 的版本都有。DHT22 精度更高但贵一些SHT30 是 I2C 接口、精度最好但价格翻好几倍。对于这个项目DHT11 是性价比最优解。不过 DHT11 有个必须知道的坑它的采样周期不能低于 1 秒最好 2 秒以上读一次。如果你在主循环里疯狂读它会直接返回失败或者给你一堆 0。我一般把它放在定时器里每 2 秒触发一次采集读完之后做一次数据有效性校验连续失败三次才认为传感器异常。2.2 MQ-138 测甲醛模拟量传感器的标定才是真功夫MQ-138 是半导体式气体传感器对甲醛、苯、甲苯等挥发性有机物敏感。它的输出是模拟电压浓度越高输出电压越高负载电阻上的电压。这里有个关键认知MQ 系列传感器输出的不是浓度值而是一个跟浓度相关的电压你必须自己做标定才能换算成有意义的数值。MQ-138 的加热丝需要预热刚上电时读数完全不可信通常要预热 24 小时以上才能稳定至少也要预热几分钟到十几分钟才有参考价值。这一点在演示的时候特别尴尬——你刚上电屏幕上的甲醛数值乱跳评委或者老师一看就觉得你这系统不稳。我的做法是上电后进入预热倒计时状态屏幕上显示传感器预热中请稍候预热时间到了再进入正常监测。这样既符合传感器特性又显得系统设计专业。标定方法上最实用的是两点标定法在已知清洁空气环境下记录一个基准电压比如用干净室外空气或者刚通风完的房间再用已知浓度的标准气体或者对照仪器记录一个高浓度点两点连线得到近似线性关系。没有标准气体怎么办退而求其次用相对变化来判断——把清洁空气的读数当作基准超过基准一定倍数就报警。虽然绝对值不准但趋势判断是可靠的。2.3 MQ-135 测 CO2它其实不是专门的 CO2 传感器这里必须说一个很多人不知道的事实MQ-135 官方定位是空气质量传感器对氨气、苯系物、烟雾、CO2 等多种气体都有响应它并不是专门测 CO2 的。市面上很多CO2 检测项目用 MQ-135其实是把它当作综合空气质量指标来用。那为什么还用 MQ-135因为在低成本方案里真正专门测 CO2 的 NDIR 传感器比如 MH-Z19要几十上百块而 MQ-135 只要几块钱。对于室内空气质量监测这种场景MQ-135 能反映空气污浊程度的整体趋势配合通风控制是够用的。你要在报告或者答辩里说清楚这一点别硬说它是高精度 CO2 传感器那样反而容易被问倒。MQ-135 同样需要预热同样输出模拟电压同样需要标定。它的负载电阻和加热电压会影响灵敏度模块上一般有可调电位器用来调节输出灵敏度。我建议先把电位器调到中间位置然后根据实际环境微调不要一上来就拧到底。2.4 三路传感器共存的干扰问题DHT11 是数字单总线MQ-138 和 MQ-135 是模拟输出理论上互不干扰。但实际布线时要注意MQ 系列传感器加热丝电流较大供电要走单独的粗线并且和模拟信号线分开走否则加热丝的电流波动会耦合到 ADC 采样上导致读数抖动。我吃过这个亏一开始把三路传感器的电源都从最小系统板的 3.3V 排针上取结果 MQ 传感器一加热DHT11 读数就开始飘。后来给 MQ 单独用 5V 供电、单独走线问题就消失了。传感器测量对象接口类型精度/特点预热要求参考价格DHT11温度、湿度单总线数字±2℃ / ±5%RH无需预热低MQ-138甲醛等 VOC模拟电压趋势可靠绝对值需标定需预热低MQ-135综合空气质量/CO2 趋势模拟电压趋势可靠非专用 CO2需预热低3. 硬件架构与关键电路最小系统板怎么把外设都挂上去3.1 整体框图与供电设计整套系统的硬件可以分成四块主控最小系统、传感器采集、人机交互显示按键警示、执行机构继电器换气扇。主控用 STM32F103C8T6 最小系统板它引出了大部分 GPIO 和 ADC 通道接线很方便。供电是第一个要规划好的事。最小系统板一般通过 Micro USB 或者排针输入 5V板载 LDO 转 3.3V 给芯片用。但 MQ 系列传感器需要 5V 加热继电器模块通常也是 5V 驱动所以整个系统最好用一个 5V/2A 的电源适配器统一供电不要指望 USB 口那点电流能带动继电器和加热丝。我实测过用电脑 USB 供电时继电器一吸合单片机就可能复位就是因为电流不够导致电压跌落。供电分配建议这样5V 主电源 → 最小系统板 5V 输入、MQ 传感器 VCC、继电器模块 VCC3.3V板载 LDO 输出→ DHT11、OLED/LCD 逻辑供电所有模块 GND 必须共地这一点新手最容易忘3.2 ADC 通道分配与采样电路STM32F103C8T6 有 10 个外部 ADC 通道PA0~PA7、PB0、PB112 位分辨率。MQ-138 和 MQ-135 各占一个通道比如 PA0 接 MQ-138、PA1 接 MQ-135。MQ 模块的模拟输出直接接到 ADC 引脚即可模块内部已经有负载电阻。这里有个细节STM32 的 ADC 参考电压是 VDDA通常 3.3V而 MQ 模块输出在 5V 供电下可能超过 3.3V。如果直接接超过 3.3V 的部分会损坏引脚或者读数饱和。解决办法有两个一是用电阻分压把 0~5V 降到 0~3.3V二是选那种输出范围本身就在 3.3V 以内的模块。我一般用两个电阻分压比如 10k 和 20k分压比 2:1把 5V 降到 2.5V 以内安全又简单。ADC 采样要做软件滤波。单次采样抖动很大我通常连续采 10 次去掉最大最小各 2 个剩下 6 个求平均这样得到的值稳定得多。这个滤波逻辑放在一个函数里每次读传感器调用一次。3.3 显示、按键与警示电路显示部分LCD1602 是并行接口占引脚多但显示直观OLEDI2C占引脚少、显示效果好。如果引脚紧张优先选 OLED。LCD1602 需要 6 根数据/控制线4 位模式OLED 只要 2 根SCL、SDA。我倾向 OLED因为 I2C 省引脚而且能显示更多信息。按键用 2~3 个就够了一个设置/确认一个加一个减用来调整报警阈值。按键要加消抖硬件上并一个 0.1uF 电容软件上延时 20ms 再确认。警示部分蜂鸣器用有源蜂鸣器给电就响不需要 PWM 驱动LED 用普通发光二极管串限流电阻。蜂鸣器和 LED 建议接在不同的 GPIO 上方便做不同报警级别不同提示比如甲醛超标红灯长鸣CO2 超标黄灯短鸣。3.4 继电器与换气扇控制继电器模块一般有光耦隔离输入端给低电平或高电平触发看模块类型输出端接换气扇。换气扇如果是 220V 交流的继电器输出侧接线一定要断电操作并且做好绝缘。如果只是做演示可以用 5V 或 12V 的小风扇安全得多。继电器控制逻辑要加迟滞不能浓度一到阈值就开、一低于阈值就关那样会在阈值附近疯狂开关继电器寿命很快耗尽。正确做法是设置两个阈值高于上限开启低于下限关闭中间保持当前状态。比如甲醛上限 0.1mg/m³ 开启换气降到 0.06mg/m³ 才关闭。4. 软件设计从裸机主循环到多任务时序协调4.1 主循环架构与定时器节拍这个项目不需要上 RTOS裸机主循环加定时器节拍完全够用。我的架构是SysTick 提供 1ms 基准用一个软件计数器产生不同周期的任务标志主循环里轮询这些标志来执行对应任务。具体任务周期这样分配DHT11 采集每 2000ms 一次MQ 传感器 ADC 采集每 500ms 一次显示刷新每 300ms 一次阈值判断与控制每 500ms 一次按键扫描每 20ms 一次这样分配的理由是DHT11 本身响应慢2 秒一次足够MQ 传感器需要一定响应时间500ms 合理显示刷新太快会闪、太慢会卡300ms 比较舒服按键必须高频扫描才能及时响应。4.2 DHT11 驱动时序是命门DHT11 用单总线协议一次完整读取包括主机拉低至少 18ms 起始信号 → 释放总线 → DHT11 响应 → 连续读出 40 位数据湿度整数小数温度整数小数校验和。整个过程对时序要求严格尤其是读每一位时的电平持续时间判断。用 HAL 库实现时关键点在于起始信号拉低时间要够18ms 以上释放后要切换到输入模式等待 DHT11 拉低响应读位时先等低电平结束再延时约 30us 判断高电平持续时间长于阈值是 1短于阈值是 0// DHT11 读一位的典型逻辑伪代码 uint8_t DHT11_ReadBit(void) { while (DHT11_PIN 0); // 等待低电平结束 delay_us(30); // 延时 30us if (DHT11_PIN 1) { // 仍为高说明是 1 while (DHT11_PIN 1); // 等待高电平结束 return 1; } return 0; // 否则是 0 }踩过的坑如果中断没关读 DHT11 时被中断打断时序就乱了读出来全是 0 或者校验失败。所以读 DHT11 的这段代码里要么关中断要么保证没有其他中断会在这几毫秒内触发。我一般读之前__disable_irq()读完再__enable_irq()。4.3 MQ 传感器 ADC 采集与滑动平均MQ 传感器的 ADC 采集相对简单但滤波要做好。除了前面说的去极值平均我还加了一层滑动平均保存最近 10 次的有效值每次新数据进来就更新窗口输出窗口平均值。这样读数曲线会非常平滑不会出现跳变。#define MQ_WINDOW 10 uint16_t mq_buf[MQ_WINDOW]; uint8_t mq_idx 0; uint16_t MQ_Filter(uint16_t new_val) { mq_buf[mq_idx] new_val; mq_idx (mq_idx 1) % MQ_WINDOW; uint32_t sum 0; for (int i 0; i MQ_WINDOW; i) sum mq_buf[i]; return sum / MQ_WINDOW; }滑动平均的代价是响应变慢但对于空气质量监测这种慢变量完全没问题。4.4 阈值判断、迟滞控制与报警状态机控制逻辑我建议用一个简单的状态机来管理而不是一堆 if-else 堆在一起。状态分三种正常、警告、报警。每个状态下对三路传感器分别判断综合决定输出。迟滞控制的实现给每个指标定义high_threshold和low_threshold。当前处于换气关闭状态时只有超过high_threshold才切到换气开启当前处于换气开启状态时只有低于low_threshold才切回关闭。这样就能避免阈值附近的抖动。报警状态机还要考虑优先级甲醛超标最严重优先报警CO2 次之温湿度异常只做提示不报警。这样设计符合实际使用逻辑。5. 标定与调试让读数从能看变成可信5.1 MQ 传感器的预热与基线记录前面反复强调预热这里给出具体操作流程系统上电进入预热模式屏幕显示倒计时比如 5 分钟预热期间不进行报警判断只采集数据预热结束后取当前读数的平均值作为清洁空气基线后续所有判断都基于当前值相对基线的变化这个基线不是固定的环境变化比如开窗、下雨会让基线漂移。进阶做法是定期自动更新基线在确认空气质量良好的时段比如换气后一段时间缓慢更新基线值。这样系统能自适应环境。5.2 用串口打印做数据可视化调试阶段串口是你的眼睛。把三路传感器的原始值、滤波值、判断结果都通过 USART 打印出来格式化成 CSV然后导入 Excel 或者用串口绘图工具看曲线。我强烈建议在开发阶段保留这个串口输出功能它能帮你快速定位是传感器问题、滤波问题还是逻辑问题。printf(DHT:%d.%dC %d.%d%% MQ138:%d MQ135:%d State:%d\r\n, temp_int, temp_dec, humi_int, humi_dec, mq138_val, mq135_val, state);5.3 常见异常与排查思路现象可能原因排查方法DHT11 读数全 0时序被打断、上拉电阻缺失关中断重试、检查 4.7k 上拉MQ 读数一直满量程分压没做、供电过高万用表量输出脚电压继电器吸合导致复位电源电流不足换大电流电源、加滤波电容显示乱码初始化时序不对、对比度没调检查初始化命令、调电位器数值跳变严重没滤波、电源干扰加滑动平均、分离电源走线6. 那些文档里不会写的实操心得第一个心得先分模块调通再整合。很多人一上来就把所有模块焊在一起结果一出问题根本不知道是哪块。正确做法是先单独调通 DHT11再单独调通 ADC 采集再单独调通显示最后才整合。每调通一个模块就写个测试程序固化下来整合时直接调用。第二个心得给系统加一个恢复出厂设置的按键组合。调试时经常把阈值改乱有个一键恢复能省很多事。实现上就是把阈值参数存在 Flash 里长按某个按键恢复默认值。第三个心得换气扇控制要加最小运行时间。继电器一开一关对风扇电机冲击大我一般设置开启后至少运行 30 秒才允许关闭保护设备也保护继电器。第四个心得外壳和走线决定项目的完成度。同样的电路线走得整齐、装进盒子、屏幕开孔规整看起来就是成品线乱成一团看起来就是实验板。如果是要交作业或者展示花点时间做外壳效果提升非常明显。第五个心得预留扩展接口。比如留一个 USART 排针以后想加 WiFi 模块上传数据、加 SD 卡记录历史都能直接接。这个项目本身是个很好的平台别做死了。整套系统从选型到调通如果每天投入两三个小时大概一周到十天能跑起来。难点集中在传感器标定和时序协调上硬件接线反而是最简单的部分。把预热、滤波、迟滞这三件事做好系统的稳定性和可信度就能上一个台阶这也是这个项目区别于玩具级作品的关键所在。
返回列表