简介:基于STM32F103C8T6的智慧厨房系统完整工程,面向嵌入式初学者、毕业设计、课程设计及工程实训人群,也可作为初期项目立项参考。系统采集烟雾、火焰、一氧化碳、煤气等多路气体传感器数据,经ESP8266模块上传至机智云平台,用户可通过手机APP远程查看数据,并自由设置报警阈值及报警开关,适用于厨房燃气泄漏、火灾隐患等场景的实时监测。压缩包共114个文件,以46个.h头文件与42个.c源文件为主,配合8个启动汇编文件、Keil工程配置、hex固件及引脚接线说明,整体仅507KB,轻量易部署。压缩包内含完整工程目录与各模块接线定义,覆盖多通道ADC采集、I2C驱动OLED、串口与ESP8266通信等关键代码,代码注释清晰,可直接烧录验证或二次开发。目前已有209人学习,对希望快速上手STM32+物联网云平台开发的读者有较高参考价值。
1. 智慧厨房系统用stm32加机智云,到底先解决什么问题
厨房环境监测和燃气报警这类项目,真正难的不是把传感器数据读出来,而是三件事:数据怎么稳定上传、报警阈值怎么随时调整、报警功能怎么在误报和漏报之间取平衡。基于stm32实现的智慧厨房系统,选型思路就是把主控、感知、平台、APP四个环节拆开,用stm32做本地逻辑管理,用机智云做设备接入和数据中转,手机APP只看结果和下发指令。这个方案对于熟悉stm32但不想自己折腾服务器和APP开发的人来说最实用,毕业设计、比赛作品和小型产品原型都能套用。阈值设置、报警开关这类功能,本质上不是stm32主动做的,而是云端把APP下发的数据点写进设备端,由stm32的协议解析层接收后写入本地变量,再参与报警判断。本文按硬件接线、平台数据点建模、stm32上报和回调、ESP8266联调、APP验证这条完整链路展开,重点写清楚哪里容易掉线、哪里数据对不上。
2. 基于stm32的智慧厨房设备端架构,以及数据点在机智云上的建模
2.1 主控与外设选型:为什么是stm32而不是ESP8266直连传感器
常见的低成本做法是直接用ESP8266接传感器,代码少、链路短,但有两个问题:一是ESP8266的ADC只有1路,接完烟雾传感器就没法同时接火焰、温度和湿度传感器;二是它的GPIO驱动能力弱,直接驱动蜂鸣器和风扇需要加三极管,逻辑一旦复杂,代码维护起来很吃力。基于stm32实现的智慧厨房系统,通常选用STM32F103C8T6作为主控,它有3个ADC、最多10个通道,PA0到PA7、PB0和PB1都可以做模拟输入,3路UART可以分别给ESP8266、调试串口和传感器预留。资源上完全够用,价格在8到12元之间,开发资料也最全。
传感器配置方面,常用组合是MQ-2烟雾传感器加DS18B20温度传感器,有条件的再加一个火焰传感器。MQ-2输出两种信号:AO是模拟电压,和可燃气体浓度成正比,接到stm32的ADC引脚;DO是数字信号,超过电位器设定的浓度后输出低电平,可以当备用报警触发源。DS18B20走单总线协议,只需要一个GPIO口,而且支持多点挂载,厨房里测环境温度和燃气管道表面温度可以挂两个。继电器模块用于控制排风扇或电磁阀,stm32的GPIO输出高电平控制继电器通断,注意继电器线圈需要外部供电,不要直接从stm32的3.3V引脚取电。
2.1.1 stm32与ESP8266的UART连接要点
ESP8266在智慧厨房系统里只承担网络透传职责,stm32把数据通过串口发给它,它再通过TCP长连接上报到机智云。接线固定为stm32的PA2(USART2_TX)接ESP8266的RXD,PA3(USART2_RX)接ESP8266的TXD,GND必须共地。这里常见的坑是ESP8266模块的工作电流峰值接近300mA,如果直接从stm32开发板的3.3V引脚取电,WiFi发射瞬间会把电压拉低到2.8V以下,导致模块反复重启。正确做法是单独用一颗AMS1117-3.3从5V降压给ESP8266供电,stm32和ESP8266之间只连TX、RX、GND三根线。另一路USART1的PA9、PA10接USB转TTL,用于打印调试日志。
2.2 机智云数据点定义:从传感器采集值到APP可读对象的基础
机智云平台的核心概念是“数据点”。数据点定义了设备和APP之间传输数据的格式,stm32端代码里的变量、ESP8266上报的JSON字段、手机APP界面上显示的控件,都围绕数据点展开。定义数据点时要先想清楚哪些数据是只读的,哪些必须是可写的。
以智慧厨房系统为例,需要建立的数据点如下表格所示:
| 数据点标识名 | 名称 | 数据类型 | 读写属性 | 取值范围 | 说明 |
|---|---|---|---|---|---|
| temp | 环境温度 | 数值型 | 只读 | -20 到 80 | 单位摄氏度,上报当前温度 |
| smoke | 烟雾浓度 | 数值型 | 只读 | 0 到 4095 | 原始ADC值或换算后的电压值 |
| temp_alarm | 温度报警阈值 | 数值型 | 可写 | 30 到 70 | 手机APP设置的温度上限 |
| smoke_alarm | 烟雾报警阈值 | 数值型 | 可写 | 100 到 4000 | 手机APP设置的烟雾浓度上限 |
| alarm_enable | 报警开关 | 布尔型 | 可写 | 0 或 1 | 0关闭报警,1开启报警 |
| alarm_status | 报警状态 | 布尔型 | 只读 | 0 或 1 | stm32本地判断后上报 |
可写的数据点会在APP界面上自动生成输入控件,数值型对应输入框或滑动条,布尔型对应开关。这里有一个容易搞混的概念:阈值和开关虽然由APP下发,但判断逻辑必须做在stm32端。原因很简单,如果依赖云端判断报警条件,网络一断报警就失效了,智慧厨房就失去了最核心的安全保障。stm32本地先把阈值存进变量,每轮采集数据后与阈值比较,达到条件立即驱动蜂鸣器和继电器,同时把报警状态上报。
2.3 stm32工程代码结构:采集、滤波、报警、上报四个模块划分
基于stm32和机智云的工程代码,我习惯按功能拆成四个文件:sensor.c负责ADC采集和DS18B20读取,filter.c做滑动平均滤波,alarm.c做阈值判断和继电器控制,gizwits_app.c处理与机智云的数据交互。main函数只做初始化和循环调度。
// main.c 伪代码 int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); ADC_Init(); DS18B20_Init(); Gizwits_Init(); while (1) { Read_Temp(); // 读取温度 Read_Smoke(); // 读取烟雾ADC值 Filter_Data(); // 滑动平均滤波 Check_Alarm(); // 判断是否报警 Gizwits_Handle(); // 处理协议收发 HAL_Delay(100); } }代码逻辑说明:主循环每100ms执行一次采集和处理,上报不在这里直接做,而是在Gizwits_Handle里根据数据变化决定是否触发上报。这样设计有三个好处:一是CPU占用低,stm32F103在72MHz主频下跑这套逻辑占用不到20%;二是ADC采样有足够的建立时间,采集值更稳定;三是在处理函数里可以统一处理云端下发的指令。参数说明:USART2的波特率建议固定9600,这是ESP8266与stm32通信最常见的速率;USART1用115200方便快速看日志。
3. stm32传感器数据采集和第二层报警逻辑
3.1 MQ-2烟雾传感器ADC采集与温度读取的代码实现
在基于stm32的智慧厨房系统里,传感器数据的准确性直接影响报警体验。MQ-2属于半导体气敏传感器,加热电阻需要预热,刚上电的30秒内输出值会虚高,代码上要做两件事:上电后跳过前20个采样点,以及后续每次采集中做多次采样取平均。
uint16_t Read_Smoke(void) { uint32_t sum = 0; for (uint8_t i = 0; i < 16; i++) { sum += HAL_ADC_GetValue(&hadc1); // 每100us读一次ADC HAL_Delay(2); } return sum / 16; }代码逻辑说明:ADC1的通道0对应PA0引脚,连续采样16次取平均可以有效滤除瞬时干扰。MQ-2上电后加热需要时间,因此主循环里使用了状态机:前20个采样周期只推进状态,不更新上报值。注意MQ-2的ADC输出范围是0到3.3V对应0到4095,但不同批次的传感器在纯净空气中的基线电压不同,常见范围在0.3V到0.8V之间,换算成ADC值在372到993之间波动。如果发现上电之后烟雾浓度一直显示400以上,可以先看基线的实际值再决定是否需要在代码里减掉一个偏移量。
DS18B20温度读取采用单总线协议,时序要求严格,建议直接使用现成的延时函数驱动。读取过程分为初始化、跳过ROM、启动温度转换、读取暂存器四个步骤,实测精度在正负0.5摄氏度以内,完全满足厨房环境监测需求。
3.1.1 采样值到浓度的换算方式
要不要把ADC值换算成真实的ppm浓度,取决于你上报到机智云的数据点类型。如果smoke数据点用的是数值型,直接上报0到4095的原始ADC值即可,APP端把阈值范围也设成100到4000,两端都用原始值就不用做拟合。因为MQ-2的浓度曲线是非线性的,手册上给的ppm对照表在项目里很难校准。简单可靠的方案是:把ADC原始值当作“烟雾强度指示值”,阈值设置为经验值1800左右。这个值在传感器距离燃气灶30厘米、正常通风时不会触发,而用打火机不点火只放气测试时会超过2500,有明确区分度。
3.2 stm32本地报警阈值判断与继电器控制
报警逻辑要放在stm32上的根本原因是响应速度,云端判断需要经过采集、上报、云端处理、下发回控的全链路,至少1秒以上,本地判断可以在毫秒级完成。代码里用两个变量存储APP下发的阈值,当温度或烟雾超过阈值且报警开关开启时,置位报警标志,同时操作蜂鸣器、继电器和LED。
void Check_Alarm(void) { if (alarm_enable == 1) { if (temp >= temp_alarm) { alarm_status = 1; HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(FAN_GPIO_Port, FAN_Pin, GPIO_PIN_SET); } else if (smoke >= smoke_alarm) { alarm_status = 1; HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(FAN_GPIO_Port, FAN_Pin, GPIO_PIN_SET); } else { alarm_status = 0; HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(FAN_GPIO_Port, FAN_Pin, GPIO_PIN_RESET); } } else { alarm_status = 0; HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(FAN_GPIO_Port, FAN_Pin, GPIO_PIN_RESET); } }代码逻辑说明:HAL_GPIO_WritePin的三个参数分别是指定GPIO端口、指定引脚编号、设置高或低电平。蜂鸣器和继电器都是低电平触发,所以报警时写GPIO_PIN_RESET。注意报警判断不要用if和else if串行判断温度和烟雾两个条件,因为如果温度超过阈值处理了温度分支,烟雾即使也超标也不会再检查,这样烟雾报警会被温度报警覆盖。我用两个独立if语句分别判断,只要任一超标就报警,除非两个条件都不是超标才进入复位分支。
3.3 数据点状态管理与上报JSON封装
基于stm32工程接入机智云,上报的本质是把数据点的当前值按平台协议封装成JSON,通过串口发给ESP8266,ESP8266再通过TCP长连接发到云端。数据点标识需要与平台上定义完全一致,一个字符都不能差,否则云端解析不成功,现象就是设备在线但APP上控件数值不动。
void Gizwits_Report_Data(void) { // 按机智云协议格式封装数据,实际开发中直接使用平台自动生成的模板文件 Set_Report_Value(temp, 200); // 向云端上报temp数据点,值为200 Set_Report_Value(smoke, smokeRaw); // 向云端上报smoke数据点 Set_Report_Value(alarm_status, alarm_status); // 调用协议栈发送函数,将封装好的数据透传给ESP8266 }代码逻辑说明:Set_Report_Value是数据点赋值通用函数,第一个参数是数据点ID,第二个参数是实际值。机智云平台自动生成的代码中会有类似currentDataPoint结构体,把温度、烟雾、报警状态分别赋给对应成员,再调用上报函数。上报内容包含报警状态很重要,APP界面可以实时显示“正在报警”或“正常”的状态。
需要特别留意的是数据长度。数值型数据点默认用int型传输,温度可以精确到小数点后一位,但上报时如果用整数会丢失精度。机智云支持数据点的小数点位数定义,如果定的是0位小数,上报39和上报39.5在云端解析结果都是39,建议小数点位数定义1位,代码里赋值时用乘以10的方式传给协议栈。
4. 机智云平台配置与ESP8266透传的联调细节
4.1 在机智云开发者中心创建产品和数据点
进入机智云开发者中心后,选择“创建新产品”,产品名称填智慧厨房,技术方案选择“WiFi/移动网络方案”,通信方式选WiFi,数据传输协议选“机智云协议”,操作系统选择“无OS”或“FreeRTOS”。创建完成后进入产品详情页,找到“数据点”菜单,逐个添加第2章表格里定义的六个数据点。
创建数据点时要注意标识名、数据类型、读写属性的配合。标识名是设备端代码和APP端通用的唯一标识,不能修改。读写属性里“可写”表示数据点可以由APP下发指令修改,报警阈值和报警开关必须选可写;温度和烟雾浓度是设备上报值,APP不需要修改,选只读。报警状态同理,stm32本地判断后上报给APP展示,选只读。
设备端代码可以从平台“MCU开发”菜单下载,选择硬件平台为“STM32F103C8Tx”,软件平台为“Keil MDK”或“STM32CubeMX”,平台会自动生成一份包含数据点定义、协议处理、串口收发的基础工程。这份工程生成的代码里已经把物联网协议栈封装好了,只需要把我们自己写的传感器采集代码集成进去。
4.2 ESP8266固件烧录与AT指令透传
stm32接入机智云用的ESP8266模块,必须烧写机智云的GAgent固件,而不是乐鑫官方AT固件。GAgent固件在机智云官网的下载中心可以找到,文件名类似“ESP8266_GAgent”,按模组型号(ESP-01、ESP-12F等)选择对应版本。烧录工具用乐鑫官方的FLASH_DOWNLOAD_TOOLS,接线为ESP8266的TXD接USB转TTL的RXD,RXD接TXD,GND共地,GPIO0拉低进入下载模式,波特率建议115200。
烧录成功后,用串口助手打开ESP8266对应的串口,会看到GAgent的启动日志。关键看两行:一行是mac地址,另一行是产品Product Key。如果日志里没有出现Product Key,说明固件是通用版,需要在平台上把设备的MAC地址和Product Key绑定。之后做一次透传测试,在串口调试助手里发送模版里的注册包,返回success说明ESP8266与云端连接正常。
4.2.1 机智云配置是esp8266灯灭了的常见原因
“机智云配置是esp8266灯灭了”这一现象出现在模块进入配网状态或固件异常时。ESP8266模块上的红灯是电源指示,绿灯是状态指示,不同固件版本状态含义不同。遇到灯灭先检查三点:第一,模块供电是否稳定,用手摸一下模块表面温度,如果发烫说明3.3V稳压可能已经损坏,先换模块;第二,检查GPIO0是否被外部电路拉低,拉低会让模块进入下载模式,表现为灯全灭且串口无任何输出;第三,使用串口工具发送AT测试指令,无响应则说明固件损坏需要重新烧录。
4.3 stm32上报周期与流量控制的最小参数
ESP8266通过TCP长连接与机智云服务器通信,上行的数据量直接影响平台的限流策略。建议上报周期设置为3秒一次,如果厨房没有人员活动,可以拉长到5秒。更省流量的做法是“变化触发上报”:温度变化超过0.5摄氏度才上报,烟雾浓度变化超过50时才上报,报警状态只要改变就立即上报。
| 参数项 | 建议值 | 说明 |
|---|---|---|
| 基础上报周期 | 3000ms | 保证APP显示不过期 |
| 温度变化触发阈值 | 0.5摄氏度 | 低于此值不上报 |
| 烟雾浓度变化触发 | 50 ADC值 | 避免抖动导致频繁上报 |
| 报警状态上报 | 立即 | 报警和解除都要秒级到达 |
| 串口波特率 | 9600 | stm32与ESP8266通信 |
稳定型测试阶段先保持3秒周期,确认链路稳定后再加变化触发逻辑。频繁上报会消耗机智云平台给的免费流量配额,实测3秒周期连续跑8小时大约消耗2到3MB流量,控制在这个量级是安全的。上报日志里如果出现ack timeout,说明上报频率超过云端处理能力,需要拉长周期或增加变化判断。
5. 手机APP端报警阈值设置与报警开关的实现路径
5.1 基于机智云公版APP改自己的控制页面
手机APP的部分,有两种做法:一是直接使用机智云官方APP“机智云”进行设备绑定和控制,不用写一行APP代码;二是下载机智云公版APP源码,用Android Studio重新打包修改界面。工程实践上建议先两步走:联调阶段用官方APP确认数据通路正常,再改源码替换成自己的UI。
公版APP源码支持扫码绑定设备、在界面上展示数据点。数据点的位置决定展示形式:数值型和布尔型的可写数据点会自动生成输入框和开关控件,读写属性由平台决定。不过公版APP默认布局比较简陋,可以直接打开源码中对应产品的Activity页面,找到控件绑定的代码,把输入框换成SeekBar,这样阈值滑动设置体验更好。
5.2 设备配网与绑定流程
手机APP要控制基于stm32的智慧厨房设备,必须先把设备绑定到账号下。第一步,长按stm32上的按键2秒触发ESP8266进入AirLink配网模式;第二步,手机连接家庭WiFi,打开APP点击添加设备,输入WiFi密码;第三步,APP通过广播把WiFi的SSID和密码发给ESP8266,ESP8266连接到路由器后上报设备上线,APP中会弹出发现设备并完成绑定。
stm32在本地通过某个GPIO检测按键,长按超过2秒后调用协议栈的配网函数。没有按键时也可以用串口命令触发配网,在USART1的串口助手中发送指定格式的指令即可。绑定时手机和ESP8266必须处于同一个WiFi网络下,如果ESP8266已经上过网,重新上电后会自动连接之前保存的路由器,不需要重新配网。
5.2.1 手机上看不到设备时的排查步骤
依次检查三处。第一,ESP8266的绿灯状态,如果绿灯不闪说明没有连接WiFi,可能是密码错误或路由器信道不支持。第二,设备列表页面如果显示设备在线但数据不刷新,按下stm32的复位键,观察ESP8266是否重新上线。第三,确认APP账号所在服务器区域和机智云平台注册时选择的区域一致,中国版、国际版账号数据不互通。997错误码的出现代表设备绑定关系异常,到平台后台解绑后重新绑定。
5.3 数据通路验证:从手机设置阈值到stm32串口打印
手机上下发阈值和开关之后,要验证stm32确实收到了数据,可以使用USART1串口打开调试打印功能。在stm32的协议处理回调函数里加上打印语句,收到可写数据点后打印其ID和值。
// 打印日志的示例代码 printf("recv cmd: temp_alarm=%d\r\n", temp_alarm); printf("recv cmd: smoke_alarm=%d\r\n", smoke_alarm); printf("recv cmd: alarm_enable=%d\r\n", alarm_enable);代码逻辑说明:printf经过重定向后从USART1输出,用USB转TTL接电脑串口助手查看。手机APP把温度报警阈值调到60摄氏度并保存,stm32串口应立即打印一行temp_alarm=60,说明云端到设备端链路完全打通。如果手机设置了值而串口没有打印,说明ESP8266到stm32的USART2链路有问题,或者平台数据点的读写属性设置成了只读,APP没法下发。
这里有个理解上的要点:手机APP设置的是“报警阈值”和“是否开启报警”,这两个功能在设备端对应的操作完全不同。阈值设置是云端把数值写到stm32的RAM变量中;报警开关是置位或清零一个标志位。stm32的报警判断代码每100ms检查一次标志位,而不是接收完指令后只判断一次。这样设计才能保证阈值修改后立即生效。
6. 给基于stm32的智慧厨房项目收尾的三个调试技巧
6.1 数据变化触发上报的完整实现
基础上报逻辑是每3秒无条件上报一次,这在实际部署中会产生不必要的流量,而且APP界面的数值会不停跳动。优化方案是“变化超过死区才上报”,尤其针对温度和烟雾这类缓变信号,死区设置合理能让上报频率下降60%以上。
if (HAL_GetTick() - last_report_time >= 3000) { if (abs(new_temp - last_temp) >= 5 || abs(new_smoke - last_smoke) >= 50 || alarm_status != last_alarm_status) { Gizwits_Report_Data(); last_temp = new_temp; last_smoke = new_smoke; last_alarm_status = alarm_status; } last_report_time = HAL_GetTick(); }代码逻辑说明:温度死区设为0.5摄氏度,对应代码里乘以10后的5;烟雾死区设为50个ADC值;报警状态变化始终触发上报。这使得正常无人环境下可能半小时都不需要上报,一旦数据变化超过阈值立即上报。
6.2 阈值范围校验与APP输入保护
可写数据点必须做范围校验。如果APP端或黑客组包发送了一个超过传感器量程的阈值,比如温度阈值设为200摄氏度,会导致报警永不触发。在stm32收到云端下发数据后立即校验。
if (temp_alarm > 70) temp_alarm = 70; if (temp_alarm < 30) temp_alarm = 30; if (smoke_alarm > 4000) smoke_alarm = 4000; if (smoke_alarm < 100) smoke_alarm = 100;代码逻辑说明:这能防止因数据异常导致的静默失效。报警开关的布尔值也要校验,非0即1,避免误传入2导致判断逻辑混乱。这些代码需要放在协议栈回调函数的最前面,先校验再赋值给报警判断变量。
6.3 检查ESP8266的在线状态,并用状态灯提示
测试过程中ESP8266偶发掉线是所有WiFi方案的普遍问题。除了硬件上确保供电稳定,软件上应该增加一个看门狗思路:stm32和ESP8266通信时,如果连续1分钟没有收到ESP8266的反馈,就判定为掉线,此时控制报警为本地silent模式,并让LED快闪提示用户。等恢复通信后,立即上报一次完整数据,把离线期间累积的报警状态补传。最后在串口日志里抓取ESP8266发送过来的错误码,如果是8002之类与云端连接相关的错误码,优先后台看产品与设备的校验信息。
本文还有配套的精品资源,点击获取