FEATURED · 精选文章

STM32气体监测与应急处置控制系统:从原理图到源码全解析

发布时间 / 2026/9/15 2:13:15
来源 / 创域科博编辑部
栏目 / 资讯中心
STM32气体监测与应急处置控制系统:从原理图到源码全解析 这阵子我一直在折腾一个跟安全相关的嵌入式小项目——STM32机库气体监测与应急处置控制系统。起因特别简单我们那边有个小型停机库平时会放几台作业车辆和一些设备经常有人开着燃油机器进来冬天门窗一关最怕的就是可燃气体和有害气体积聚。市面上现成的气体报警器要么贵要么功能单一串不进自己的管理流程干脆自己用STM32做了一套把监测、报警、应急联动全打通了。现在整套东西已经开源源码加原理图都在仓库里项目编号0739A。这篇文章我就把这套系统的设计思路、硬件原理、软件实现和踩过的坑完整讲一遍想抄作业的可以直接去拉代码想自己改造成别的场景的看完这篇也能少走不少弯路。1. 项目背景与整体设计思路1.1 为什么需要一个“会动手”的气体监测系统先说清楚一个容易被忽略的点普通气体报警器只能“喊”不能“干”。市面上几百块钱的独立式气体报警器检测到超标就响一声然后就没了剩下的事全靠人。但很多机库、仓库、地下车库的实际场景里人未必时刻都在就算人在从听到报警到手动开启排风设备中间隔着的几十秒可能就已经过了最佳处置窗口。我做的这套系统从一开始就不是奔着“替代报警器”去的而是奔着“替代值班员”去的。它要做的事情有三件实时监测连续采集可燃气体主要针对甲烷、丙烷类和一氧化碳浓度同步采集环境温湿度。分级报警浓度低的时候声光提示浓度高的时候触发强报警不同状态用不同颜色和蜂鸣模式区分。自动处置一旦确认危险浓度直接驱动继电器去开排风扇、切断非防爆设备电源同时可以往外送一个开关量信号给上级管理平台。这套逻辑看着不难但真正做起来会发现模拟量采集的稳定性、报警阈值的防抖处理、执行机构的电气隔离每一环都有坑。后面我会逐条拆。1.2 方案选型为什么是STM32F103C8T6主控选型上我基本没犹豫直接用了STM32F103C8T6。这颗芯片在嵌入式开源项目里的地位差不多相当于“表圈里的劳力士”——不是最浮夸的但绝对是最稳的。72MHz主频64KB Flash20KB RAM片内还有3个ADC、多个定时器、I2C、SPI、USART做气体监测这种场景绰绰有余。有人可能会问这项目用个8位单片机比如STC或者AVR不也行吗确实行但我选择STM32有几个实打实的理由ADC精度和稳定性更好。STM32的ADC是12位的配合内部参考电压校准比大部分8位机自带的10位ADC在长期运行中更不容易漂。资源余量大。后续想加WiFi模块、4G模块、触控屏F103C8T6的接口都能接得住不用换平台。生态成熟。Keil、STM32CubeMX、标准外设库、HAL库资料满网都是开源出去别人也好二次开发。另外一点F103C8T6的耐温范围是-40°C到85°C机库这种户外铁皮房夏天暴晒冬天结冰的极端环境芯片本身不会成为短板。传感器组合上我这版用的是MQ-2半导体可燃气体传感器加MQ-7一氧化碳传感器再加一个DHT22做温湿度补偿。后面会详细说这个组合的逻辑。1.3 系统整体架构与工作流程整套系统的硬件拓扑不复杂一句话就能说清传感器采集信号STM32做判断然后驱动声光报警和继电器执行机构。数据流是这样的MQ-2和MQ-7输出的模拟电压先经过信号调理电路送进STM32的ADC引脚。DHT22走单总线协议接一个普通GPIO口。STM32内部对采样值做滑动滤波再把电压换算成气体浓度。浓度值跟设定阈值比较阈值分“预警”和“报警”两级。预警状态LED黄色闪烁蜂鸣器每隔2秒短响一声。报警状态LED红色常亮蜂鸣器连续鸣叫同时继电器1闭合开排风扇继电器2延时3秒后切断非防爆负载。OLED屏实时显示当前浓度、温湿度和运行状态。这套流程里最有价值的就是那个“报警状态下的联动执行”部分。很多DIY气体监测项目只做到报警就结束了我这版把排风和断电逻辑直接嵌进固件里让系统在没人干预的情况下也能完成初期应急处置。2. 硬件设计解析原理图里到底有什么讲究2.1 电源部分三路供电与抗干扰布局原理图里最先要讲也是很多人最容易忽略的是电源。整套系统里存在三种电压外部输入12V、5V传感器供电、3.3VMCU供电。你如果直接把12V怼到传感器或者直接把5V怼到STM32上板子大概率当场冒烟。我的设计方案是两级降压。外部12V进来先经过一个MP1584降压模块输出5V5V这路电分成两条支路一条直接给MQ系列传感器加热丝供电另一条经过AMS1117-3.3再降压一次给STM32和OLED屏用。这里有个很关键的细节MQ系列传感器的加热丝是纯阻性负载电流不算太大但启停瞬间有冲击如果跟MCU共用一条电源轨ADC采出来的数据会被拉得上下乱跳。所以我原理图上把传感器供电和数字供电从AMS1117前面就分开了5V先过一个大容量的电解电容我用了470uF稳住再进传感器数字部分的3.3V直接从电解电容后面通过LC滤波取电。这样做的效果我自己实测ADC波动能从原来的上百个LSB压到十几个LSB以内。电源部分的第二个讲究是反接保护。机库现场接线的多是普通电工师傅正负极接反不是不可能。我在电源入口串了一个SS34肖特基二极管做防反接同时并联了一个TVS管SMBJ15A吸收浪涌。这两个元件成本加起来不到五毛钱但能把板子保下来。2.2 传感器接口电路别把ADC引脚直接怼上去原理图里另一个比较见功夫的地方是传感器接口。很多新手画图的时候习惯把MQ-2或者MQ-7的模拟输出直接连到STM32的PA0、PA1引脚上图是能跑但长期运行稳定性堪忧。为什么因为MQ系列传感器的内阻是会随环境变化的其输出等效阻抗很高而STM32的ADC输入阻抗是有限的高阻抗信号直接进ADC采样瞬间会因为内部采样电容的充电效应把电压拉低读数就会偏小且不稳定。我的做法是每一路传感器输出都加了一级电压跟随器用LM358双运放实现。MQ-2的输出先经过一个10K电位器做灵敏度调节然后进运放跟随再从运放输出端接到STM32的ADC引脚。运放输入阻抗极高不会对传感器信号产生负载效应输出阻抗极低驱动ADC的采样电容绰绰有余。这个改动看着不起眼但对ADC读数的稳定性和重复性提升非常明显。DHT22的接口相对简单数据线直接接GPIO但我加了两个东西一个4.7K上拉电阻一个33欧姆的串联电阻。上拉电阻是协议要求串联电阻是拿来做ESD防护的DHT22这种外置探头通过线缆连接拔插的时候很容易产生静电尖峰有了这个电阻能挡住大多数伤害。2.3 应急执行机构继电器驱动电路的关键设计系统的“应急处置”最终落在继电器上。我选了松乐的SRD-05VDC-SL-C5V继电器触点容量10A 250VAC驱动排风扇这种几百瓦的负载绰绰有余如果以后要断更大的设备可以通过这个继电器再去控制交流接触器。继电器驱动电路有几个绝对不能省的东西三极管驱动。STM32的GPIO输出能力只有几个毫安直接驱动继电器线圈约70mA会烧引脚必须用S8050三极管扩流。续流二极管。继电器线圈在断电瞬间会产生反向电动势电压可能是供电电压的几十倍这个能量如果没地方泄放会顺着三极管或者GPIO打进芯片内部轻则数据错乱重则直接烧芯片。我在线圈两端反向并联了一个1N4148这个二极管平时不工作线圈断电瞬间才导通给反向电流提供一条低阻回路。光耦隔离。继电器控制的是强电负载如果强电部分出故障或者雷击窜扰高压会顺着控制线倒灌进MCU所以驱动信号从STM32出来先经过一个EL357N光耦再做电平转换驱动三极管。光耦两侧的地是分开的继电器侧独立接地。原理图里继电器输出端的走线我也特意加宽了触点引脚周围做了大面积敷铜这样大电流通过时不会因为阻抗过高而发热。2.4 人机交互OLED、按键、声光报警人机交互这部分看着零碎实际上对现场使用的体验影响最大。我的板载了一个0.96寸OLED屏I2C接口SCL和SDA各接10K上拉电阻这是I2C协议的要求不加上拉通信会不稳定。显示内容分三页循环切换第一页显示当前可燃气体浓度和一氧化碳浓度第二页显示温湿度和报警状态第三页显示系统运行时间和阈值设定值。每页停留3秒自动切换也可以通过按键手动翻页。按键一共三个设置键、加键、减键。长按设置键进入阈值调节模式加键和减键用来调整报警阈值。调节后数据实时写入STM32内部Flash里面的一块独立扇区断电不丢失。这个设计是给现场试运行用的气体浓度本底值每个机库都不一样阈值写死在代码里的话换场地就要重新编译固件太不友好了。声光报警用了两个器件一个有源蜂鸣器和一个三色LED灯珠。蜂鸣器用NPN三极管驱动跟继电器电路类似但不加光耦因为蜂鸣器是低压器件不涉及强电隔离。LED用红黄绿三色绿色正常黄色预警红色报警。三色由一个共阳极LED实现三个GPIO引脚分别控制三路颜色。3. 软件实现与源码导读3.1 代码整体结构与工程组织软件这块我放弃了裸机主循环那种写法而是直接上了状态机加时间片调度虽然没有跑RTOS但整个结构清晰得多。源码在仓库里目录结构是这样组织的App/应用层代码包括状态机主循环、报警逻辑、联动控制逻辑。BSP/板级支持包每个外设一个文件包括ADC、DHT22、OLED、蜂鸣器、按键、继电器。Drivers/标准外设库文件这部分是ST官方的基本没动。Middlewares/中间层包括算浓度用的查表工具和滤波算法。User/主函数入口和中断处理。主循环是一个周期10ms的状态机每个状态下只做一件事STATE_MEASURE启动一次ADC转换读传感器原始值。STATE_FILTER把最近10次采样值做滑动平均得到稳定值。STATE_CONVERT通过查表法把电压值换算成浓度百分比或ppm。STATE_JUDGE跟阈值比较得出当前安全等级。STATE_ACTION根据安全等级执行报警和联动动作。STATE_DISPLAY刷新OLED显示。不同状态之间通过一个全局结构体传递数据这个结构体也承担着参数存储的职责。没有用中断去做频繁采样因为气体传感器本身响应速度很慢几十毫秒采一次和几毫秒采一次对最终效果来说差别不大轮询方式反而更容易把数据流理清楚。3.2 ADC采集与软件滤波ADC采集说难不难但想采得“稳”需要几个配合措施。我配置的是ADC1的通道0和通道1对应读MQ-2和MQ-7的信号12位分辨率采样周期设为239.5个时钟周期这是这个芯片上最长的采样时间。为什么要最长的采样时间前面说了内部采样电容要在采样阶段把引脚电压充到跟外部信号一样如果采样时间太短电容还没充满就被断开采集到的电压就会偏低。气体传感器的信号变化本身是缓慢的用最长时间换精度非常划算。软件滤波我用了双层的策略先是限幅滤波把单次采样值与上一次有效值的差值超过200个LSB的样本丢弃防止脉冲干扰然后滑动平均滤波维持一个容量为10的环形缓冲区每次取平均。两层配合下来显示出来的数字基本能稳定到个位数波动不会再有那种一个数字跳来跳去让人心里发毛的情况。浓度换算这块我建了一个查表数组。MQ系列传感器的特性曲线在厂家手册上是双对数坐标下的直线我取了手册上10个典型数据点然后线性插值生成一个1024元素的查找表以ADC值为索引直接取出浓度值。这样做的好处是MCU不用做对数运算速度和精度都有保证。3.3 阈值判断与滞回控制防止报警“抖动”这是软件里最值得说的一块。如果你只是简单地把“浓度大于阈值”作为报警条件在实际现场会遇到一个特别烦人的问题报警之后排风扇开始转空气流动把浓度吹降到阈值以下系统立刻解除报警然后排风扇停了浓度又慢慢升上来再次报警……如此反复蜂鸣器会像抽风一样叫叫停停继电器频繁通断。解决这个问题的标准做法叫滞回控制或者叫施密特触发器逻辑。简单说就是“报警阈值”和“解除阈值”设成两个不同的值中间隔一个区间。我开始报警的浓度是2000ppm但只有当浓度降到1200ppm以下才会解除报警并关闭排风。这800ppm的差值就是滞回区间它避免了系统在临界点附近来回翻转。代码里我还加了一个“确认次数”逻辑。只有当连续5次测量值都超过报警阈值时才真正触发报警目的是滤掉气体在传感器附近的瞬时波动比如有人拿打火机在传感器旁边晃了一下这种瞬态信号不能触发真的应急联动。级报警的时候还会附带一个3秒的断电延时。这个延时是在报警确认后的3秒后才执行强电切断动作给现场人员一个确认和手动处理窗口防止误动作把关键设备给断掉。你想机库里可能在充电、在检修误断电造成的损失有时候比灾害本身还大。3.4 应急处置联动流程联动控制这部分就是真正体现“应急”的地方了。我给它定义了一个清晰的有穷状态机状态的迁移条件在代码里写得非常明确。正常情况下系统处于SAFE状态。一旦进入WARNING状态GPIO控制蜂鸣器以2Hz频率短响黄灯闪烁。OLED屏幕强制切到浓度显示页。系统继续监测如果浓度回落则回到SAFE如果浓度继续上升则跳到DANGER状态。进入DANGER状态继电器1立即吸合启动排风扇。蜂鸣器连续鸣叫红灯常亮。同时启动一个3秒定时器3秒后继电器2吸合切断非防爆插座供电。如果浓度在排风启动后持续下降并跌破解除阈值系统会先断开继电器2恢复供电然后再断开继电器1关闭排风最后回到SAFE状态。这个“先恢复供电、再关排风”的时序是我反复想过的。实际操作中如果排风机关得太早而供电先恢复了万一还有残余气体整个空间依然有风险所以必须让排风多转一会儿把环境彻底置换干净再恢复正常供电。3.5 OLED显示与按键交互实现显示和交互虽然不是什么高深技术但用户体验好不好全看这里。OLED屏我采用的是U8g2库的移植版本字体用中文模式一屏能显示2行中文信息量够用。页面切换的逻辑不复杂我在主循环的STATE_DISPLAY里根据当前安全等级自动决定显示内容正常状态显示所有数据预警状态显示“危险浓度”报警状态显示“立即撤离”。这个设计是为了现场人员一眼就能看到当前系统的判定结论而不是自己去解读数字。按键处理我用了“短按长按”的区分方式。短按切换显示页面长按进入阈值设置界面。整个阈值设置过程不需要计算机现场就能搞定。设置完按一下设置键保存数据会先写入内部Flash缓存区断电重启后自动加载。这里必须提一个坑STM32内部Flash的写入次数是有寿命限制的虽然F103的Flash能扛10万次擦写但如果你在阈值设置界面频繁按保存按键长期下来还是可能磨穿。我的办法是只在退出设置界面时写入一次而不是每次按键都写Flash。4. 常见问题与排查实录4.1 传感器上电预热与标定的几个坑MQ系列传感器有一个比较磨人的特性刚上电的几分钟到十几分钟内输出信号会明显漂移。我的MQ-2在冷态下读数是0.4V左右但通电半小时后会慢慢稳定到0.6V左右。如果你上电就按最终阈值去判断大概率一开机就误报。解决方案是在软件里加了一个“预热标志”。系统判断传感器是否已经稳定依据是连续60秒内ADC读数的变化幅度小于10个LSB。在没有达到这个条件之前系统只显示“预热中”不启动报警逻辑。这样做虽然牺牲了开机后第一分钟的监测能力但换来的是长期运行不误报。标定方面说实话没有标准气体浓度的情况下只能做相对标定。我的思路是找一个空气流通好的开阔环境记录传感器稳定后的基线电压把这个电压对应的浓度作为环境中该气体的本底浓度。然后用打火机放气只放气不打火靠近传感器记录电压跳到最大值时的读数把这组数据作为100%满量程参考点。这样标定出来的系统在定量精度上谈不上多准但对于“有没有超标”这种定性判断完全够用。4.2 继电器吸合瞬间MCU复位的经典问题这个问题在我调试早期出现过现象是每次继电器吸合那一瞬间OLED屏会闪一下或者系统直接重启。根源在于继电器线圈吸合瞬间的电流冲击和触点切换产生的反向电动势通过地线或者电源线串了进来。虽然电路上加了续流二极管但如果PCB布局时候器件位置不好仍然有风险。我最后的解决方法是三层措施叠加把继电器驱动部分放在PCB角落远离MCU和传感器模拟电路。继电器地功率地和MCU地信号地单点连接中间放一个磁珠做隔离。光耦隔离确保两侧地完全物理分开。还有一个操作层面的注意继电器旁边的走线要走短而粗的不要绕远路绕远路就相当于天线干扰出去再耦合回来问题更棘手。4.3 ADC读数漂移的排查过程有一次联调的时候发现MQ-7的ADC读数会慢慢变小从开机到3小时后居然掉了40多个LSB。当时我怀疑是传感器老化后来发现是参考电压的问题。F103C8T6的ADC参考电压用的是VDDA引脚而VDDA在最小系统板上通常是直接从3.3V上接的。芯片内部电路运行发热后3.3V会有一点点跌落参考电压跟着变ADC结果就直接被影响了。解决方式是给VDDA单独加了一路LC滤波从3.3V主电源经过一个10uH电感加一个22uF电容再进VDDA。这样一来VDDA的稳定度大幅提升ADC读数的长时间漂移从40多个LSB降到了5个LSB以内。这个改动我之前一直没当回事后来对比测试才发现影响这么明显。4.4 误报多发的排查思路与处置建议如果你在自己的项目里也遇到了频繁误报建议从下面几个方向排查效率会高很多现象可能原因排查顺序开机就报警传感器未预热完成基线未稳定先看预热逻辑是否生效等待时间是否够长间歇性短促报警阈值设置过低接近本底浓度调高报警阈值加长确认次数继电器动作时报警驱动电路地线干扰到模拟部分检查功率地与信号地是否分开环境温度变化大时报警传感器温漂超出预期增加温湿度补偿或延长滤波器时间常数数值持续偏高但无气味传感器老化或者被污染重新标定必要时更换传感器另外一个经验是MQ系列传感器尽量不要长期通电后又在高浓度的油烟、酒精类环境里泡着。它本质上是一种化学敏感电阻表面吸附了不该吸附的东西之后恢复很慢测出来的数值会长期偏高。机库这种可能停靠燃油设备的地方建议每3到6个月拿到新鲜空气环境里通电老化一次顺便重新标定。我在这个项目的源码注释里也写了这些注意事项。开源出去不是为了让别人拿到就能跑而是希望别人拿到之后能跑得好、跑得稳。5. 开源资料说明与二次开发方向5.1 仓库里都有什么这个项目目前在GitHub和Gitee都有镜像仓库目录跟硬件和软件对应拿到手之后按顺序看就行Hardware/目录下是原理图源文件立创EDA画的可以直接打开导出PDF和BOM和PCB源文件。Firmware/目录下是Keil5工程源码用的是标准外设库不需要额外安装HAL库相关插件。Docs/目录下有一个简单的调试笔记记录了硬件参数调整和标定流程。Release/目录下是编译好的Hex文件手头有板子不想自己编译的话可以直接烧录用。原理图源文件用的是立创EDA专业版格式这个工具免费且国内访问快不像某些国外EDA软件又慢又贵对初学者也友好。5.2 二次开发可以往哪些方向走如果觉得这套系统还不够贴合你自己的场景有几个我认为比较值得做的扩展方向增加无线通信模块。在USART2上挂一个ESP8266或者ATK-MW8266把监测数据通过MQTT协议推到云端或者局域网服务器就能实现手机远程查看。我代码里已经把串口发送部分封装好了留了一个UART_SendData()接口直接用就行。换成工业级气体传感器。如果监测的气体种类不一样比如氨气、硫化氢可以换成对应的电化学传感器模块它们的输出也是模拟电压原理图不用大改只需要调整ADC对应的换算参数。扩展多路探头轮询。目前是单点监测如果机库面积大可以加一个模拟开关或者每个探头配一个小单片机通过RS485总线把多路浓度汇总到主机。F103的USART外设数量能支撑这个扩展。我在源码的结构上特意把硬件驱动和业务逻辑分层了就是为二次开发准备的。改传感器类型换通信协议加控制对象基本不用动主状态机的逻辑。说实话这个项目的原始出发点就是“自己用顺手”开源出来之后倒是收到了不少反馈有人把它接到了自己的鱼缸换水系统上有人改成了粮仓温湿度监测还有人把它用作毕设题目。挺好一个东西能的的确确用在实处比什么都强。如果你也在做一个类似的嵌入式开源项目我的建议是原理图和源码头上来就一起放不要只开源代码。硬件项目的完整价值一定在“软硬结合”那一层只给代码别人很难摸着你的思路走代码和原理图都给齐了这个项目才是真正能被学习和复用的。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻