拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

STM32实验室消防预警系统实战:从原理图到Proteus仿真

STM32实验室消防预警系统实战:从原理图到Proteus仿真 从本科做课设一路到现在带新人做嵌入式我见过太多“消防预警系统”要么停留在PPT要么焊完板子调不出来。这个STM32实验室消防预警控制系统的开源项目属于典型的“麻雀虽小五脏俱全”主控芯片、多传感器采集、状态显示、报警执行、Proteus仿真全程打通。项目把代码、原理图、仿真文件全放出来了对正在做课设、毕设或者刚入坑嵌入式想找个完整工程练手的人来说是非常合适的参考样本。这篇文章我就按自己复刻这个项目时的思路来聊从需求拆解、原理图设计、核心代码逻辑到Proteus仿真和实际调试的坑全部过一遍。文中涉及的具体引脚映射和代码片段是我基于主流常见接线方式补全的你拿到原理图后可以对照修改原理一样。1. 这个项目到底是干什么的1.1 为什么选“实验室消防预警”这个切入点先说说需求本身。实验室和普通家庭场景最大的区别是环境里大概率有酒精灯、化学品、大功率用电设备一旦着火蔓延速度极快而且实验室经常没人值守。所以系统的核心诉求不是“检测到烟雾就叫一嗓子”而是“越快发现、越早报警、能联动断开危险源”。这个项目把需求拆成了四个功能模块非常清楚烟雾检测用MQ-2气体传感器监测空气中的烟雾浓度这是火灾初期最重要的信号。温度检测用DS18B20监测环境温度当温度异常升高时作为第二重判断依据。声光报警超过阈值后蜂鸣器响、LED闪同时LCD屏幕显示当前浓度和状态。联动控制触发报警后通过继电器控制排风扇或电磁阀实现排烟、切断电源等动作。这四个模块组合起来就是一个最小可用的消防预警闭环。它不追求军工级的火警探测精度但胜在逻辑完整、实现成本低、可复现性强特别适合教学和毕设的场景。1.2 方案选型为什么是STM32F103C8T6主控芯片选了STM32F103C8T6这个决定很合理。它的资源对于一个消防预警系统来说属于“过剩但不过分”Cortex-M3内核72MHz主频64KB Flash20KB RAM12位ADC多个定时器还带硬件I2C和SPI。跟我见过的大量用51核做的同类项目相比STM32的优势主要体现在数据采集精度上。51核的ADC通常是8位或10位而且采集速度慢做烟雾传感器的模拟量采集时检测灵敏度和抗干扰能力都差一截。STM32F103的12位ADC加上规则组扫描模式可以稳定地同时采集烟雾传感器、火焰传感器等多个模拟量通道这是项目体验的根本差距。当然用STM32也意味着工程复杂度上升。你得配置时钟树、初始化GPIO、写中断服务函数这些对新手来说是门槛。但这个项目把工程模板、代码注释都整理好了正好把学习成本变成了学习收益。至于烟雾传感器选MQ-2而不是更贵的MQ-135或光电式烟雾探测器纯粹是性价比考量。MQ-2对液化气、丙烷、氢气、烟雾都敏感响应时间在10秒以内传感器模块自带比较器和数字/模拟双输出一个模块几块钱到十几块钱作为教学演示完全够用。后面我也详细说了它最大的坑预热漂移。这在实际工程里必须处理。2. 硬件设计全程拆解原理图是怎么画出来的2.1 从需求到引脚分配拿到需求后别急着画线先把MCU的引脚资源盘一遍。STM32F103C8T6是LQFP48封装GPIO有PA0-PA15、PB0-PB15还有PC13-PC15等。我按这个项目最常见的接线逻辑给出一版参考分配外设模块引脚类型说明MQ-2烟雾传感器模拟输出PA0模拟输入ADC1通道0DS18B20温度传感器PB12开漏输出/输入单总线火焰传感器数字输出PB13数字输入高电平有效蜂鸣器PB14推挽输出有源蜂鸣器高电平触发继电器控制PC13推挽输出高电平吸合驱动排风扇LCD1602数据线PB0-PB7推挽输出8位并口模式LCD1602控制线RS/RW/ENPB8、PB9、PC14推挽输出对应RS、RW、EN报警LEDPB15推挽输出高电平点亮这套分配的思路是模拟信号和数字信号尽量分开ADC通道放在PA0避免和LCD并口总线抢位置造成画PCB时走线困难。DS18B18的单总线引脚必须配置成开漏并外接4.7kΩ上拉电阻这点原理图上一般画了但很多人接实物时忘了这个上拉电阻死活读不到温度。有源蜂鸣器直接用一个GPIO推挽输出就能驱动不像无源蜂鸣器需要PWM。但要注意蜂鸣器工作电流20到30mA如果直接用GPIO带其实风险很大最好加一个NPN三极管S8050做驱动。原理图上如果没画建议自己补上别让PA14直接被蜂鸣器拽到地。2.2 传感器电路的几个关键细节先看MQ-2。传感器模块的核心是一颗气敏电阻其阻值随烟雾浓度降低模块内部用比较器和电位器把手动阈值调好了数字输出DO口可以直接接MCU的普通GPIO。但如果要精确读取浓度梯度必须用AO口的模拟电压。AO输出接到PA0之前最好先过一级RC低通滤波。我用的是10kΩ电阻加0.1μF电容截止频率约159Hz足以滤掉传感器输出上的高频噪声同时不影响烟雾信号的响应速度。这个细节在原理图上不一定标得很清楚但实际做板子时加上会省掉不少调ADC滤波的麻烦。ADC参考电压直接用VDDA3.3V所以读回来的12位ADC值在0到4095之间对应0到3.3V。再看DS18B20。这颗传感器用单总线协议数据传输和电源共用一根线读取时序精确到微秒级。在原理图设计上必须保证引脚配置为开漏输出外接4.7kΩ上拉电阻到3.3V。供电用寄生供电模式还是外部供电建议直接外部供电把VDD接3.3V数据线单独接上拉。寄生供电模式在长线传输时电压跌落严重容易导致温度读数随机跳变。数据线和电源线之间加一个0.1μF去耦电容。火焰传感器的处理最容易出错。火焰传感器模块在检测到火焰时数字输出是低电平还是高电平不同厂家定义不同。我用的模块是检测到火焰输出低电平指示灯点亮。但很多资料里写的是反逻辑。做原理图前一定先查模块数据手册最好在接线图上用注释标明逻辑。软件里面读到的电平状态和报警逻辑必须和模块的实际输出定义一致否则整个系统反着报警那才是真事故。继电器驱动电路是硬件设计里最容易翻车的地方。STM32引脚输出能力最大只有几mA直接驱动继电器线圈线圈电流约70mA必烧引脚。标准做法是GPIO输出接一个S8050三极管基极发射极接地集电极接继电器线圈另一端线圈并联一个1N4148续流二极管。续流二极管的极性是阴极接电源正极阳极接集电极方向千万别接反接反了等于短路。原理图里这一步必须有很多新手抄图时漏了这个二极管继电器断电瞬间的反向电动势能直接击穿三极管。2.3 电源设计别让三个模块抢电实验室消防系统的负载包括STM32核心板、MQ-2模块、DS18B20、蜂鸣器、继电器、排风扇。继电器和排风扇的电流都是安培级的如果全部从STM32板载稳压器通常是AMS1117-3.3取电稳压器会过热甚至烧毁。合理的电源分配是这样外部输入12V/1A直流电源。12V直接给继电器线圈和排风扇供电这是动力回路。12V经LM2596降压到5V给LCD1602背光、蜂鸣器和MQ-2加热丝供电。5V再经AMS1117-3.3降到3.3V给STM32、DS18B20、火焰传感器、逻辑电路供电。注意一点MQ-2内部有一个加热电阻需要持续供电约5V功耗约1W左右。这个加热丝电流不小如果把它接到3.3V上加热温度不够传感器灵敏度会大幅下降响应变慢。所以MQ-2一定要用5V供电。地线处理上动力地12V回路和信号地3.3V逻辑地建议单点汇接避免继电器动作瞬间的大电流在地上产生压降导致ADC参考电位抖动烟雾浓度读数跳变。3. 软件核心代码实现从初始化到报警联动3.1 工程搭建与初始化要点项目代码基于STM32标准外设库StdPeriph_Lib或HAL库都可以实现。用标准库的老项目代码风格紧凑但GPIO初始化比较繁琐用HAL库代码更多但逻辑清晰。这套开源代码我实测是标准库风格初始化顺序很典型void System_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 使能时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); /* MQ2模拟输入 PA0 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, GPIO_InitStructure); /* DS18B20 单总线 PB12 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); /* LCD 数据引脚 PB0-PB7 推挽输出 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_Init(GPIOB, GPIO_InitStructure); }两个最容易忽略的初始化步骤第一ADC1的时钟分频必须设置。ADC的输入时钟不能超过14MHz而APB2时钟是72MHz所以必须设ADC_Prescaler为6分频否则ADC采样结果会漂移。不少人的代码里漏掉这句采集到的烟雾电压偏高且不稳定。第二DS18B20引脚要配置成开漏不是推挽。单总线协议要求总线空闲时被上拉到高电平设备拉低则产生通信时序。如果用推挽输出主机拉低时设备也拉低总线冲突直接烧器件虽然STM32引脚有电流限制但长时间冲突会不稳定。3.2 数据采集ADC采样与滤波ADC配置成连续转换模式单通道采集PA0的烟雾电压。但裸读一次ADC值就去判断报警在真实场景里会误报得一塌糊涂。因为MQ-2有漂移环境空气流动会让读数上下抖动。我在代码里看到原作者用了一次20次均值滤波uint16_t Read_MQ2_Value(void) { uint16_t sum 0; for (uint8_t i 0; i 20; i) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) RESET); sum ADC_GetConversionValue(ADC1); } return sum / 20; }20次连续采样然后取平均基本能把瞬时毛刺干掉。如果还想做更好的数字滤波可以加一个一阶低通滤波指数滑动平均static float alpha 0.2f; float filtered alpha * raw_value (1.0f - alpha) * filtered;alpha越小滤波越平滑但响应越慢。消防场合建议alpha取0.3左右在“抗误报”和“及时报警”之间取平衡。DS18B20的读取代码稍微复杂它靠时序通信分三个步骤初始化、跳过ROM、读温度。关键点是延时函数的准确性在STM32主频72MHz下用简单的for循环空转做微秒延时其实误差很大。建议用SysTick做微秒级延时或者直接用HAL_DelayHAL库自带换算成微妙级延时。初始化时序要求主机拉低480μs以上再释放然后等待设备拉低60~240μs作为应答。时序不对就读回0xFFFF。uint8_t DS18B20_Init(void) { GPIO_ResetBits(GPIOB, GPIO_Pin_12); Delay_us(500); // 拉低500us GPIO_SetBits(GPIOB, GPIO_Pin_12); // 释放总线 Delay_us(60); uint8_t presence GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12); Delay_us(420); // 等待设备应答结束 return presence; // 0表示存在1表示无应答 }注意DS18B20温度转换时间最长750ms12位精度读取温度之前必须等待转换完成不然读到的是上一次的缓存值。系统启动后第一次读温度尤其容易踩这个坑显示“85℃”或者固定值就是因为没等转换完成。3.3 报警判定逻辑用状态机代替单阈值新手做这个项目最容易写出的报警逻辑是if (smoke 阈值) 打开蜂鸣器;这样写会有一堆问题。最典型的是烟雾浓度在阈值附近抖动蜂鸣器开0.5秒停0.5秒地反复抽风报警状态非常不稳定。我看到这个开源项目的代码里已经用了“二级阈值状态锁存”的思路这个值得特别拿出来讲。它把系统状态分成四个节点正常、预警、报警、复位。正常状态烟雾浓度和温度都低于预警阈值继电器不动作。预警状态当烟雾浓度超过预警值或温度超过45℃时LCD显示“预警”但蜂鸣器不响。这个设计很科学因为很多场景比如实验时正常产生少量烟雾不需要立刻疏散。报警状态当烟雾浓度或温度超过报警阈值时蜂鸣器响、继电器吸合、风扇开启。报警状态一旦进入即使传感器读数回落到预警值以下系统也不会自动退出报警。必须人工按下复位按键或者用遥控/上位机远程复位。复位状态按键触发后系统将报警标志清0继电器释放回到正常状态。typedef enum {STATE_NORMAL, STATE_WARNING, STATE_ALARM} SysState_t; void Fire_Control_Task(void) { uint16_t smoke Read_MQ2_Value(); float temp DS18B20_GetTemp(); switch (state) { case STATE_NORMAL: if (smoke SMOKE_WARNING_LVL || temp TEMP_WARNING_LVL) state STATE_WARNING; break; case STATE_WARNING: if (smoke SMOKE_ALARM_LVL || temp TEMP_ALARM_LVL) { state STATE_ALARM; Alarm_On(); } else if (smoke SMOKE_WARNING_LVL temp TEMP_WARNING_LVL) { state STATE_NORMAL; // 预警可自动恢复 } break; case STATE_ALARM: if (Reset_Key_Read() KEY_PRESSED) { state STATE_NORMAL; Alarm_Off(); } break; } }这套状态机的几个好处避免抖动的阈值杂音引发反复鸣叫。预警和报警之间有时间缓冲允许误报自愈。报警状态锁存保证消防响应不会因为传感器数值回落而自动解除。阈值参数怎么定我在代码里看到默认烟雾报警阈值是ADC值1200约等于1V浓度为中等烟雾温度报警阈值是55℃。这两个值在课设环境下可以按你的传感器校准情况调整。校准方法让传感器在正常环境通电预热30分钟记录稳定读数A再把打火机的气体不打火靠近传感器记录读数B取(AB)/2左右作为预警阈值。注意MQ-2对酒精、液化气也敏感校准的时候要用和目标场景一致的气体。同时防误报还有一个很实用的办法把“报警条件”改为“烟雾超标 且 持续2秒以上”而不是瞬时判断。用定时器做一个标志累计if (smoke SMOKE_ALARM_LVL) alarm_cnt; else alarm_cnt 0; if (alarm_cnt 4) // 每250ms检测一次持续1秒 state STATE_ALARM;这个思路叫“失压延时”实际工程里报警、保护动作几乎都会加它能把真实火灾和瞬时油烟区分开。3.4 LCD1602显示与联动控制LCD1602是这类项目最常见的显示方案。它有8位和4位两种接法这个开源工程用的是8位并口接法初始化代码按标准时序写等待40ms上电延迟然后连续发送0x30、0x30、0x308位模式复位命令最后设置0x388位模式、双行、5x7字符、0x0C开显示不显示光标、0x01清屏、0x06光标右移。void LCD_Init(void) { Delay_ms(50); LCD_WriteCmd(0x30); Delay_ms(5); LCD_WriteCmd(0x30); Delay_ms(1); LCD_WriteCmd(0x30); LCD_WriteCmd(0x38); // 8位模式, 2行 LCD_WriteCmd(0x0C); // 显示开, 光标关 LCD_WriteCmd(0x01); // 清屏 LCD_WriteCmd(0x06); // 光标右移 }LCD显示内容可以分两行第一行SMOKE:0123 TEMP:28C第二行STATE:NORMAL这样实验人员一眼就能看到两个核心指标和当前系统状态。我在实际项目中建议你再加上一条“设备ID”或“房间号”比如“LAB301”方便以后多设备组网时区分。联动控制部分我用的是继电器控制排风扇。代码逻辑简单报警状态下将PC13置高继电器吸合。但真正要注意的是动作延时不要在报警瞬间就立刻让继电器吸合那样风扇启动的浪涌电流会拉低整个电源电压导致LCD花屏、MCU复位。稳妥的做法是在进入报警状态后延时100ms再吸合继电器避开MCU正在刷新LCD的电流峰值。这个细节不写代码里根本想不到我当初调试时就是风扇一启动板子就重启后来才发现是电源瞬间掉压。4. Proteus仿真怎么搭从原理图到仿真跑起来4.1 元件选型与连接这个项目带了Proteus仿真文件对有实物条件的人来说仿真可能“看不出新东西”但对没有硬件、想先跑通代码逻辑的人来说仿真非常关键。Proteus版本建议8.6以上太老版本没有STM32模型。零件库里的关键器件MCU在Proteus里搜索STM32F103C8注意选对封装。老版本库里可能没有需要手动放置并用“Program File”属性加载Keil编译出的hex文件。LCD用LM016L16x2字符屏这个元件引脚兼容LCD1602。MQ-2Proteus库里没有专门的MQ-2元件通常用电位器模拟。电位器滑臂接模拟电压到PA0调电位器改电压就等价于调烟雾浓度。这个方法简单但要注意电位器分压范围和真实MQ-2 AO口的电压范围尽量一致0到3.3V。温度传感器Proteus 8.7以上自带了DS18B20模型可以直接放到原理图里。放上去之后设置它的初始温度比如25℃仿真运行中可以通过滑块实时调整效果非常直观。继电器用Proteus里的RELAY元件线圈接PC13驱动经过一个虚拟三极管触点到灯泡或风扇模型。连接方式和我前面说的实物接线完全一致。唯一注意的地方是Proteus的电源网络它没有“物理电源引脚”你需要在工具菜单里打开“电源轨”工具给3.3V和GND网络命名MCU的VDD引脚才能正确供电。4.2 仿真中的几个坑第一个坑是时钟设置。Proteus里STM32仿真默认外部晶振是1MHz或者8MHz而你的代码初始化用的是72MHz主频。如果Power-Simulation设置为使用外部晶振Proteus按1MHz跑那么你的延时全部变长72倍LCD刷新慢得离谱。解决办法有两种一是把项目里的外部晶振改成8MHz并把RCC配置中的PLL倍频系数调成9得到72MHz二是在Keil工程里把启动文件的SystemInit里默认的外部晶振参数调好。不想折腾的话仿真时直接用“内部HSI”也行但代码里的时钟配置要对应。第二个坑是ADC模型。Proteus的STM32 ADC是“真实”的但电压源必须有一个明确的地参考。我在连接电位器模拟MQ-2时一开始电位器两端悬空ADC读回来全是4095接近满偏后来给电位器两端分别接3.3V和GND才正常。仿真里跑ADC养成先量节点电压的好习惯。第三个坑是hex文件加载路径。Keil编译默认在Objects目录下生成Project.hex如果没开“Create HEX File”选项编译成功也不会生成hex。勾选路径Options for Target - Output - Create HEX File勾上。另外Proteus加载的hex文件路径里不要有中文一些版本对中文路径支持得不好加载后MCU不执行代码看起来像死机。这个坑我见过很多次有网友发现仿真文件放在桌面就正常运行放到“我的项目”文件夹就白屏就是路径问题。仿真调通的步骤建议按这个顺序来先不加载火焰传感器和继电器只放MCU、LCD、电位器、DS18B20。加载代码后确认LCD能显示初始界面调电位器看ADC数值变化。把传感器读数用串口虚拟终端打印出来Proteus里的Virtual Terminal接到USART2这样可以边调边观察不用猜。确认ADC数值稳定后再把继电器、蜂鸣器加进去测试动作逻辑。最后测试报警-锁存-复位完整流程。4.3 仿真验证的效果仿真里最让我满意的一步是把DS18B20的温度拉到65℃时系统直接跳进预警状态屏幕显示温度值也同步刷新。继续拉到75℃蜂鸣器响、继电器吸合、风扇转。按复位键系统恢复。整个逻辑演示一遍大约2分钟非常适合答辩现场演示。但必须说清楚仿真始终是仿真它的意义在于验证“逻辑正确”不能完全验证“硬件可靠”。比如真实MQ-2的预热漂移、继电器线圈反向电动势、按键抖动这些在Proteus里都没有。你仿真通过之后上实物还是要面对这些实际问题。5. 常见问题与调试实战记录5.1 常见问题速查表现象可能原因排查/解决LCD无显示或只有背光LCD对比度电位器没调初始化时序不对调10k电位器到VEE约0.4V检查延时ADC值始终4095PA0悬空电位器未接参考地用万用表量PA0对地电压DS18B20显示85℃上拉电阻缺失供电不足转换未完成加4.7k上拉等待750ms转换时间蜂鸣器不响三极管基极电阻太大如10k导致驱动不足引脚复用冲突基极电阻用1k检查NVIC优先级继电器不吸合三极管接反续流二极管方向错PC13在标准库是JTAG复用脚重新检查原理图禁用JTAGAFIO重映射风扇启动后MCU复位电源压降过大感性负载冲击动力回路独立供电增加延时吸合仿真加载hex后无反应hex路径含中文未开启创建hex文件时钟配置不符国路径勾选Create HEX File核对晶振系统误报警频繁阈值过低传感器预热不充分预热30分钟校准加持续超标延时这里单独强调一下PC13的问题。PC13默认是RTC输出脚TAMPER在标准库工程里要先使能AFIO时钟并且把SWJ配置成禁用JTAG-DP、仅保留SW-DP然后才能把它当普通GPIO输出用。很多人仿真没问题上实物后PC13控制的继电器死活不动大概率是没做这一步或者代码和实物还固化了别的功能。这个坑在STM32F103C8T6上非常典型值得在方案设计阶段就避开。如果不想折腾把继电器控制脚换到PB14把蜂鸣器换到PC13也能解决问题。5.2 两个实测中印象很深的疑难点第一个是MQ-2的“冷启动假报警”。刚接通电源时传感器加热丝还没达到工作温度气敏电阻处于高阻态AO口输出一个接近满量程的电压ADC读数可以达到3000多直接触发报警。这个假报警持续大约20到60秒。所以代码里必须在系统初始化后加一个“预热延时”建议至少30秒。在预热期间系统显示“WARM UP”不进行任何报警判断。这个细节在真实项目中必不可少否则每次上电都诈唬一通。我当时调试时为了加快测试把预热延时改成了5秒结果每次开机蜂鸣器都先响三五秒一开始还以为是传感器坏了。后来对照MQ-2数据手册才发现是预热问题。从这里也能看出来器件手册比一切调试经验都靠谱遇到怪问题先翻手册。第二个是按键消抖。报警锁存的复位按键如果不做软件消抖按键按下瞬间会连抖好几次状态可能刚退出报警又立刻进入报警导致“复位无效”的假象。消抖代码很常规uint8_t Key_Scan(void) { if (KEY_PIN 0) // 按下 { Delay_ms(20); // 延时跳过抖动区间 if (KEY_PIN 0) return KEY_PRESSED; } return KEY_NONE; }在状态机的复位分支里等检测到有效按键后还要再加一个“松手检测”——等按键抬起后再清报警标志防止一次按下多次触发。5.3 代码质量给新人的三个建议我看完这套开源代码觉得它在“能跑”这个层面做得很到位但有些地方还是新手习惯需要改进我这里一并提出建议。第一个建议是模块化。原来的代码把LCD、传感器、蜂鸣器全写在一个main.c里500行还可以忍受但一旦你要加WiFi模块、RFID门禁、上位机协议main.c会膨胀到没法维护。我重构时把它拆成了bsp_lcd.c、bsp_ds18b20.c、bsp_mq2.c、app_fire_control.c每个模块只留一个头文件接口。这样改完整个系统结构清晰得多也方便多人协作。第二个建议是配置参数集中管理。用#define把烟雾预警阈值、报警阈值、温度阈值、预热时间都集中放到一个config.h里#define SMOKE_WARNING_LVL 600 #define SMOKE_ALARM_LVL 1200 #define TEMP_WARNING_LVL 45 #define TEMP_ALARM_LVL 55 #define WARM_UP_TIME_MS 30000这样后期调试只需改一个文件不用在代码里翻来翻去找魔数。第三个建议是加日志输出。哪怕硬件上没有串口调试助手你也可以在USART2上挂一个USB转TTL模块把系统的状态变迁进入预警、进入报警、复位都打印出来。这样调试状态机逻辑时再也不是靠猜而是看着日志追踪每一步。我在代码里增加了类似这样的打印printf([FIRE] State: NORMAL - WARNING, smoke%d, temp%.1f\r\n, smoke, temp);用printf之前初始化重定向函数在工程里写一个fputc重定向到USART2即可。6. 这个系统的后续扩展思路项目做到“能跑、能报警、能复位”只是完成了基础版。以当前这套代码和硬件为基础后续扩展很顺我把三个方向简单列出来。第一加无线远程报警。实验室场景要求无人值守时也能通知到人在MCU上接一个ESP8266模块通过AT指令把报警状态发到MQTT服务器或直接发到微信通过Server酱接口。扩展的时候注意一点ESP8266模块功耗大峰值300mA以上必须单独供电不能直接从STM32的3.3V脚取电否则一联网MCU就复位。我实际试过用PC13串口接ESP8266第一次没单独供电WiFi连上那一刻板子重启后来外接5V/2A电源给ESP8266问题才消失。第二加故障自检。消防设备最怕的是“设备坏了还以为没事”。可以让系统每次上电时自检一遍传感器和执行机构让继电器短促吸合再释放听有没有“咔嗒”声让蜂鸣器鸣叫0.2秒让LCD显示“SELF TEST OK”。如果过自检失败屏幕显示故障代码。这个功能看似简单确是把“演示项目”推向“可用产品”的关键一步。第三做多节点组网。在一个实验室里部署多个传感器节点通过RS485总线连接每个节点分配一个地址主机汇总所有节点的数据。RS485总线比WiFi可靠得多传输距离1200米适合实验室这种电磁干扰小的环境。总线两端各加一个120Ω终端电阻这又是硬件上容易忘的细节。我在实际开发和带新人的过程中体会最深的一点是这类项目最值的不是“某个技术点有多深”而是它逼着你把ADC采集、传感器时序、GPIO驱动、状态机、电源设计、仿真调试整条链路都走通一遍。消防预警虽然是个很小的场景但它覆盖的硬件系统知识面极广做完一遍之后再去做智能家居、环境监测、农业物联网很多思路都能直接复用。如果按这套流程从头到尾复现一遍遇到上电假报警先想到预热延时遇到风扇启动系统复位先查电源分配遇到LCD白屏先查对比度电压和初始化时序——那这篇文章的作用就达到了。实际动手过程中还有一个小技巧把每个模块先在面包板上单独调通再接进系统。我就是先在面包板上把DS18B20的时序调到能稳定读到温度之后整个系统联调时间缩短了一大半。
返回列表