基于STM32的智能消防预警系统:传感器采集与WiFi远程报警实现
简介基于STM32单片机的物联网智能消防预警系统毕业设计源码面向电子、嵌入式及物联网专业学生和毕业设计开发者提供一套可运行的消防预警项目完整参考。系统以STM32为主控结合WiFi模块实现烟雾、温度、火焰等传感器的数据采集、远程监控与异常报警能够通过云端或移动端查看状态并及时接收预警信息适合作为课程设计或毕业论文的工程基础。资源共202个文件包含57个h头文件与53个c源码文件构成完整STM32固件工程另有Keil工程配置uvprojx/uvoptx、Android客户端源码kt/gradle及apk安装包、演示视频mp4和docx说明文档方便从代码阅读、环境编译到实物演示全流程使用压缩包整体约46.08MB目录结构清晰便于按模块检索。已有71人学习下载。源码模块化程度高外设驱动与核心算法均有注释可帮助开发者快速掌握传感器数据采集、WiFi通信、嵌入式端逻辑处理及移动端联动等关键环节也可在此基础上扩展功能、完善毕设报告。1. 为什么拿STM32做消防预警一块板子把采集、判断、上报一次做完做过物联网毕设的人都清楚最怕的不是功能做不出来而是功能做完老师一问原理就卡壳。这套基于STM32的智能消防预警系统正好卡在“够用”和“能讲清”之间用一块STM32做主控接烟雾、火焰、温度三路传感器再通过WiFi模块把数据传到云平台实现本地声光报警和手机远程预警。整套源码覆盖了从传感器采集、阈值判断、数据上云到远程控制的完整链路适合正在做物联网/嵌入式方向毕设、又不想堆砌高深算法的人也适合想快速搭一套可演示原型的开发者。我拆完这套资源后最直接的感觉是它的工程结构并不复杂但每一环都踩在常见毕设评分点上。2. 系统架构与器件选型三路传感信号和WiFi透传的链路怎么打通2.1 传感器选型烟雾、火焰、温度三路信号各走各的接口这套系统的前端采集是三路并行烟雾浓度、火焰有无、环境温度。三个传感器对应三种不同的接口类型正好覆盖了嵌入式里最常见的三种数据读取方式——模拟量采集、数字量读取和单总线通信。烟雾传感器用的是MQ-2输出是模拟电压浓度越高输出电压越高。它接到STM32的ADC引脚通过采集电压值换算成烟雾浓度百分比。这里有个常见的坑MQ-2上电后会有一段预热期前几十秒输出漂移很厉害代码里如果上电立刻采集很容易误报。火焰传感器用的是红外探测型模块检测火焰发出的红外光谱输出是数字电平有火为低电平无火为高电平。直接接GPIO读电平即可不需要ADC参与。温度传感器用DS18B20单总线协议一根数据线既能发命令又能收数据但时序要求严格代码里对延时精度敏感后面避坑章节会单独说。三个传感器的接口分配如下传感器输出类型STM32接口供电电压数据特征MQ-2烟雾模拟电压PA0 ADC5V浓度越高电压越大火焰探测数字电平PA1 GPIO3.3V有火为低电平DS18B20温度单总线PA2 GPIO3.3V12位温度数据2.2 主控与WiFi分工为什么选ESP8266做透传而不是直接做主控这套资源里主控是STM32WiFi模块是ESP8266两者通过串口通信ESP8266工作在透传模式。为什么不用ESP8266直接采集传感器这是很多人拿到源码后第一个问题。ESP8266本身也有ADC但它只有一个通道精度一般而且WiFi协议栈会占用大量CPU时间实时性不好控制。STM32负责传感器采集和报警判断ESP8266只做数据搬运各干各的活逻辑上清晰很多。透传模式的用法是先通过AT指令把ESP8266配成TCP客户端连接到云平台或自建服务器的IP和端口连接成功后发送ATCIPMODE1进入透传之后所有发到串口的数据都会自动通过TCP发出去。// 串口发送AT指令初始化ESP8266 uint8_t *wifi_init_cmds[] { AT\r\n, ATCWMODE1\r\n, // 1表示Station模式连接外部路由器 ATCWJAP\MyWiFi\,\password123\\r\n, // 替换为实际WiFi账号密码 ATCIPSTART\TCP\,\192.168.1.100\,8080\r\n, // 服务器IP和端口 ATCIPMODE1\r\n, // 进入透传模式 ATCIPSEND\r\n // 开始发送数据 };这段代码的逻辑是逐条发送AT指令每条指令之间需要一个延时等待ESP8266返回OK。注意第三个参数的WiFi账号密码和第四个参数的服务器IP端口这两个是必须按实际环境修改的。ATCIPMODE1之后模块不再响应AT指令直到发送才能退出透传。2.3 供电与继电器联动5V和3.3V的隔离不能将就系统里同时存在5V设备和3.3V设备MQ-2需要5V供电才能保证加热丝正常工作ESP8266也需要稳定的3.3V而STM32和DS18B20是3.3V逻辑。很多人在这一环翻车——用一个AMS1117-3.3直接从5V降压结果WiFi一发射数据电流瞬间拉高单片机复位。我一般建议的做法是5V电源进来后先给MQ-2供电再通过AMS1117-3.3降压给STM32和ESP8266。继电器模块如果用来控制220V设备比如排风扇、电磁阀需要用光耦隔离继电器模块绝不能和单片机的GND直接连在一起否则继电器动作时的电磁干扰会把ADC采集值打得乱七八糟。3. 固件源码移植拿到工程后先改配置、再调阈值、最后对协议3.1 工程目录与启动流程别急着编译先看这三个文件这套源码的工程结构是典型的STM32标准库或HAL库项目具体用哪个库不影响整体思路。拿到压缩包解压后先不要急着点编译先把下面三个地方看明白第一个是main.c系统的初始化流程都在这里。典型的执行顺序是系统时钟初始化、GPIO初始化、ADC初始化、DS18B20初始化、串口初始化一个接ESP8266一个接调试信息、然后进入while循环。第二个是传感器驱动文件里面封装了MQ-2读取、DS18B20温度读取、火焰电平读取的函数。这些函数返回值的数据类型和范围决定了后续阈值判断怎么写。第三个是WiFi通信相关的文件里面封装了AT指令发送、透传模式切换、数据打包发送的函数。这套资源的WiFi部分没有用AT指令解析库而是直接串口打印字符串理解起来更直观。3.2 传感器采集与阈值判断先换算物理量再做判断看源码里烟雾采集部分核心代码是ADC读取和电压换算uint16_t smoke_get_value(void) { uint16_t raw 0; HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 100); // 等待转换完成超时100ms raw HAL_ADC_GetValue(hadc1); HAL_ADC_Stop(hadc1); // 换算成电压值再归一化成0-100的浓度百分比 float vol raw * 3.3f / 4095.0f; // 12位ADC满量程4095 int percent (int)(vol / 3.3f * 100.0f); return (uint16_t)percent; }这段代码看起来简单但有一个关键点ADC的参考电压。如果板子上的3.3V不是精确的3.3V而是3.5V或者3.0V算出来的百分比就有偏差。所以前一行从4095.0f换算电压时理论值应该用实际参考电压替代。这套源码里直接写死了3.3f实际用的时候如果你的板子供电偏高阈值也需要配合调整。温度读取部分用的是DS18B20的64位ROM命令序列整套代码是标准的单总线时序复位脉冲、存在脉冲、跳过ROM、启动转换、读取暂存器然后拼接12位温度数据。这部分源码时序是调好的移植时注意延时函数不能随意改。火焰读取就简单得多直接读GPIO电平uint8_t flame_get_status(void) { // 返回0表示检测到火焰返回1表示无火焰 return HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1); }阈值判断的主逻辑在while循环里烟雾百分比大于设定阈值、或火焰电平为低、或温度超过60度三者任一成立就进入报警状态。源码里默认阈值烟雾是30%、温度是60度这两个数值在代码里是宏定义移植时按环境调整。3.3 数据打包与上报JSON格式别自己发明字段要前后端对死数据上报这段源码用的是JSON格式字符串拼接核心代码如下char json_buf[128]; sprintf(json_buf, {\t\:%d,\s\:%d,\f\:%d,\a\:%d}, temperature, smoke_percent, flame_status, alarm_flag); printf(%s\r\n, json_buf);JSON的四个字段含义t是温度s是烟雾百分比f是火焰状态a是报警标志。这套源码里的字段命名很短刚开始看可能不习惯但这正是为了节省流量和单片机的内存开销。云平台那边解析的时候要严格按照这四个字段名来。如果你改了字段名云端规则引擎也要同步改否则数据能到平台但触发不了报警。3.4 远程控制指令解析下行指令怎么从云平台回到设备预警系统不只是上传数据还要能接收控制指令。源码里基于TCP下发指令解析也很直接——串口中断里收数据读到特定字符就执行对应动作void uart_rx_parse(uint8_t data) { static uint8_t cmd_buf[8]; static uint8_t idx 0; cmd_buf[idx] data; if (data \n) { // 匹配字符串例如relay_on开继电器relay_off关闭继电器 if (strstr((const char*)cmd_buf, relay_on) ! NULL) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); } else if (strstr((const char*)cmd_buf, relay_off) ! NULL) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); } idx 0; } }这段代码的逻辑很简单把串口收到的字符存进缓冲检测到换行符就认为一条指令结束然后用strstr做子串匹配。注意一个问题strstr匹配是包含即命中如果云平台发来relay_on后面还带了一些调试信息也会被误判为开继电器。严谨的做法是精确比较但作为毕设演示这种包含匹配完全够用。4. 数据上云与预警联动从TCP透传到远程告警的完整闭环4.1 云平台接入方案自建服务器和现成物联网平台怎么选这套源码里WiFi模块建立TCP连接的目标地址是192.168.1.100。如果只是做本地调试手机开热点、电脑开一个TCP调试助手就能接收数据但如果要演示远程预警就需要一个公网可达的服务器。有两种常用做法。第一种是自建TCP服务器在云服务器上跑一个简单的Python脚本监听端口把收到的数据存成日志或者转发到手机。优点是可控性强缺点是你得自己写服务端代码。第二种是接入现成的物联网平台平台自带数据可视化和报警推送功能省去写服务端的功夫。两种方案的对比如下方案服务端工作量可视化报警推送适合场景自建TCP服务器自行写脚本需另做需另做想展示网络编程能力物联网平台零代码配置内置内置重点展示设备端功能我一般会建议毕设用第二种因为答辩时老师更关心嵌入式端做了什么事不是服务端写了多少行Python。数据能稳定上云、报警能推到手机就已经达到验收预期了。4.2 数据格式与心跳机制断线重连是稳定演示的保底数据透传连接建立后设备侧要有心跳包。TCP连接本质上是长连接但如果中间路由器NAT超时或者WiFi波动连接会悄悄断开设备自己也感知不到。源码里如果只发数据不发心跳演示时很容易出现设备离线但界面还显示在线的假象。常见做法是每10秒发一次心跳包心跳包可以带简单的设备状态信息// 定时器10秒回调发送心跳保持连接活跃 void heartbeat_timer_callback(void) { sprintf(json_buf, {\type\:\heartbeat\,\device\:\stm32_fire\}); printf(%s\r\n, json_buf); }心跳包和数据包用type字段区分云平台收到heartbeat类型就回复一个ACK设备收到ACK就认为链路正常。如果连续三次没收到ACK源码里会执行ESP8266重启逻辑重新建立连接。这个设计很实用能在调试时省掉大量设备怎么又掉线了的排查时间。4.3 报警联动逻辑声光、推送、继电器三级响应报警联动是这套系统的演示亮点可以分为三个层级。第一层是本地声光报警蜂鸣器响、红色LED闪烁这由STM32直接控制不依赖网络。第二层是远程推送设备将报警状态位a置1云平台收到后通过规则引擎推送到手机。第三层是继电器联动报警时自动打开排风扇或电磁阀执行灭火或排烟动作。继电器联动代码通常放在报警处理逻辑里void fire_emergency_handle(uint8_t alarm) { if (alarm 1) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 打开排烟阀 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); // 蜂鸣器鸣叫 printf({\action\:\relay_on\,\reason\:\smoke\}); } else { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); } }这个函数的关键在于报警状态必须有自恢复机制。很多同学做报警只会置位不会复位演示时触发一次报警后现场温度降下来了蜂鸣器还在响。正确逻辑是连续N次采集恢复正常才清除报警标志避免瞬态波动导致反复触发。5. 避坑指南WiFi掉线、误报、上电烧板五个常见翻车现场5.1 WiFi连接失败但单独测试模块正常现象ESP8266单独用USB转串口接电脑AT指令全都正常一接到STM32上就连接失败串口调试助手能看到发送的AT指令但收不到OK返回。原因大部分ESP8266模块是3.3V供电但峰值电流能到300mA以上。STM32开发板上的3.3V稳压芯片如果同时给ST-Link、传感器、屏幕供电电流余量不足WiFi发射瞬间电压跌落模块直接复位。解决给ESP8266单独一路AMS1117-3.3供电输入从5V取输出只给ESP8266。TXD和RXD的连接注意交叉模块的TXD接STM32的RXD模块的RXD接STM32的TXD共地必须连接。5.2 烟雾传感器上电就误报现象板子上电后还没点烟手机就收到报警推送而且过一会儿自己又好了。原因MQ-2传感器的加热丝需要预热冷态时阻抗不稳定输出电压漂移ADC读到的等效浓度很高。源码里上电后立即进入主循环没有等待预热完成。解决在初始化时加一段预热延时至少让传感器通电60秒后再开始采集。同时代码里做首次采集值的基准确认把前20次采样取平均值作为基准后续浓度计算都减去这个基准值。这样不仅解决上电误报还能修正个体差异。5.3 温度读数跳变偶尔出现85度现象串口打印的温度值大部分时间正常但每隔几秒跳出一个85然后又恢复正常。原因DS18B20在上电时暂存器里默认值是85度如果代码的时序不对或者上拉电阻太弱读到的就是初始化默认值。另一个常见原因是线太长DS18B20的数据线超过30厘米就会出问题。解决数据线和3.3V之间焊一个4.7kΩ上拉电阻。如果用的是一体化模块确认板上是否已有上拉电阻很多廉价模块偷工减料省掉了。代码里对读取结果加一个合理性判断超过125度或者低于-55度就丢弃重读。5.4 火焰传感器在大白天疯狂报警现象晚上演示一切正常白天拉到窗边火焰传感器动不动就触发报警。原因火焰传感器的红外探测对阳光中的红外成分非常敏感太阳光里的红外辐射强度比一个小火苗高得多传感器直接饱和输出低电平。解决把火焰传感器模块上的灵敏度电位器逆时针调小降低增益。安装位置避免朝向窗户和强光源。如果演示场地光线不可控把火焰触发优先级放到烟雾和温度之后或者给传感器套一个黑色遮光筒筒口对准被测区域减少环境光干扰。5.5 继电器动作瞬间单片机死机现象继电器吸合一切正常释放的瞬间蜂鸣器跟着响一声或者整个系统重启看门狗复位。原因继电器线圈是感性负载断电瞬间会产生反向电动势如果继电器的供电和单片机共用一个电源这个尖峰直接灌进单片机的复位引脚或者3.3V稳压芯片导致复位。解决用带光耦隔离的继电器模块模块上自带续流二极管。模块的供电不要从单片机的3.3V取直接从5V电源取。如果模块上没有续流二极管在继电器线圈两端并联一个1N4007二极管负极接电源正极。这五个问题是我在实际调这套系统时最常踩的坑前三个通过改软件就能解决后两个必须在硬件上动手。很多时候调了一整天代码最后发现是供电问题这种翻车经历做嵌入式的应该都懂。6. 进阶调试技巧没有显示屏也能看清系统内部状态很多毕设板子不带屏幕只有一颗LED和串口怎么看系统内部状态我的习惯是做一个三级调试日志第一级是错误信息只打印传感器无响应、WiFi断开这类关键事件第二级是状态切换打印报警进入和退出的事件第三级是原始数据每轮采集打印三个传感器的原始值。这样做的价值在于平时只开第一级日志系统跑一天也不会刷屏出问题时把第三级打开就能看到烟雾浓度曲线、温度波动和WiFi重连的时间点问题定位效率翻倍。另一个技巧是给报警状态机加一个LED闪烁节奏作为“简易显示屏”。正常状态LED一秒闪一次报警状态快速闪烁WiFi连接失败时慢速双闪。不看代码只看灯就能判断系统当前处于什么状态。这个技巧在答辩现场特别好用——评委一眼就能看出报警状态有没有被触发。还有关于阈值标定。MQ-2的灵敏度个体差异很大两个模块放在同一个烟雾环境里输出能差20%。我会在代码里加一个校准模式长按按键进入校准采集当前环境的稳定值作为基准然后自动乘以1.2作为报警阈值。这样每块板子都能在各自的部署位置自适应标定而不是死用源码里的默认30%。最后说一个教训。有一次我改了WiFi的密码和服务器端口编译烧录后放在现场演示结果网络一直不通。折腾了一个多小时最后才发现改的是旧工程文件的宏定义真正编译的源文件里还是旧参数。从那以后我每次烧录前都会强制检查一遍三个关键宏定义——WiFi名称、WiFi密码、服务器IP端口——确认对了才连烧录器。这套系统本身不复杂但越简单的东西越容易在细节上翻车希望你拿到源码后能少走我走过的弯路。希望帮到你。本文还有配套的精品资源点击获取