尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

STM32实验室消防预警系统:传感器采集、状态机与Proteus仿真全开源

发布时间:2026/9/28 19:17:06

资讯中心
01
ARTICLE

STM32实验室消防预警系统:传感器采集、状态机与Proteus仿真全开源

STM32实验室消防预警系统:传感器采集、状态机与Proteus仿真全开源
做嵌入式这些年陆陆续续攒了不少开发板和小模块但真正让我觉得“拿得出手、能直接用、也值得开源”的项目这是头一个。这套实验室消防预警控制系统我整理了完整的STM32工程代码、原理图以及Proteus仿真工程全部公开。核心场景很明确实验室、实训室、小型机房这种人员密度低但用电设备和化学品密集的场所靠人力巡检不可靠但买一套商用消防主机又贵又难二次开发于是自己做一套低成本、可复现、能按实际需求改的预警设备就成了最合适的路径。它的能力说起来不复杂实时监测烟雾浓度、环境温度和火焰信号一旦出现异常就声光报警同时联动继电器打开排风扇或者切断加热设备电源。坏消息是越“看起来简单”的嵌入式项目自来水深。烟雾传感器的标定、状态机的防误报设计、蜂鸣器对ADC采样的干扰每一个都是实打实踩出来的坑。这篇文章把设计思路、原理图细节、关键代码和仿真方法一次讲透适合准备做STM32项目练手的学生也适合想把实验室安防升级一下的工程师直接抄作业。1. 方案设计与核心选型拆解1.1 实验室消防场景的本质需求实验室火灾和普通居民楼火灾有个很大的区别初起阶段往往没有明火先是某个电器过热冒烟或者化学试剂挥发后在角落积聚。这个阶段恰恰是预警的黄金窗口等火焰真的起来普通烟感探头虽然也能报警但留给人员反应和断电处理的时间就很少了。所以这套系统在设计时重点抓三个物理量烟雾浓度覆盖阴燃阶段、温度覆盖过热阶段、火焰红外信号覆盖明火阶段。三路信号独立采集互不依赖任何一路达到阈值都能触发预警同时综合判据又能有效降低单传感器的误报率。部署位置通常选在房间顶部或靠墙的上方因为热空气和烟气都是向上走的。传感器模块用杜邦线外接方便根据现场调整探测位置主控板固定在配电箱附近或者门口LED状态灯和蜂鸣器要保证值班人员一眼能看到听到。这套系统解决的痛点是“无人值守时段”的安全盲区所以报警输出不能只是响一下要有持续的声光提示和可控制的联动动作。1.2 传感器选型与主控定位主控用STM32F103C8T6这是最保守也最不容易出错的方案。它虽然是多年前的产品但Cortex-M3内核、72MHz主频、三个12位ADC、丰富的基本定时器和串口资源处理这三路传感器加一个OLED显示屏绰绰有余而且板子便宜、资料多、下载器兼容性好。有人说用ESP32还能顺便上物联网但项目的定位是稳定可靠的本地预警STM32的逻辑确定性比带WiFi栈的方案高得多功耗也低所以我最终把网络功能留作后期扩展第一版不引入不确定性。传感器选型我走过弯路最初用过单一气体传感器模块后来发现它的响应曲线受温湿度影响很大在实验室这种经常开空调的环境里固定阈值根本没法设。最终确定三种器件传感器型号输出方式检测对象烟雾/可燃气体MQ-2模拟电压0~5V烟雾、液化气、酒精蒸汽温度DS18B20单总线数字环境温度分辨率0.5℃火焰5路红外火焰模块模拟/数字双输出红外火焰光谱MQ-2选它是因为它对烟雾的灵敏度在民用传感器里最均衡而且有成熟的加热驱动电路响应时间在三五秒级别足够预警场景使用。火焰模块的红外接收管能检测到火焰特有的5~10Hz闪烁频率比单纯依赖温度更早发现明火。DS18B20是成熟的单总线方案一根线就能带多个探头成本极低。1.3 阈值体系的初始设定与标定思路阈值不是拍脑袋定的我在代码里分了“预警阈值”和“报警阈值”两档。举例来说实验室正常环境温度夏天可能到35℃冬天十几度所以我的温度预警线设在55℃报警线设在70℃。烟雾方面MQ-2在洁净空气中的输出电压通常在0.3V到0.5V之间我按1.2V作为预警线2.5V作为报警线。但这个数值只是起点每个实验室的体积、通风条件、背景气味都不一样我把阈值全部做成宏定义和可改写配置部署时用串口命令就能临时调整实测稳定后再固化到Flash里。火焰模块因为容易受阳光、白炽灯光干扰我在代码里做的处理是连续检测到3次以上有效红外信号才确认触发而不是单次边沿就拉警报。这套“多档阈值连续确认”的思路是整个系统抗误报的核心后面软件部分会细讲。2. 原理图设计与硬件电路细节2.1 最小系统与下载调试电路原理图的主控部分就是标准的STM32F103C8T6最小系统8MHz无源晶振配两个20pF负载电容接到OSC_IN/OSC_OUTBOOT0和BOOT1各通过10K电阻下拉到地保证从Flash启动NRST引脚用10K上拉到3.3V并接一个104电容再引一个复位按键到地。VDDA、VSSA引脚单独接0.1uF和1uF电容组合去耦这点很关键ADC的参考电压干净程度直接决定采样稳定性。下载调试接口我用的是SWD四线制SWDIO、SWCLK、GND、3.3V比JTAG省引脚而且ST-Link和J-Link都支持。SWDIO和SWCLK上各串一个33欧姆小电阻这个经验是从一次“仿真器连上就烧引脚”的教训里得来的。实际项目中调试接口常常暴露在机箱外工人插拔时静电放电很常见串电阻不是为了滤波是为了限流保护MCU引脚。2.2 传感器输入电路与ADC采样保护MQ-2模块的核心是一个气敏电阻加热电路加一个比较器模块上带电位器可以把数字输出阈值扭到任意位置。我在设计时没有用它的数字输出而是用AO口输出原始模拟电压到STM32的ADC输入引脚PC0。这里有个注意点MQ-2模块供电是5V它的模拟输出范围接近0~5V而STM32的ADC输入范围不能超过3.3V直接接会烧引脚。我的处理方式是在ADC引脚前面用两个电阻分压例如10K和20K串联将最高5V分压到约3.33V再并联一个104电容做低通滤波。分压之后电压对应的浓度换算关系需要在代码里做物理量还原但我们的系统本质上做的是阈值比较所以我会先把输出电压量程校准到“实际MQ-2探头电压”这一层便于后续换算法。温度探头DS18B20的数据线要接一个4.7K上拉电阻到3.3V因为单总线协议要求总线空闲时是高电平设备通过拉低总线来发送数据。火焰传感器模块的输出有模拟和数字两路我同时接了两个引脚数字输出接普通GPIO用于快速判断模拟输出接另一路ADC用于观察信号强度变化。这种双通道设计在实际调试中非常有用能区分是真的检测到火焰还是模块的比较器阈值设置不当。2.3 执行机构驱动与电源树设计蜂鸣器和继电器不能直接用GPIO驱动GPIO的灌电流和拉电流能力最多几十毫安带不动线圈和压电片。蜂鸣器我用了一颗S8050 NPN三极管做开关基极串联1K电阻接PA4蜂鸣器正极接5V、负极接三极管集电极发射极接地同时在蜂鸣器两端反向并联一个1N4148二极管。用有源蜂鸣器时这个二极管容易被忽略但蜂鸣器内部有振荡线圈关断瞬间会产生反向电动势不加续流二极管容易把三极管击穿或者产生干扰脉冲影响ADC采样。继电器部分直接买的是5V低电平触发模块模块上自带光耦隔离和驱动三极管但我在模块前级仍然加了ULN2003驱动级。ULN2003内部是达林顿管阵列每路能灌500mA电流而且自带续流二极管驱动多个继电器也轻松。实验室应用里我留了两路继电器输出一路控制排风扇一路控制加热设备电源通断。电源树是5V从USB或者适配器进来AMS1117-3.3稳压出3.3V给MCU、OLED和DS18B20。5V直接给MQ-2加热丝、蜂鸣器、继电器模块。这样分配的原因是MQ-2的加热电流有150mA左右如果从3.3V取电AMS1117的压力和发热都太大。3. 软件架构与关键代码实现3.1 工程模块划分与初始化流程工程用STM32CubeMX生成HAL库框架但我不是把所有逻辑都写进main.c。目录结构按功能拆成独立模块每个模块一个.c和.hCore/ 系统时钟、中断 BSP/ 板级外设OLED、蜂鸣器、继电器 App/ 应用逻辑传感器采集、消防状态机、阈值管理 Driver/ 传感器驱动DS18B20、MQ-2、火焰模块初始化顺序是固定套路先HAL_Init和SystemClock_Config然后初始化ADC、I2C、串口、GPIO再初始化传感器最后进入主循环。这里有个容易被新手忽略的点OLED上电后默认可能有残留内容要在初始化末尾主动清屏否则第一帧画面会出现乱码。主循环不要写成一个大while里堆代码。我用了一个轻量级的调度方式通过SysTick产生1ms基准时钟用非阻塞延时和标志位来执行不同频率的任务while (1) { if (tick_1ms - last_sensor_tick 200) { // 200ms采集一次 Sensor_Collect(); Alarm_Task(); last_sensor_tick tick_1ms; } if (tick_1ms - last_display_tick 500) { // 500ms刷新屏 OLED_ShowStatus(); last_display_tick tick_1ms; } }这样做的核心原因是报警逻辑不能被阻塞如果某个传感器读取卡了几百毫秒蜂鸣器响起来都会变含糊。3.2 多路ADC采集与滤波处理STM32F103的ADC一次采样的值抖动很厉害尤其是MQ-2的模拟信号还叠加了加热丝的周期性温度波动。我做了两重处理先连续采样12次排序后去掉最大和最小再取平均这是中值平均滤波能干掉开关电源带来的毛刺。然后对得到的平均值再做一次一阶低通滤波float alpha 0.2f; smoke_filtered (1.0f - alpha) * smoke_filtered alpha * smoke_raw;这种方式不占太多内存响应也跟得上烟雾的逐渐累积。要注意的是alpha取值不能太大否则报警反应太慢也不能太小否则系统一直抖。实测下来0.15到0.25是个合理区间。温度因为DS18B20本身是12位ADC量化过的数字信号不需要做那么重的滤波但我会在解析数据时做一次CRC校验校验失败就直接丢弃本次读数连续失败三次就显示“温度数据异常”。采集程序的另一个细节是ADC的转换模式最好设置成DMA循环采集而不是每次调用阻塞式读取。阻塞式读取在等待转换完成期间会占用CPU时间导致主循环的调度节拍漂移多个传感器轮流采集时延迟会叠加。3.3 基于有限状态机的消防判定逻辑状态机是这套软件里最重要的设计。用简单的if堆判断条件一旦条件多了就会乱所以我用了一个标准的有限状态机包含三个状态空闲态、预警态、报警态。typedef enum { STATE_IDLE 0, STATE_WARN, STATE_ALARM } AlarmState; AlarmState g_state STATE_IDLE; void Alarm_Task(void) { switch (g_state) { case STATE_IDLE: if (Sensor_HitThreshold(LEVEL_WARN)) { g_state STATE_WARN; Buzzer_OnSlow(); // 每2秒短鸣一声 Relay_TurnOn(RELAY_FAN); OLED_ShowWarn(); } break; case STATE_WARN: if (Sensor_HitThreshold(LEVEL_ALARM)) { g_state STATE_ALARM; Buzzer_OnEmergency(); // 连续鸣叫 Relay_TurnOn(RELAY_FAN); Relay_TurnOn(RELAY_CUT_POWER); OLED_ShowAlarm(); } if (!Sensor_HitThreshold(LEVEL_WARN)) { g_state STATE_IDLE; Buzzer_Off(); Relay_TurnOff(RELAY_FAN | RELAY_CUT_POWER); OLED_ShowIdle(); } break; case STATE_ALARM: if (!Sensor_HitThreshold(LEVEL_WARN)) { g_state STATE_WARN; // 降级到预警 } break; } }这个状态迁移规则里最重要的不是报警本身而是“自动降级”的条件。如果状态从报警回到空闲必须经过预警态不能直接从报警跳到空闲这是为了防止传感器信号在临界点反复横跳时蜂鸣器一停一响。Sensor_HitThreshold()内部做的事情是“连续N次超过阈值”。我对烟雾和火焰采用连续3次确认对应大约600ms的确认时间可以过滤掉绝大部分短路冲脉冲温度因为变化慢采用连续5次确认对应约1秒防止瞬时热浪误报。这两个次数参数是调出来的不是从网上抄的你可以根据现场情况调整。3.4 OLED显示与串口调试输出显示用的0.96寸OLEDSSD1306控制器I2C接口。我踩过一次坑以后决定用软件模拟I2C而不是STM32F103的硬件I2C外设。F103的硬件I2C在早期固件库版本中确实存在仲裁丢失之类的兼容性问题网上吐槽一大片虽然新版本HAL库有所改善但软件模拟I2C的可靠性在这个场景下完全够用而且换引脚非常方便不用去管I2C外设的AF映射。SSD1306的7个初始化命令组和写显存的流程是固定的这部分网上有很多现成库我只是把字库缩小到只保留ASCII字符腾出Flash空间。串口调试输出是另一个重要出口。我用USART2的DMA发送配合一个简单的printf重定向每秒钟输出一帧调试信息当前三路传感器的原始值、滤波值、计算出的物理量、当前状态机状态。串口打印在实物调试时几乎必不可少日志数据比OLED屏幕展示的内容更详尽。有一个使用技巧开发阶段建议把采样周期设成100ms方便观察波形变化但现场运行版本要设成500ms减少串口数据刷屏和OLED刷新闪烁。4. Proteus仿真搭建与验证过程4.1 仿真工程的元件布置与时钟配置Proteus仿真部分是本项目的一个重要组成部分因为很多人想验证逻辑但手头没有实物和传感器。我用的仿真环境是Proteus 8.15元件库里的STM32F103C8T6模型是完全可用的。搭建仿真工程时有个关键步骤给MCU模型配置时钟属性。我在这上面耗了一晚上原因是Proteus里的晶振模型不一定能正常起振配合PLL倍频仿真程序经常卡在SystemClock_Config里。最后采用的办法是准备一套仿真专用的工程配置在Keil的条件编译宏里加上SIMULATIONCubeMX初始化时选择HSI内部时钟系统主频定为8MHz编译出来的HEX专门给Protues用。功能逻辑完全一致只是主频和实际硬件不同。这套“实物版和仿真版共用代码、靠宏切换时钟配置”的做法算是仿真开发的一个通用方案。仿真原理图要放置的元件不多STM32F103C8T6、两个电位器模拟烟雾和火焰模拟电压、两个按钮模拟火焰数字信号、红绿黄三个LED、一个SOUNDER蜂鸣器、一个虚拟串口终端。OLED在仿真里可以选择LCD模型代替因为SSD1306的显示逻辑和LCD的字符显示逻辑在状态指示验证层面是等价的。4.2 用电压信号模拟烟雾浓度的测试方法仿真里没有真正的MQ-2模型我的做法是将电位器的分压输出直接连接到ADC输入引脚PC0通过滑动电位器改变电压模拟烟雾浓度从低到高的过程。测试用例是这样的先在实物环境里量一下MQ-2在洁净空气下的输出电压大约是0.4V对应ADC采集值约为500。在仿真里将电位器调到0.4V确认系统处于空闲态然后快速旋转电位器到1.2V观察黄色LED亮起、蜂鸣器开始慢速鸣叫、OLED显示预警状态。再继续调到2.5V以上红色LED亮起、蜂鸣器连续鸣叫、继电器输出标志位置位。整个过程用虚拟示波器抓ADC输入电压和GPIO输出逻辑能清楚看到状态机跳变时刻和阈值设置是否一致。火焰模块的仿真我用了按钮来模拟火焰模块数字输出是低电平有效平时按键松开是高电平按下变低电平代表探测到火焰。连按三次间隔较长的按键确认不会被误触发快速连续按三次确认进入报警态。这些用例覆盖了状态机的核心路径也暴露了我在初版代码里一个重要的逻辑缺陷火焰信号在预警态变成低电平后状态机直接跳变到报警态的前提是对火焰的连续确认次数更新不够及时经过仿真反复测试才修正了这个时序问题。4.3 仿真与实物的差异及处理策略仿真能验证逻辑和时序但不能验证模拟电路的很多真实特性。最典型的差异有三个一是仿真中不会出现ADC采样毛刺而实物中电机启停、继电器吸合瞬间电源波动会直接反映到采样值上二是仿真中DS18B20的时序是理想化的而实物中导线分布电容会拉缓单总线的上升沿导致读时序临界失败三是仿真中蜂鸣器和继电器没有真实的线圈感性负载不会产生反向电动势。这些差异意味着仿真通过只是第一步实物测试才是最终标准。我做实物调试时给这套系统加了一块自制的“电源隔离小板”将传感器供电和继电器供电从同一路5V分成两路中间串磁珠和1000uF电解电容ADC采样值在继电器动作时的波动从几百个ADC位数下降到几十个位数以内这个处理方案在后面问题排查章节会详细说。5. 常见问题排查与避坑实录5.1 上电误报传感器预热与基线校准MQ-2传感器内部有加热丝上电后需要时间把气敏电阻加热到工作温度这个过程通常要三到五分钟。加热过程中传感器输出电压会从零开始爬升很容易在一两分钟内冲到阈值以上导致系统一通电就报警。这个误报几乎是所有使用MQ-2的项目都会遇到的。我的处理方法是软件里设置一个“预热窗口”上电后的前180秒内只采集数据不判断报警同时记录这段窗口内的平均输出作为基线。到达180秒后将实时值与基线比较超过阈值的差值才算有效触发。相对阈值判断比绝对阈值判断要稳健得多因为每次上电基线都会被重新校准传感器老化也不会影响判断逻辑。这个方案在实物换过两个批次的MQ-2模块之后验证下来很有效老模块和新模块都能一致工作。5.2 ADC跳变与蜂鸣器干扰的处理调试时遇到过一个最恼火的现象蜂鸣器一响OLED屏幕亮度就开始闪ADC采样值同步大幅跳动严重的时候系统直接复位。排查过程从波形抓起用示波器夹在3.3V电源轨上发现蜂鸣器启动瞬间3.3V轨上出现了一个约600mV的跌落同时叠加了高频振铃。这个问题的根源是蜂鸣器直接从3.3V电源取电电流冲击直接作用于MCU电源。解决方法是把蜂鸣器的供电从3.3V改到5V因为5V输入进来后尚未经过LDO瞬态电流的缓冲余地更大同时给蜂鸣器电源脚加了一个100uF电容和一个104陶瓷电容作为低阻抗储能。改完之后电源跌落减小到150mV以内AD值波动恢复正常。这件事给我最大的教训是电路的电源完整性设计比代码滤波重要得多软件滤波只是补救手段不是根治方法。5.3 DS18B20读取失败与单总线时序DS18B20的时序非常敏感每次读取要经历初始化复位脉冲、ROM命令、功能命令三个阶段每个阶段都有精确的微秒级时间窗口。在一版固件中我在读取DS18B20的同时使能了串口中断结果偶发读取错误返回值是著名的0x8585这个值就代表复位时序错误。根治方法有两层第一层是读取过程要保证不被高优先级中断打扰我用临界区保护了整个读取流程第二层是增加软件上的校验和重试机制连续失败三次后显示“温度异常”而不是把错误数据送进状态机。这两层保障做好后DS18B20的读取成功率能从95%提升到99.9%以上。另外要注意的是DS18B20的数据线不宜过长超过1米就必须使用屏蔽线或者降低上拉电阻。我之前试过用3米长的普通杜邦线连接探头读取完全失败换成双绞屏蔽线并接2.2K上拉后恢复正常。5.4 常见问题速查表现象可能原因处理办法上电持续报警MQ-2预热漂移启用预热窗口改用相对基线判断蜂鸣器响时ADC跳变电源共用、LDO选型不当蜂鸣器改5V供电增加储能电容DS18B20返回0x85中断打扰、导线过长临界区保护读取缩短走线或加屏蔽火焰传感器频繁误报日光/白炽灯干扰调整安装角度加装滤光片连续确认过滤OLED屏花屏I2C时序不稳定改软件模拟I2C降低I2C时钟频率继电器吸合后系统复位继电器线圈反电动势确保续流二极管方向正确光耦隔离串口打印乱码主频配置与实际晶振不符检查SystemClock_Config仿真与实物分开编译预警状态无法自动恢复状态机降级条件缺失增加报警态到预警态的降级路径做完这套系统再回头复盘最深的体会是嵌入式项目的复杂度从来不在某一个点上而是藏在模块之间的边界处。传感器、电源、状态机、仿真每一块单独拆开都有标准答案但串在一起之后边界上的“杂质”全靠一遍遍实测去清理。我这次开源的内容里代码可以直接编译烧录原理图可以直接打样仿真工程可以完整运行但更希望你把它当成一个骨架传感器型号、阈值参数、报警动作都可以换成你自己场景里的配置。后续如果要扩展往里面加WiFi模块做远程报警推送或者接入RS485总线汇入实验室门禁系统都是顺理成章的事套用这套状态机框架也不会动到核心逻辑。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。