ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于STM32的实验室消防预警控制系统设计与仿真

基于STM32的实验室消防预警控制系统设计与仿真 实验室里的烟雾报警器十有八九就是个摆设。这不是瞎说——我在实验室泡了好几年见过太多报警器被塑料袋罩住防误报、又或者电池没电自己都不吭声的情况。真要遇到电线短路烧糊、试剂挥发冒烟这种突发事件能不能可靠地叫醒人全靠缘分。所以我一直琢磨用STM32自己搞一套实验室消防预警控制系统带传感器、带声光报警、带排风联动再配上简单的状态显示成本不过百来块钱却比很多成品误报率还低。这个项目目前已经整理成开源工程包含完整的代码、原理图和Proteus仿真这篇就把整个设计思路、关键细节和踩坑过程都写出来。先说清楚这套东西能干什么实时监测烟雾浓度和温度有两级预警逻辑烟雾浓度超标自动开启排风扇同时蜂鸣器报警、红色LED闪烁如果温度也飙升到危险值直接进入强报警状态。平时OLED屏上能看到当前烟雾值、温度和系统工作状态串口还能输出调试日志。整套系统用STM32F103C8T6做主控性价比很高适合课程设计、实验室安全管理也适合刚学完单片机想练手的嵌入式爱好者。下面从方案选型开始把原理图、代码、仿真三条线完整拆开讲。1. 项目整体方案与硬件选型思路1.1 为什么用STM32而不是8位单片机这套系统最核心的需求是同时采集多路传感器信号 执行多路输出控制这和传统51单片机的经典应用场景确实有重叠。我选STM32F103C8T6主要是从三个角度考虑的。第一是ADC资源。消防预警要同时盯烟雾浓度和火焰红外信号51单片机很多型号没有ADC或者只有8位精度还得外挂ADC芯片布线和代码都麻烦。STM32F103C8T6自带两个12位ADC通道足够采样精度对传感器来说绰绰有余软件上还能做滤波处理。第二是扩展性。实际做下来你会发现光是烟雾和温度还不够想加WiFi远程报警、加CAN总线组网、加LCD显示屏51的引脚和外设很容易到瓶颈。STM32的USART、I2C、SPI、定时器PWM都是现成的后续想加什么模块基本不用换主控。我用CubeMX配置外设生成HAL库工程整个初始化代码都是自动生成的写业务逻辑的时间占了八成以上。第三是调试体验。STM32支持SWD调试Keil里直接打断点看变量传感器数值、状态机变化都能实时观察。这在调报警阈值的时候特别重要——你要知道当前烟雾值到底是多少而不是靠猜。51那种串口打印、没有调试器的老流程调这种多状态系统会痛苦得多。1.2 传感器选型和取舍传感器是整个系统的眼睛选错比写错代码更致命。我在这套系统里用了三个传感器各有分工。烟雾浓度用的是MQ-2这是国产项目里最常见的廉价烟雾传感器对液化气、丁烷、烟雾都有响应模块自带一个模拟电压输出和一个比较器数字输出。我用的就是它的模拟输出接STM32的ADC。MQ-2的灵敏度可以靠模块上的电位器调这个很实用不同实验室环境对烟雾浓度的敏感度不一样调一下就行了。需要注意的一点是模块如果接5V供电模拟输出范围能达到0-5V直接怼到STM32的ADC引脚上会烧芯片。我把模块的VCC接到了3.3V上输出范围就变成了0-3.3V完美匹配片内ADC的量程。代价是灵敏度会稍微降一点点但消防预警这种场景不缺那一点灵敏度。温度和湿度探测用的DHT11。这是一颗数字传感器单总线协议只用一个IO口就能读回温度和湿度成本几块钱。精度是±2℃做消防预警足够用了又不是做体温计。选择DHT11而不是DS18B20的原因很简单DS18B20只能测温DHT11连湿度一起读了实验室里高湿度环境也容易引发设备凝露风险多一个湿度数据聊胜于无。这个传感器有个脾气读取间隔必须大于1秒连续读会返回超时代码里要做防超时处理。火焰传感器是用来辅助检测明火的用的是红外光敏二极管对760nm到1100nm波长的火焰光谱敏感模拟输出一个与红外强度相关的电压。老实说火焰传感器在实验室这种环境误报率偏高阳光、白炽灯、电烙铁发热都会影响它。我把它当成一个辅助证据而不是判据也就是说烟雾和温度没达到预警值之前火焰传感器的信号不会触发报警只有当另外两个条件也异常时它才参与综合判断。这样既保留了感知明火的能力又不会因为阳光晃了一下就鬼叫。1.3 系统工作流程设计整个系统运行起来是这样一个流程开机后STM32先做ADC自校准、串口初始化、OLED显示初始化然后进入一个持续约3分钟的传感器预热期。MQ-2这种气敏传感器刚上电时电阻会剧烈变化如果开机立刻投入判断大概率会误报。我在OLED上显示Calibrating...同时采集50次烟雾值取最小值作为洁净基准预热结束才开始正常的轮询判断。正常工作状态下系统以200ms为周期读一次烟雾值以2秒为周期读一次DHT11数据把数据显示在OLED上。一旦烟雾值超过一级阈值系统进入预警状态排风扇开启、红色LED开始闪烁、蜂鸣器以间歇模式响OLED切换到预警界面显示当前烟雾值。如果烟继续烧烟雾值突破二级阈值或者温度超过报警值系统升级到强报警状态蜂鸣器长鸣、指示灯常亮、串口输出紧急报警日志。预警状态在烟雾回落到阈值以下后自动恢复强报警状态则增加了迟滞逻辑必须明显下降到安全区间才解除防止传感器在临界点抖动导致继电器反复吸合。这套流程从顶层就分成了采集、判断、执行三条线代码也按这个结构来组织后面写状态机的时候会发现特别顺畅。2. 原理图设计每一路IO都要想清楚再画2.1 最小系统与引脚分配STM32F103C8T6是LQFP48封装引脚不多但分配好了就很够用。我整套系统的引脚分配如下引脚功能说明PA0MQ-2模拟输出ADC1通道0检测烟雾浓度PA1火焰传感器模拟输出ADC1通道1检测红外火焰PA2DHT11数据线单总线协议开漏输出外部上拉PB0蜂鸣器控制PWM输出兼容有源/无源蜂鸣器PB1排风扇继电器高电平触发继电器PB5红色报警LED高电平点亮PB6I2C1_SCLOLED屏幕时钟PB7I2C1_SDAOLED屏幕数据PA9/PA10USART1 TX/RX串口调试日志NRST复位按键外部RC复位最小系统部分3.3V电源我用AMS1117把外接的5V降压下来输入输出两侧各配一个10uF钽电容和一个0.1uF陶瓷电容去耦。8MHz外部晶振配上两颗20pF负载电容给HSE提供时钟源。BOOT0直接下拉到GND让芯片从Flash启动。复位电路用了经典的10k上拉电阻加0.1uF电容再串联一个按键按下拉低NRST复位。这个部分没啥特殊设计但每次画板都必须核对一遍尤其是BOOT0和复位电路容易抄错。2.2 传感器接口电路的三个关键细节传感器接口电路看着简单实际踩坑不少。MQ-2模块的模拟输出走一根线就直接到PA0了但我在PA0上额外加了一个0.1uF对地电容和一个10k下拉电阻。原因很直接MQ-2的模拟输出内阻偏大抗干扰能力弱加上这个RC滤波能让ADC采样值稳定不少。实测不加电容时ADC读数的跳动范围能达到±80加完电容以后能压到±20以内。DHT11的数据引脚一定不能直接推挽输出。DHT11是单总线协议数据线主机要能拉低也能释放读取从机拉低所以STM32这边的GPIO要配置成开漏输出模式外部接一颗4.7k上拉电阻到3.3V。如果配成推挽输出读数据的时候会跟从机的拉低产生冲突读回来的数据全是乱的。这是DHT11电路最常见的错误画完原理图一定要回头检查这个引脚的配置。火焰传感器的模拟输出跟MQ-2一样直接接PA1同样加上0.1uF滤波电容。这个传感器对方向性非常敏感探头正前方是检测区域画PCB的时候要给模块留出朝外安装的位置。我第一版把火焰传感器贴在板子中间结果被旁边的LED指示灯干扰得根本没法用后来才挪到板子边缘。2.3 声光报警与继电器驱动电路蜂鸣器这块我一开始直接用一个IO口接有源蜂鸣器模块高电平触发。后来发现实验室实际使用中有可能换无源蜂鸣器就改成了三极管驱动方案PB0输出到S8050三极管的基极集电极驱动蜂鸣器发射极接地基极串一颗1k限流电阻。这样无论有源蜂鸣器还是无源蜂鸣器都能驱动软件上用PWM输出就能发声。有源蜂鸣器内部自带振荡器高电平就响无源蜂鸣器要靠PWM方波才能响。代码里我把PB0配置成定时器PWM输出有源蜂鸣器就输出50%占空比无源蜂鸣器就直接输出4kHz的方波一套代码兼容两种硬件。排风扇继电器是另一个容易翻车的点。继电器线圈是个大电感三极管关断瞬间会产生反向电动势如果不处理直接就把三极管击穿了。正确做法是在线圈两端反向并联一颗1N4007续流二极管正极接三极管的集电极侧负极接正电源。这样断电瞬间反向电流通过二极管泄放保护三极管。基极电阻我用了1k配合S8050的放大倍数能保证继电器在低电平IO输出时也可靠吸合。注意如果继电器型号是5V线圈的S8050的集电极供电必须接5V不能接3.3V否则线圈电压不足吸合不牢。2.4 画原理图时的几条实操心得用立创EDA或者Altium Designer画这套图都行。我的建议是给每个功能模块画一个独立的分块电源、主控、传感器、输出执行分开再用网络标号连接而不是把所有连线都拉成蜘蛛网。后期维护的时候哪个模块有问题一眼就能定位。电源去耦是我画完第一版之后补上的关键改动。每个IC的VCC引脚旁边都放一颗0.1uF陶瓷电容电源输入端放电解电容这是MCU电路稳定运行的基本保证。STM32对电源纹波不算特别敏感但ADC采样对电源噪声非常敏感去耦电容一加ADC的数值稳定性肉眼可见地提升。原理图里我还特意标了一颗系统状态彩色LED绿色LED表示正常工作红色LED表示报警。这两颗LED各串一个330Ω限流电阻直接由GPIO驱动不需要三极管。选电阻阻值的时候算一下3.3V供电减去LED压降约1.8V剩下1.5V加在330Ω上电流约4.5mA亮度足够又不会烧LED。3. 代码实现状态机让预警逻辑清晰不打架3.1 开发环境和工程结构这套系统的软件我用Keil MDK5 STM32CubeMX生成HAL库工程。CubeMX配置清单大概是RCC选择外部晶振HSE时钟树设定PLL倍频到72MHzADC1开启两个通道扫描模式采样时间55.5周期TIM2配置一个PWM通道输出到PB0I2C1配置成标准模式100kHzUSART1配置115200 8N1PA2配置为开漏输出PB5和LED引脚配置为推挽输出。第一次用Keil MDK5的时候记得先把STM32F1系列的芯片包装上不然工程里找不到芯片型号。新版包可以通过Keil官网或者Pack Installer在线装过程很简单。如果你电脑上还装了C51的Keil注意Keil MDK5和C51的安装目录最好分开不要装在同一个路径下不然两个工具链会互相干扰。工程文件组织成下面这样逻辑清晰也方便开源给别人看/Firmware /Core // CubeMX生成的初始化代码 main.c adc.c gpio.c i2c.c tim.c usart.c /Drivers /BSP sensor_mq2.c // 烟雾采集与滤波 dht11.c // DHT11单总线时序 oled.c // OLED显示 /App alarm_state.c // 预警状态机CubeMX生成的代码是基础业务逻辑都放在App目录里这样固件升级或者换外设时不用动底层初始化代码。3.2 ADC采样与软件滤波烟雾和火焰两个传感器接在ADC1的通道0和通道1上。HAL库的ADC用起来有两种姿势一种是用HAL_ADC_Start_DMA开启DMA自动搬运一种是用HAL_ADC_Start加HAL_ADC_PollForConversion阻塞轮询。我这个系统轮询周期200ms采样频率不高用阻塞轮询就够还省得调DMA配置。滤波我用了两层。第一层是中值滤波每次读10个采样点排序后取中间的那一个值这能把毛刺尖峰干掉。第二层是滑动平均新值 上次值 * 0.7 本次采样值 * 0.3相当于一阶低通滤波让曲线变得平滑。这套组合实测下来比传统的纯平均值滤波响应速度更快又不至于因为单次异常跳到报警状态。ADC采样的代码去掉了CubeMX的复杂写法我自己写了个封装函数uint16_t ADC_FilteredValue(ADC_HandleTypeDef *hadc, uint32_t channel) { uint16_t buf[10]; uint16_t mid; for (int i 0; i 10; i) { buf[i] ReadADC(hadc, channel); // 启动转换并等待完成 } // 简单选择排序取中位数 for (int i 0; i 9; i) { for (int j i 1; j 10; j) { if (buf[j] buf[i]) { uint16_t tmp buf[i]; buf[i] buf[j]; buf[j] tmp; } } } mid buf[4]; // 10个数的第5个作为中值 // 滑动平均0.7旧值 0.3新值 static uint16_t filterBuf 0; if (filterBuf 0) filterBuf mid; filterBuf (uint16_t)(filterBuf * 0.7f mid * 0.3f); return filterBuf; }3.3 DHT11时序解析与仿真替代方案DHT11的单总线时序是典型的需要看时序图才能写的代码。具体流程是这样主机先把数据线拉低至少18毫秒发起起始信号然后释放总线DHT11会在30us左右拉低响应信号80us接着开始输出40位数据每位数据都以50us低电平开始然后高电平持续时间代表数据26到28us的高电平表示070us左右的高电平表示1。判断方式就是测量高电平宽度。代码实现的时候我直接用DWT循环计数器做微秒延时避免HAL_Delay在中断里失准的坑。读取每一位的时候等电平拉低再计时高电平时间超过40us就算1没超过就算0。读完40位以后前32位是湿度和温度的整数小数部分最后8位是校验和校验通过才认为数据有效。DHT11有个脾气读取间隔必须大于1秒。我代码里用一个简单的定时计数来控制每次读操作之间至少间隔1.5秒否则DHT11就不回复了返回超时错误。这个错误要能容忍不能因为一次读超时就触发报警状态。Proteus仿真软件里没有DHT11的模型这是个现实问题。我的处理方式是在代码里加一个SIMULATION宏仿真版固件里把温度直接定义成一个可在串口终端模拟设置的全局变量DHT11的相关代码全部用宏包起来跳过。这样实物固件和仿真固件是同一份源文件编译出来的只是宏定义不同不会出现仿真验证了假逻辑、实物跑真逻辑的脱节。温度模拟就用串口发指令比如输入T70就把温度变量设为70可以测试高温报警逻辑。3.4 预警状态机的设计思路预警逻辑是整套系统的核心我用的是一个简单的三态状态机状态已经在上文定义了。为什么必须用状态机而不是一堆if-else因为报警逻辑里存在一个迟滞需求烟雾值到2050要触发报警但回落到1800就要解除报警中间留了250的迟滞区间防止传感器在临界点轻微抖动导致蜂鸣器和继电器不停地开关。用if-else写得把上升触发和下降复位分散到两个条件里很容易逻辑混乱。状态机把每个状态下的转移条件集中在一起可维护性高得多。状态机的核心代码如下typedef enum { STATE_NORMAL 0, STATE_WARNING 1, STATE_ALARM 2 } AlarmState; AlarmState Alarm_Run(uint16_t smoke, uint16_t fireVal, uint8_t tempC) { static AlarmState cur STATE_NORMAL; switch (cur) { case STATE_NORMAL: // 正常 - 预警烟雾超一级阈值 或 温度超50度 if (smoke WARN_SMOKE_TH || tempC WARN_TEMP_TH) cur STATE_WARNING; break; case STATE_WARNING: // 预警 - 正常需要跌回安全区间带迟滞 if (smoke WARN_SMOKE_TH - HYSTERESIS tempC WARN_TEMP_TH) cur STATE_NORMAL; // 预警 - 报警烟雾超二级阈值 或 温度超70度 else if (smoke ALARM_SMOKE_TH || tempC ALARM_TEMP_TH) cur STATE_ALARM; break; case STATE_ALARM: // 报警 - 预警强报警必须明显回落才解除 if (smoke ALARM_SMOKE_TH - HYSTERESIS tempC ALARM_TEMP_TH) cur STATE_WARNING; break; } return cur; }阈值初始化的时候我做了个自动基准校准开机预热阶段连续采集50次烟雾值取最小的那个作为无烟环境的基准smokeBase然后一级阈值 smokeBase 800二级阈值 smokeBase 1800。这样就算换了个MQ-2批次或者实验室环境有细微差别阈值也是自动适应不用每次改代码重新编译。3.5 执行动作与显示、串口输出状态确定后执行动作就很简单了。每个状态对应一套输出正常态绿色LED亮、继电器关断、蜂鸣器静音预警态红色LED以2Hz频率闪烁、继电器吸合启动排风扇、蜂鸣器以1s为周期间歇响报警态红色LED常亮、继电器继续吸合、蜂鸣器长鸣同时串口每隔2秒输出一次带状态标记的日志。OLED每一秒刷新一次显示内容包含烟雾浓度原始数值、映射后的等效浓度等级、温度值、当前状态名称。OLED驱动用的是I2C接口的0.96寸屏幕驱动芯片SSD1306。代码直接用了网上常见的基础驱动移植核心就是写命令和写数据两个函数显示汉字的话还得准备字库。我为了省事OLED上只显示英文状态和数字这样就不需要弄中文字库了。你如果一定要显示中文找一下现成的中文字库模块或者用带字库的OLED模块也可以。OLED写数字的时候有个小技巧用sprintf格式化成字符串再逐字显示。但要注意sprintf在小内存MCU上比较耗资源建议用snprintf限定长度或者自己写一个简单的整数转字符串函数。我在STM32F103C8T6上跑sprintf没遇到什么问题但如果你用更小的芯片就要注意这个问题。4. 仿真验证先用Proteus跑通逻辑再动手焊板4.1 搭建Proteus仿真工程仿真用Proteus 8.9以上的版本器件库里直接找到STM32F103C8T6。有一个需要注意的坑Proteus早期的STM32模型加载程序文件时有时候需要COFF文件而不是HEX文件。我用的是Keil MDK5编译勾选输出HEX文件后在Proteus里双击单片机在Program File里选择HEX文件就能加载。如果你的Proteus版本识别不了HEX就在Keil的Output选项里勾上Create Batch File生成包含COFF路径的批处理或者直接看Proteus是否支持加载AXF文件。仿真原理图跟实物原理图保持一致但器件上有三个替代MQ-2烟雾传感器用滑动变阻器POT-HG代替调节旋钮改变分压值模拟烟雾浓度的变化。火焰传感器也用另一个滑动变阻器模拟红外强度。DHT11直接用仿真专用宏方案替代温度变量通过串口虚拟终端输入设置。这几个替代都是软件层面的逻辑件和实物是同一份。唯一区别是仿真里没有MQ-2的缓慢响应特性和预热期所以仿真版代码把预热等待时间缩短为2秒方便快速看效果。4.2 仿真场景模拟和联动验证仿真调试我一般按这样几个场景来测场景一洁净环境。两块滑动变阻器都调到最小分压系统应该稳定在正常状态绿色LED亮蜂鸣器不响OLED显示NORMAL。场景二缓慢烟雾上升。把模拟烟雾的滑动变阻器从0慢慢往上调观察ADC值在OLED上的变化直到超过一级阈值。此时系统应该跳到预警状态继电器闭合、蜂鸣器开始间歇响、显示WARNING。这个场景验证的是迟滞逻辑——这时候再稍微回调一点阻值系统不应该立刻跳回正常状态必须等数值明显回落。场景三温度飙升。通过虚拟终端输入T75触发报警状态蜂鸣器长鸣、红灯常亮、串口输出ALARM。这个场景验证高温逻辑。场景四烟雾猛升。滑动变阻器直接拧到最大系统应该直接从正常状态跳到报警状态跨过预警状态直接强报警因为二级阈值也被突破了。仿真的时候用Proteus的虚拟示波器看看PWM波形的频率确认蜂鸣器PWM输出是正常的4kHz。如果波形频率不对多半是定时器分频配错了趁早发现。4.3 仿真时钟配置这个最坑的细节Proteus仿真STM32时最坑的是时钟配置。实物板上用8MHz外部晶振配PLL到72MHz没问题但Proteus的VSM模型对外部晶振支持不太好尤其是用CubeMX默认配置生成的PLL倍频仿真时启动往往直接失败Proteus显示芯片不工作或者复位循环。这不是你电路画错了而是仿真器模型与时钟树不兼容。我的解决办法是在CubeMX里给仿真版本单独配置RCC时钟源选HSI内部8MHz不用PLLSysClk直接8MHz。这样ADC、USART、定时器的时钟频率都降下来了但逻辑判断、联动执行这些核心功能完全不受影响仿真运行也稳定。实物板再改回外部晶振PLL 72MHz。不要嫌麻烦这两套配置是CubeMX工程里两个时钟方案而已导出两次工程就行。仿真通过之后再打板实测。实测的流程是先刷一个最简单的LED闪烁程序确认最小系统正常再刷传感器采集程序用串口看ADC数值变化最后才刷完整固件。一步到位刷完整固件如果出问题根本分不清是硬件还是软件的问题所以我强烈建议这个分步验证的顺序。4.4 实测结果与仿真对照仿真和实测的差异主要来自传感器特性。仿真的滑动变阻器响应是即时的MQ-2在实物上有个数秒的响应时间烟雾出来要过几秒数值才会明显上升。感知到这个问题后我在状态机的预警转移条件里做了一个连续3次超过阈值才触发的计数逻辑实测下来能有效过滤瞬间的临界抖动同时又不影响真正的报警响应速度。实物测试的地点就是普通办公室空气环境没有真的放火。我用的是电烙铁加热松香模拟烟雾环境让松香烟雾飘向MQ-2探头ADC值从基准的260一路涨到2000以上系统稳定触发了预警和报警。温度检测端则用电吹风直接对着DHT11吹热风验证。这套测试方法安全又有效写毕业论文或者项目验收的时候也拿得出手。5. 常见问题与排查技巧实录5.1 ADC数值乱跳和阈值误触发这几乎是必踩的坑。现象系统刚开机就报警或者没烟雾时OLED上烟雾值一直乱跳。排查方向有三层硬件上先检查MQ-2模块的供电是不是3.3VVCC接5V会导致输出超过3.3VADC读满量程再检查PA0引脚有没有加0.1uF滤波电容没有的话用示波器看引脚电压是带毛刺的软件上检查滤波函数是否正确确认中值滤波和滑动平均都启用了。另外MQ-2上电确实有个预热过程新传感器从冷态上电到稳定可能要几分钟我在开机流程里加了Calibrating...的3分钟延时就是这个原因。如果跳过预热直接判断几乎必然误报。这个不是代码bug是气敏传感器的物理特性。5.2 DHT11一直读不通DHT11读不到数据的排查顺序先确认引脚配置成开漏输出再确认外部4.7k上拉电阻真实焊接且一端接3.3V程序里确认读取间隔有没有小于1秒最后用示波器看数据引脚有没有波形。波形能看到但代码读不出来多半是微秒延时函数不准DHT11的高电平宽度窗口很窄延时偏差一层就把0判成了1。实测中还遇到过一种情况DHT11和OLED共用I2C总线时OLED的时序干扰到了DHT11。最后我把DHT11挪到独立的GPIO引脚彻底隔离开问题就消失了这也是为什么前面的引脚分配表里DHT11用的是PA2而不是I2C的引脚。5.3 蜂鸣器声音小或者不响先说声音小。有源蜂鸣器直接给高电平就响但如果供电只有3.3V很多蜂鸣器模块音量偏小。换成5V供电的蜂鸣器模块或者驱动电路用三极管接到5V电源上音量立刻上来了。我在原理图里把蜂鸣器的集电极供电就接到了5V那路实测效果好很多——这就是为什么驱动级要单独接5V而不直接吃3.3V。完全不响的情况先分清是有源还是无源蜂鸣器。无源蜂鸣器你给个高电平它不会响必须给PWM方波。我在代码里用定时器输出4kHz PWM就是为了兼容无源蜂鸣器。如果用的是有源蜂鸣器PWM的高电平有效一样响如果是低电平触发型的蜂鸣器模块检查一下模块是高还是低电平触发把代码改成取反输出就行。5.4 继电器频繁吸合断开继电器啪嗒啪嗒来回跳是阈值临界抖动造成的。解决思路就是软件上做迟滞和状态计数双重机制。具体实现我已经写进状态机正常转预警需要连续3次采样都超阈值预警转报警需要连续3次采样都超二级阈值恢复正常状态要低于阈值减掉迟滞量。加上这个逻辑后继电器在两小时内没有任何误动作之前调试过程中大概每几分钟就会跳一次。硬件上一个容易被忽略的坑是继电器线圈断电瞬间续流二极管焊反了会造成三极管直接烧穿。方向判断方法很简单二极管负极接线圈接正电源的那一端正极接三极管集电极那端。验证的时候用手摸一下三极管如果吸合一会儿就烫手大概率续流二极管有问题。5.5 仿真能跑实物不跑仿真通过实物上电没反应先别怀疑代码。用万用表量3.3V电压是不是正常的量芯片NRST引脚是不是高电平VDD每个引脚都要供电。再检查BOOT0有没有可靠接地——如果悬空芯片可能进不了Flash启动模式。启动不起来还有一个常见原因外部晶振没起振或者负载电容值不对。示波器测不到8MHz波形的话可以先用STM32内部HSI时钟跑代码里把时钟源改回HSI确认芯片能运行后再查晶振电路。实物板上我最开始犯的错是PCB上引脚画错了把PA2和PA3当成DHT11的数据口但代码里配置的是PA2。这种事情原理图核对一百遍都不如用万用表量通断一遍来得直接。所以每次焊完板子第一件事就是拿万用表蜂鸣档顺着关键信号线量一遍。6. 开源工程使用建议与后续扩展6.1 开源目录结构与快速上手顺序开源工程发布后很多人下载下来不知道从哪看起我特意把文件按使用顺序排列了一下/README.md // 项目说明、引脚分配、使用步骤 /Hardware // 原理图源文件立创EDA和AD双版本 /Schematic_V1.0 /Firmware // Keil MDK5 工程 /Simulation_8MHz // 仿真版8MHz内部时钟 /Board_72MHz // 实物版外部晶振72MHz /Simulation // Proteus仿真工程 /Fire_Alarm.pdsprj /Doc // 设计文档、阈值标定记录建议的上手顺序是先从仿真开始用Proteus打开仿真工程加载Firmware/Simulation_8MHz编译出来的HEX文件按第4章的四个场景把逻辑跑一遍理解状态机的行为。然后打开实物的原理图和实物版代码对照引脚把外设接一遍烧录后先用串口配合实验调试最后再真实模拟烟雾环境做整体验证。6.2 后续可以怎么扩展这套系统的传感器和主控外围其实已经预留了扩展空间。最实用的方向是加WiFi远程报警STM32的USART2和USART3都空闲接一个ESP8266模块固件里加几行AT指令的发送和解析代码就能在烟雾报警时把消息推到手机。更进一步可以用MQTT协议把温湿度、烟雾值、系统状态周期性地发到服务器远程查看实验室环境。多节点组网也是实验室常用的需求。一个实验室可能有多间屋子每间屋子一套预警节点用CAN总线或者RS485把所有节点串起来主节点汇总显示所有屋子的状态。STM32F103C8T6的CAN控制器本来就内置RS485只需要外接一颗收发芯片硬件改动不大。还有一个值得做的升级是灭火联动。继电器从只控制排风扇改成控制一个电磁阀或者灭火装置报警状态延时几秒后自动启动灭火。这个要看实验室的具体环境和安全规范别自己乱接但作为毕业设计的功能亮点是非常加分的。6.3 移植到其他型号STM32需要注意什么代码里除了CubeMX生成的初始化文件跟型号有关之外业务逻辑层基本上是跨型号通用的。把ADC通道号、引脚编号改成目标型号对应的宏就行。如果是STM32F103系列内移植到ZET6或者RCT6几乎不用改代码。如果换到F4系列ADC的差异化比较明显F4的ADC转换速度更快而且多了多通道扫描的硬件支持滤波里面的采样间隔参数要适当调整一下不然ADC太快导致滤波频率过高CPU空跑占资源。时钟配置是移植最大的坎。F4的HSE启动过程比F1慢如果沿用我工程里的外部晶振那套配置建议用CubeMX重新生成一遍时钟树别手动硬改避免因为启动时序差异导致芯片卡在HSE就绪等待上。最后再分享一个小技巧。这套系统可以直接用STM32CubeProgrammer通过ST-Link烧录也可以用来读芯片内部Flash验证固件版本。我调试的时候用ST-Link Utility读回芯片里的二进制跟编译生成的HEX做比对排除过几次烧录没成功但以为成功的尴尬局面。调试接口那个4针的SWD预留所在地原理图上一定要留出来不然后面想升级固件、调现场的话会非常痛苦。做开源项目最怕的是半途烂尾但消防预警这种真能救命的系统做的时候动力很足。回头来看整个项目里最花时间其实不是STM32代码而是传感器的标定和状态机的边界设计——要让系统敏感但不误报这个平衡点只能靠实测慢慢试出来。工程里我已经把默认阈值和标定方法写进了文档拿过去直接用问题不大不过真心建议你在自己实验室环境下重新做一遍基准标定毕竟每间屋子的空气本底数值是不一样的。这套系统后来的版本我还加了继电器自检和传感器失效检测如果邮件或者评论区问的人多我再把升级版 的差分整理出来。
返回列表