简介:本资源是一套完整的基于STM32的物联网火灾烟雾报警系统毕业设计实现方案,面向电子信息、自动化、物联网工程等专业的本科生及嵌入式初学者,解决智能安防类课题中传感器采集、本地声光报警、Wi-Fi组网、远程监控与云平台联动等核心需求。压缩包含298个文件,总计50.09MB,涵盖98个C语言源码(如stm32f10x_tim.c、cJSON.c)、93个头文件(.h)、25个XML配置与界面描述文件、13个Java代码(APP端逻辑)、4个HEX固件及1个可直接安装的Android APK应用,同时包含演示视频MP4、OLED显示驱动、ESP8266联网与断网重连机制、阿里云MQTT通信模块等关键实现。已有153人学习下载,提供从硬件驱动、RTOS任务调度、APP交互到云平台接入的全链路代码与说明文档,配套使用说明与操作录屏,便于快速部署验证与课程答辩。 做毕业设计选题的时候,很多人第一反应就是躲开STM32这种“烂大街”的方向,觉得没新意。但你真正把“基于STM32单片机物联网火灾烟雾报警系统”这个题目做下来就会发现,它看似简单,其实上下游供应链、云平台对接、传感器数据采集、报警联动逻辑、硬件抗干扰设计全都涉及了。网上打包好的“源码+使用说明+演示视频.zip”虽然很多,但多数人拿回来只会烧录不会改,一到答辩问原理就卡壳。这篇东西我不讲那些复制的README,我直接以自己从头做过的经验出发,把这个毕业设计项目从方案选型到底层代码逻辑、从MQ-2飘移到ESP8266掉线,全部拆开揉碎讲清楚。
这个项目到底能做什么?简单说,就是一块STM32做主控,采集烟雾传感器和温度传感器的数据,实时显示在OLED屏幕上,本地触发蜂鸣器报警,同时通过WiFi模块把数据推到云平台,手机端远程能看到报警状态。适合谁参考?正在做嵌入式/物联网类毕业设计的学生,或者想快速上手STM32+云平台这套开发链路的人,这篇文章可以帮你省掉至少两周的弯路。
1. 项目整体设计与思路拆解
1.1 为什么选STM32做主控而不是51或树莓派
先说结论:STM32F103C8T6这种芯片,在做“传感器采集+逻辑判定+串口通信”的物联网终端节点时,性价比和开发效率是最平衡的。
用51单片机(如STC89C52)做这个项目当然也能跑起来,但51的ADC模块简陋、主频只有12MHz左右,处理MQ-2模拟量采集时要么外扩ADC芯片,要么用电压比较器走数字量,精度和灵敏度都很难调。而且51的串口只有一个半,又要接ESP8266又要接调试串口,硬生生能把人逼疯。树莓派这种Linux板卡又太“重”,一个烟雾报警终端用Linux系统,启动时间、功耗、成本全都超标,毕设答辩现场演示时万一系统更新卡住了,非常尴尬。
所以STM32F103C8T6的核心优势很明确:工作主频72MHz,内置12位ADC、多个USART、硬件I2C/SPI,运行裸机或RTOS都能稳定工作;CubeMX加HAL库的开发方式让外设配置变成图形化勾选,写驱动代码的效率远高于寄存器开发。最关键的是它的生态足够成熟,网上所有你能踩到的坑基本都有前人记录,调试信息也好搜。
1.2 系统整体架构与工作流程
这个系统从物理结构上划分为四个层级:感知层、控制层、交互层、网络层。
感知层包括MQ-2烟雾传感器和DS18B20温度传感器。MQ-2输出一路模拟电压信号,电压高低和空气中可燃气体/烟雾浓度呈正相关;DS18B20走单总线协议,直接输出数字温度值。控制层就是一片STM32F103C8T6,它负责定时采集这两路信号、做滤波和阈值判定,然后决定是否触发报警,同时把数据打包成JSON格式通过串口发给网络层。
交互层是一块0.96寸OLED屏幕、一个蜂鸣器、两个LED指示灯和两个按键。OLED用于实时显示烟雾浓度ADC值、温度、当前报警状态;蜂鸣器和红色LED组成声光报警;按键用来设置报警阈值或手动消音。网络层选用ESP8266-01S,通过UART串口和STM32通信,ESP8266连接家庭路由器后,用MQTT协议把数据推送到云平台,手机端就可以看到实时曲线。
整体工作流程一句话概括:STM32周期性读传感器、软件滤波、和阈值比较,状态变化就更新OLED和报警器,并同步把这个快照推上云。整个过程在裸机while循环里用状态机实现,不搞复杂操作系统,稳定性好,代码量可控,答辩时逻辑也很好讲。
1.3 为什么这是“物联网”项目而不只是“单片机”项目
很多人质疑这个题目“挂羊头卖狗肉”,觉得加个ESP8266就叫物联网。其实这个项目里的物联网并不只是“WiFi传数据”那么简单,它包含了物联网系统的三个关键要素:端、管、云。
端就是STM32传感终端,负责数据采集和本地控制;管是ESP8266和MQTT协议这条传输通道;云是OneNET或自建的MQTT Broker,负责数据存储、可视化展示和消息推送。你要把这三层打通,至少会涉及串口通信协议、WiFi配网、MQTT主题订阅发布、JSON数据解析、云平台产品/设备/数据流配置这些知识点。这些不正是物联网工程专业的核心技能吗?
而且从毕业设计评分角度讲,“物联网”这个标签直接提升了项目上限。你可以在论文里清楚地画出三层的架构图,每一层都有对应的技术细节和工作量,章节内容能写得很饱满,答辩时老师也更容易认可项目的完整度。
2. 核心硬件选型与电路设计
2.1 STM32最小系统:从核心板到原理图设计
如果你不想自己画PCB、打样,最省事的方案是买一块现成的STM32F103C8T6最小系统板,十几块钱包邮,引出所有GPIO,板载8MHz晶振、复位电路、USB转串口、AMS1117-3.3稳压芯片。这种核心板够用、稳定,省去自己焊LQFP48封装芯片的痛苦,建议把精力放在传感器和通信模块的接线上。
如果你选择自己画PCB打样,那最小系统这几部分是必须的:8MHz主晶振(两个20pF负载电容)、32.768KHz低速晶振(可选,做RTC才需要)、复位电路(10K上拉电阻加0.1uF电容接地)、BOOT0和BOOT1配置(BOOT0下拉10K到地,默认从Flash启动)、3.3V电源网络(每个VDD引脚旁边放一个100nF去耦电容,电源入口放10uF和0.1uF滤波)。
我自己做过一版PCB,第一次投板就踩了坑——去耦电容没放在芯片电源引脚附近,结果ADC采到的数据带着明显的高频噪声,波形在示波器上看全是毛刺,后来把所有电容挪到芯片背面电源引脚正下方,问题才消失。所以别嫌这些细节琐碎,它们是区分“能跑”和“稳定跑”的关键。
2.2 MQ-2烟雾传感器:只用模拟量输出
MQ-2模块在淘宝上很常见,四根引脚:VCC、GND、DO(数字量输出)、AO(模拟量输出)。很多新手第一次都会接DO,然后发现它只能在“浓度超过电位器设定值”时输出高低电平,根本看不到浓度变化——你拧电位器调灵敏度,调到某个点就突然跳变,完全没法做精确报警。
正确做法是把AO引脚接到STM32的ADC输入引脚,比如PA0。MQ-2内部是一个SnO2半导体气体敏感元件,空气中还原性气体(烟雾、液化气、丙烷、氢气等)浓度上升时,敏感材料电导率变大,AO输出对应的模拟电压就变高。STM32的12位ADC把这个0到3.3V的电压量化成0到4095的数字量,我们就是用这个数字量来反映烟雾浓度等级的。
有一点务必记住:MQ-2上电后需要预热,敏感元件内部有一个加热电阻在工作,刚上电的一两分钟内AO电压会大幅度漂移,甚至看起来像是“误报”。所以代码里我加了开机初始化延时和基线校准逻辑,这个后面代码部分详细说。
2.3 DS18B20温度传感器与OLED显示
DS18B20大家应该不陌生,它支持单总线协议,也就是说一根数据线既做供电又传数据(寄生供电模式),但寄生供电在长线上容易出问题,我用的是外部供电方式:VCC接3.3V,GND接地,DQ接一个GPIO(比如PB1),并在DQ上接一个4.7K上拉电阻。
温度和烟雾浓度联合判断非常重要。现实中一个场景是:厨房炒菜产生大量油烟,但温度不高,MQ-2会被油烟触发;另一种场景是电线短路起火,温度快速上升但烟雾浓度还没来得及达到阈值。如果只依赖烟雾浓度,误报漏报都会发生。所以我用“烟雾浓度超过阈值 且 温度超过50℃”作为强报警条件,只满足烟雾一个条件则为预警,这样可以大幅降低误报率。OLED这里建议选I2C接口的0.96寸黄蓝双色模块,SCL接PB6、SDA接PB7,只需要两根数据线再加电源就能驱动,显示实时状态非常方便。
2.4 报警电路与ESP8266通信模块选型
蜂鸣器分有源和无源两种。有源蜂鸣器内部自带振荡源,只要给高电平就响,控制逻辑最简单,适合这种报警项目。但要注意STM32 GPIO引脚驱动能力有限,直接驱动蜂鸣器带不动,需要用一颗S8050 NPN三极管做开关:GPIO通过1K电阻接三极管基极,发射极接地,集电极接蜂鸣器负极,蜂鸣器正极接5V。这样GPIO高电平时三极管导通,蜂鸣器通电发声。
ESP8266模块我选ESP8266-01S。它只有8个引脚,VCC、GND、RX、TX、EN、GPIO0、GPIO1、RST,IO口虽少但做串口透传完全够用。ESP8266-01S的VCC要用3.3V供电,而且WiFi发射时瞬态电流能到300mA以上,如果直接从STM32板载的AMS1117取电,容易把电压拉低导致系统重启。所以我单独用一个AMS1117-3.3模块给它供电,地线跟STM32共地,效果很稳定。GPIO0在上电时为低电平则进入下载模式,正常运行时悬空或接上拉。
有一点很关键:ESP8266的TX和RX是3.3V电平,STM32的串口也是3.3V电平,二者直连没问题。但如果你的STM32核心板带有USB转串口芯片,而那个串口是5V电平,就不能直接把ESP8266接上去用,得加电平转换,否则会烧WiFi模块。我见过太多人因为这个把ESP8266烧挂了。
3. 软件核心逻辑与代码实现
3.1 开发环境:CuBeMX初始化 + Keil MDK编译
这个项目用标准库还是HAL库?我的建议是HAL库,因为用STM32CubeMX图形化配置外设,代码生成的效率比手写标准库高太多,尤其适合毕设这种时间紧、任务重的场景。CubeMX的操作流程并不复杂:先选STM32F103C8T6芯片,然后在Pinout视图里配置PA0为ADC1_IN0,PB1为GPIO输出(温度单总线),PB6/PB7为I2C1,PA2/PA3为USART2(接ESP8266),PA9/PA10为USART1(调试打印),PC13-PC15作为按键和LED控制引脚。时钟树直接选HSE 8MHz,PLL倍频到72MHz,点Generate Code,一份初始化工程就出来了。
生成完的工程拿到Keil MDK里编译下载。注意安装STM32F1系列器件支持包(Keil.STM32F1xx_DFP),否则打开工程会报找不到芯片。烧录工具用ST-Link V2,几块钱的“山寨”ST-Link也能用,但驱动要装对。另外ST-Link的烧录下载在Keil里配置成“ST-Link Debugger”,然后Utilities里选“Settings”->“Flash Download”勾选“Reset and Run”,这样烧录完程序自动运行。
3.2 ADC采样与滑动平均滤波算法
ADC多通道采样本身不难,难的是采样结果稳定。MQ-2的模拟输出本身带有纹波,加上市电干扰和电源波动,单次采样值可能上下跳动好几十甚至上百,直接拿去做阈值判断非常容易误报。我的做法是滑动平均滤波:连续采样10次,去掉最大值和最小值,剩下8个取平均。
用HAL库在CubeMX里配置ADC1,PA0通道,采样周期设为239.5个周期(采样时间越长,输入阻抗影响越小,采样越稳定),然后开启ADC扫描和连续转换。HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, 10)启动DMA采样,指定缓冲区长度10,DMA会自动连续搬移转换结果,DMA传输完成中断里读取最新一批数据,再做去极值平均。
这里要注意一个细节:STM32F103的ADC是12位,参考电压是3.3V,所以ADC值对应的电压是adc_val * 3.3f / 4095。如果参考电压不准确,可以接一个精密电阻分压做校准,或者直接用5V供电的MQ-2模块(有些模块AO输出最大是5V,需要分压后再进ADC)。我用的模块AO最大输出3.3V,就直接怼到PA0了。
3.3 烟雾浓度计算与报警判定状态机
很多人问“MQ-2读到的ADC值怎么换算成ppm?”老实说,MQ-2模块不校准的话,所有ppm换算都是经验估算,误差很大,毕设论文里硬写一个公式容易被答辩老师质疑。我的做法是:不做精确ppm换算,直接以ADC值作为“烟雾浓度等级”的线性指标,论文里定义为“无量纲烟雾指数”,实质是ADC电压值经过滤波后的百分制映射。这样既符合MQ-2的实际工作特性,又不牺牲报警灵敏度。
报警判定我建议写成一个有限状态机,而不是简单的if-else。状态分三种:NORMAL(正常)、WARNING(预警)、ALARM(报警)。正常态下每2秒采样一次,烟雾值超过预警阈值就进入WARNING并显示提醒;在WARNING状态若连续3次采样(大约6秒)仍然超过预警阈值,而且温度大于45℃,则进入ALARM状态,蜂鸣器响、LED闪烁、云端推送报警消息。如果检测到烟雾回落且温度降低,状态机逐级回退。
用状态机的最大好处是逻辑清晰、状态迁移有据可循,答辩时老师问“误报警怎么处理”“漏报怎么避免”你都有话可讲。
3.4 OLED显示与按键配置
OLED用U8g2库或HAL驱动其实都可以。为了减小内存占用,我用了U8g2库的软件I2C模式(U8g2 SH1106/SH1107驱动),在工程里加入U8g2源码,初始化后u8g2_ClearBuffer()、u8g2_DrawStr()、u8g2_SendBuffer()即可显示字符串。主循环里每500ms刷新一次屏幕,显示:当前烟雾指数、温度、报警状态。超过OLED单屏显示的字数时注意截断,防止乱码。
按键我用了两个:一个“阈值设置”按键,短按循环切换“预警阈值/报警阈值/温度阈值”的选中项,长按进入调节模式,另一个“加”按键每按一次阈值加10;还有一个“消音”按键,在报警状态下按下后蜂鸣器停止,但LED继续闪烁提示。消音状态在状态机里加一个MUTE标志即可,报警恢复后自动清除。
按键输入一定要做消抖,最简单的办法是HAL_Delay延时20ms后再次读取电平,或者用定时器做按键扫描。我实际用下来发现延时消抖在裸机主循环里就够用,没必要写太复杂的矩阵扫描逻辑。
4. 物联网平台对接与数据上云
4.1 平台选型:OneNET还是自建MQTT Broker
如果你要的是“毕设答辩稳定演示”而不是折腾服务器,我强烈建议用中移物联网的OneNET平台,注册后创建产品,设备接入协议选择MQTT,平台会自动生成产品ID、设备ID、APIKey等参数。之所以不推荐自己搭Mosquitto MQTT Broker,是因为答辩现场的局域网环境不允许你临时开一个虚拟机的服务,万一IP映射搞错、端口没开,整个远程监控环节直接表演“翻车”。OneNET作为公有云平台,只要现场有网,手机就能看到数据,稳定省心。
云平台的作用不只是“转发数据”:它自带数据可视化看板,可以拖拽图表把温度曲线和烟雾指数折线图展示出来,也可以配置消息推送,报警时通过App通知到手机。这些功能在论文和答辩PPT里都是很好的亮点,直接截图就能当成果展示。
4.2 STM32和ESP8266的AT指令通信流程
ESP8266-01S默认出厂是AT固件,STM32通过串口发AT指令控制它连接WiFi并发布MQTT消息。整个流程分为三个阶段。
第一阶段:配置WiFi连接。STM32上电延时2秒,发送“AT+RST”软复位,等ESP8266返回“ready”后,依次发送“AT+CWMODE=1”设置Station模式,再发“AT+CWJAP="你的WiFi名","你的WiFi密码"”连接路由器。这里返回“WIFI CONNECTED”表示连接成功,后面还会显示“WIFI GOT IP”。这一步如果卡住,通常检查的是WiFi名字有没有加转义引号、密码是否正确、路由器是否开了AP隔离。
第二阶段:配置MQTT连接。AT固件里直接用基础AT指令做MQTT很痛苦(要自己写PUBLISH报文),所以更实际的做法是刷一个带MQTT库的AT固件或者直接用NodeMCU(ESP8266)的Arduino环境跑MQTT客户端。如果你坚持用原版AT固件,也可以换成TCP透传模式:先AT+CIPSTART="TCP","183.230.40.39",80建立到OneNET的TCP连接,然后按OneNET的EDP协议或MQTT over TCP格式自己拼报文字节流,复杂度对毕设来说偏高。所以我建议方案是:STM32串口发给ESP8266的固件不做MQTT封装,改用一个“串口透传”AT命令,ESP8266把收到的原始TCP数据直接转发到云平台,所有MQTT报文由云平台一侧的SDK生成——但这在纯AT固件里很难实现。
更稳妥的路线:用ESP8266刷入Arduino固件,在ESP8266内部直接跑PubSubClient库,STM32只通过串口把“传感器数据”的JSON字符串发给ESP8266,ESP8266负责把它Publish到MQTT Broker。换句话说,ESP8266既当WiFi模组又当“协议转换网关”,STM32管采集和本地逻辑,ESP8266管网络,两边的分工非常干净。
4.3 数据上报格式与心跳保活机制
采用Arduino方案后,STM32和ESP8266的串口协议可以设计得很简单:周期性发送一行ASCII文本,比如“up:{"temp":26.5,"smoke":438}\n”,ESP8266收到后解析出JSON部分,通过PubSubClient发布到“devices/设备ID/datapoints”主题。上报周期设为5秒一次,太频繁会平白增加云平台负载和流量,太慢则手机端曲线不流畅、报警延迟大。5秒属于一个“看实时状态不卡顿但又不会浪费资源”的折中方案。
MQTT还有一个特性是KeepAlive,默认60秒发一次心跳包。如果你的系统上报频率是5秒,那心跳就自然包含在数据上报里,不需要额外处理。但“断线重连”必须写:ESP8266在上报失败时先检测WiFi是否还在,然后循环尝试重连MQTT Broker,超过一定次数就重启ESP8266。不然答辩现场突然断开连接后,后续数据就永远传不上去了。
4.4 手机端远程查看的实现细节
OneNET平台自带App(如“中移物联网APP”)和设备云管理后台,不需要自己开发App,这能节省大量时间。登录平台后直接创建数据流模板,绑定设备的数据点,然后在应用管理里拖一个仪表盘和折线图,绑定烟雾指数和温度属性,就能在手机端实时看到曲线。这个“从零到可视化看板”的搭建过程大概半天时间,作为毕业设计的“物联网”展示面完全足够了。
如果你还有余力,甚至可以把OneNET的API对接进微信小程序,在微信里实现“设备列表-实时数据-报警记录”的页面。这个属于进阶玩法,对代码能力要求高,但对毕设绝对是加分项,有能力的同学可以自行尝试。
5. 常见问题与避坑实录
5.1 MQ-2传感器上电漂移和基线校准
我碰到最典型的问题:系统刚上电,OLED上烟雾指数显示好几百,甚至直接报警。起初以为是传感器坏了,后来查资料才知道是MQ-2的正常预热行为——敏感元件温度还没稳定,阻抗一直在变。解决方法是代码里加“开机基线校准”:上电后延时30秒,期间禁止报警判定,只采集数据;第30秒时取连续50次采样的平均值作为基线值;之后上报和判定的烟雾指数都变成“当前值-基线值”的差值。这个差值带正负,负值强制归0。这样无论传感器老化还是环境差异,都能自动适应到当前环境的“零点”。
5.2 ADC数值跳动大:滤波之外还要查电源
软件滤波能压住一部分噪声,但如果硬件上电源纹波大,滤波拉不住。我吃过一次亏:用同一个5V电源给蜂鸣器、ESP8266、传感器一起供电,结果蜂鸣器一响,ADC采集值瞬间跳变几百,报警声直接导致“自己触发自己”。后来改成蜂鸣器和传感器分开供电,或至少在地线上做“星形接地”,并在MQ-2的VCC和GND之间加一个100uF电解电容和100nF陶瓷电容,噪声明显下降。
5.3 ESP8266一直连不上路由器
排查顺序很重要。先看电源:ESP8266附近用万用表测VCC是不是稳定在3.3V,如果掉到3.0V以下,基本就是供电不足,换独立电源。再看网络:ESP8266-01S只支持2.4GHz WiFi,不支持5GHz,你的手机开了双频合一,可能给模块分配了一个连不上的5G信号,进路由器后台关掉5GHz或把双频合一改成“2.4G优先”。最后查串口:波特率默认115200但很多模块出厂是9600或38400,发送AT回车看是否有“OK”返回。我建议第一步先PC端接一个USB-TTL模块,直接在串口助手里调试ESP8266,确认模块和网络都没问题后再接STM32,可以省掉一半的排错时间。
5.4 烧录失败或下载不了程序
STM32下载出现问题通常分两类:一类是Keil报“No Target Connected”,原因是ST-Link没插好、目标板没有独立供电、SWD三根线(SWDIO、SWCLK、GND)接错。另一类是烧到一半卡住,很可能是芯片被读保护了。这时候用一个STM32 ST-LINK Utility工具,连接后执行“Full Chip Erase”解除读保护,再重新下载即可。切记不要在程序里对Flash做整片擦除操作,否则把固件自己擦没了,芯片直接变砖。
5.5 误报和漏报的调优心得
调试报警阈值的时候,不能只用一个固定值。我自己的经验是设三档:预警阈值(比如烟雾指数1500)、报警阈值(比如2400)、温度阈值(45℃)。报警判定必须是“烟雾超报警阈值 并且 温度超温度阈值”这种AND逻辑,双条件同时满足才拉响强报警;只满足烟雾预警就只亮黄灯提醒,不响蜂鸣器。这个逻辑我个人用下来是在“灵敏度”和“可靠性”之间平衡得最好的,既不会炒个菜就吵翻天,又能在真着火时及时响应。
6. 从毕设到答辩PPT的扩展建议
最后再分享一个很多人忽略的点:这个题目虽然烂大街,但你和别人做出来的东西价值可以完全不同。有人只跑通了“传感器+蜂鸣器”就交差,而你可以在这个基础上加一个火焰传感器、一个烟雾浓度趋势分析、甚至加一个排风风扇联动——火灾发生时自动打开排风扇排烟、同时切断非必要负载电源。这些扩展点放在论文“系统功能扩展”章节,立刻让项目的工程完整度和创新性上一个台阶。答辩时老师如果问“你的系统还能怎么改进”,你把这些扩展思路说一遍,就足以展示你真的是理解了整个系统而不仅仅是“抄了一份代码”。这个项目做下来,我最深的体会是:硬件项目永远不会按你预想的方式第一次就跑通,耐心排查、逐层验证、多留一个串口打印调试信息,才是把“可运行”变成“可靠可展示”的关键。
本文还有配套的精品资源,点击获取