1. 项目缘起与整体设计思路
1.1 这个项目到底在做什么
先把这个项目的核心讲清楚。标题里提到的“STM32环境检测(烟雾粉尘噪音)物联网WiFi云平台”,拆开来看是四个关键词:STM32、环境检测、烟雾粉尘噪音、WiFi云平台。合在一起,就是一套以STM32单片机为主控,外接烟雾、粉尘、噪音三类传感器,通过WiFi模块把数据上传到云平台,实现远程环境监测的完整系统。
这类项目在实际场景里非常常见。比如工厂车间需要监测粉尘浓度和噪音水平,保障工人健康;仓库需要监测烟雾浓度,做早期火灾预警;学校实验室、图书馆需要监测噪音,维持安静环境;甚至家庭场景里,厨房烟雾监测、卧室噪音监测都有实际需求。传统做法是人工巡检或者本地仪表显示,数据不连续、无法远程查看、无法历史追溯。这套系统解决的就是这三个痛点:实时性、远程化、数据可追溯。
适合谁来参考?如果你正在做嵌入式课程设计、毕业设计、电子竞赛作品,或者想入门物联网开发,这个项目是一个非常好的练手载体。它涉及单片机外设驱动、传感器数据采集、串口通信、WiFi联网、云平台对接、数据可视化等多个环节,覆盖面广但每个环节的难度都可控。即使你之前只点亮过LED,跟着思路一步步来也能跑通。
1.2 为什么选STM32而不是其他主控
主控选型是整个项目的第一道决策。市面上常见的选项有51单片机、Arduino、ESP32、STM32等。我选STM32的理由很直接:
- 外设资源丰富:STM32F103系列至少带3个USART、2个SPI、2个I2C、多个ADC通道和定时器。烟雾传感器用ADC采集,粉尘传感器用串口或ADC,噪音传感器用ADC,WiFi模块用串口,云平台通信再用一个串口调试——这些外设需求51单片机根本扛不住,Arduino虽然能凑合但资源也紧张。
- ADC精度够用:STM32F103的12位ADC,分辨率是4096级,对于烟雾和噪音这种模拟量采集完全够用。51单片机多数是8位ADC甚至没有内置ADC,需要外挂芯片,增加复杂度。
- 生态成熟:标准库和HAL库资料齐全,网上能找到大量参考代码。对于新手来说,遇到问题能搜到答案,这一点比性能参数更重要。
- 成本可控:一块STM32F103C8T6最小系统板十几块钱,比Arduino Uno还便宜,性能却强不少。
ESP32虽然自带WiFi,看起来更省事,但它的ADC线性度一直被诟病,而且如果项目要求同时处理多路传感器加WiFi通信,ESP32的单核任务调度会有点吃力。STM32加独立WiFi模块的方案,分工更清晰,调试也更容易定位问题。
1.3 传感器选型的取舍逻辑
三类传感器里,每一个都有多种技术路线可选,我逐一说明我的选择和理由。
烟雾检测:常见方案有MQ-2、MQ-5、MQ-7等半导体气敏传感器,以及红外光电式烟雾传感器。MQ系列便宜、接口简单、模拟输出,但缺点是选择性差,对酒精、液化气等都有响应,而且需要预热。红外光电式精度高、误报少,但价格贵、接口复杂。这个项目我选MQ-2,理由是成本低、资料多、模拟输出直接接STM32的ADC即可,适合学习和原型验证。如果要做产品级,建议换红外方案。
粉尘检测:主流方案是GP2Y1010AU0F(夏普光学粉尘传感器)和PM2.5激光传感器(如攀藤系列)。夏普这款便宜、驱动简单,但精度一般,只能测个大概趋势。激光传感器精度高、能输出PM1.0/PM2.5/PM10,但价格贵、需要串口通信、协议解析稍复杂。这个项目我选夏普GP2Y1010AU0F,因为它只需要一个ADC通道加一个数字引脚控制红外LED,代码量小,适合快速出效果。如果你要做空气质量监测站级别的项目,建议上激光传感器。
噪音检测:常见方案是驻极体麦克风加放大电路,或者成品噪音模块(如KY-038)。驻极体麦克风输出的是毫伏级信号,需要运放放大到STM32的ADC量程(0-3.3V)。成品模块内部已经做好了放大和整形,直接输出模拟电压,接线简单。我选成品噪音模块,省去运放电路设计和调试的麻烦。但要注意,成品模块的输出电压范围和灵敏度差异很大,买回来第一件事是用示波器或者万用表测一下实际输出,再决定ADC的参考电压和分压电路。
1.4 WiFi模块与云平台的搭配
WiFi模块选ESP8266还是ESP32?如果只是做数据透传,ESP8266足够,价格也更便宜。ESP8266通过AT指令和STM32串口通信,STM32发AT指令,ESP8266执行联网、发数据等操作。这种方式的优点是STM32端代码简单,不需要处理TCP/IP协议栈;缺点是AT指令的响应解析比较繁琐,遇到网络异常时错误处理麻烦。
云平台方面,常见的有阿里云IoT、腾讯云IoT、OneNET、巴法云、Blinker等。选择云平台要考虑几个因素:是否免费、接入难度、数据可视化能力、API是否友好。对于个人学习项目,我建议选支持MQTT协议、有免费额度、提供Web可视化面板的平台。MQTT协议轻量、适合嵌入式设备,而且大多数云平台都支持。具体选哪家,可以根据你手头的资料和教程来定,核心是跑通“设备上报数据→云平台存储→Web端展示”这条链路。
注意:云平台的选择不要贪多,先把一个平台跑通,再考虑多平台兼容。我见过不少新手同时注册了五六个平台,结果每个都只走到“设备上线”就卡住了。
1.5 整体架构与数据流
系统的整体架构可以分成四层:
- 感知层:MQ-2烟雾传感器、GP2Y1010AU0F粉尘传感器、噪音模块,负责把物理量转换成电信号。
- 控制层:STM32F103主控,负责ADC采集、数据处理、逻辑判断、串口通信。
- 通信层:ESP8266 WiFi模块,负责把STM32的数据通过MQTT协议发到云平台。
- 应用层:云平台+Web/App端,负责数据存储、可视化展示、报警推送。
数据流是这样的:传感器输出模拟电压→STM32的ADC采集→STM32做滤波和换算→通过串口发给ESP8266→ESP8266通过WiFi发到云平台→云平台存储并展示→用户在Web端查看。
这个架构的好处是每一层职责清晰,调试时可以分层排查。比如数据不对,先看传感器输出,再看ADC读数,再看串口发送,最后看云平台接收。哪一层出问题就修哪一层,不会一团乱麻。
2. 核心细节解析与实操要点
2.1 烟雾传感器MQ-2的驱动细节
MQ-2的驱动看起来简单——接电源、接ADC、读值,但实际有几个坑必须提前说清楚。
预热时间:MQ-2内部是二氧化锡气敏材料,需要加热到一定温度才能正常工作。冷启动时读数会从高到低缓慢变化,通常需要预热24小时以上才能达到稳定状态。实际项目中,我建议至少预热5-10分钟再开始采集,否则初始数据会偏高很多。如果你要做演示,可以提前一天给传感器通电预热。
负载电阻选择:MQ-2模块上通常有一个可调电阻,用来调节负载电阻RL。RL的大小直接影响输出电压范围和灵敏度。RL越大,灵敏度越高,但输出阻抗也越大,容易受干扰。一般模块出厂默认的RL在10K左右,如果你发现读数范围太窄或者太宽,可以微调这个电阻。我的经验是,在洁净空气中让输出电压落在1.0-1.5V之间比较合适,这样烟雾出现时电压有明显上升空间。
ADC参考电压:STM32的ADC参考电压默认是3.3V,但如果你用USB供电,实际VDD可能在3.2-3.4V之间波动。这个波动会直接影响ADC读数。如果对精度要求高,建议用外部基准电压芯片(如REF3033)提供稳定的3.3V参考。如果只是做趋势监测,用内部参考也够用,但要在代码里做软件校准。
浓度换算:MQ-2输出的是电压值,要换算成ppm浓度需要标定。标定方法是用已知浓度的标准气体,记录不同浓度下的电压值,拟合出曲线。没有标准气体怎么办?可以用酒精棉球靠近传感器,观察电压变化范围,大致估算灵敏度。但要注意,这种粗略标定只能用于定性判断,不能用于精确测量。
// MQ-2 ADC采集示例(HAL库) #define MQ2_ADC_CHANNEL ADC_CHANNEL_0 #define MQ2_ADC_MAX 4095.0f #define VREF 3.3f float read_mq2_voltage(void) { HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 100); uint16_t adc_value = HAL_ADC_GetValue(&hadc1); HAL_ADC_Stop(&hadc1); return (adc_value / MQ2_ADC_MAX) * VREF; }2.2 粉尘传感器GP2Y1010AU0F的时序控制
GP2Y1010AU0F的驱动比MQ-2复杂,因为它需要一个脉冲驱动信号来控制内部红外LED的开关。具体时序是:拉低LED控制引脚→延时280微秒→读取ADC→延时40微秒→拉高LED控制引脚→延时9680微秒,然后循环。这个时序不能错,否则读数会不稳定。
为什么需要脉冲驱动:传感器内部的红外LED如果一直亮着,会发热并影响光学检测精度。用脉冲驱动可以让LED间歇工作,减少发热,同时降低功耗。280微秒的延时是让LED稳定发光,40微秒是让光敏管响应,9680微秒是让LED冷却。整个周期是10毫秒,对应100Hz的采样率。
输出特性:GP2Y1010AU0F的输出电压和粉尘浓度大致呈线性关系,但有个基础电压(洁净空气中约0.9V)。浓度换算公式通常是:浓度(μg/m³) = (输出电压 - 基础电压) / 斜率。斜率因传感器个体差异而不同,典型值在0.005-0.01V/(μg/m³)之间。我建议先用洁净空气测基础电压,再用香烟烟雾测一个高浓度点,两点确定一条直线,做粗略标定。
常见问题:很多人反映这个传感器读数飘忽不定,原因通常是:电源纹波大、LED驱动时序不对、或者传感器镜头脏了。电源方面,建议在传感器VCC和GND之间并一个100μF电解电容加一个0.1μF陶瓷电容,滤除高频和低频噪声。镜头用棉签蘸酒精轻轻擦拭,注意不要刮花。
// GP2Y1010AU0F 驱动示例 #define GP2Y_LED_PIN GPIO_PIN_1 #define GP2Y_LED_PORT GPIOA float read_dust_voltage(void) { HAL_GPIO_WritePin(GP2Y_LED_PORT, GP2Y_LED_PIN, GPIO_PIN_RESET); delay_us(280); HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 10); uint16_t adc_value = HAL_ADC_GetValue(&hadc1); HAL_ADC_Stop(&hadc1); delay_us(40); HAL_GPIO_WritePin(GP2Y_LED_PORT, GP2Y_LED_PIN, GPIO_PIN_SET); delay_us(9680); return (adc_value / 4095.0f) * 3.3f; }2.3 噪音模块的采集与换算
噪音模块输出的是模拟电压,但要注意几个问题。
输出范围:不同厂家的噪音模块输出范围差异很大。有的模块输出0-5V,直接接STM32的ADC会烧引脚(STM32的ADC输入最大3.3V)。有的模块输出0-3.3V,可以直接接。买回来第一件事是看说明书或者用万用表测输出范围。如果是0-5V,必须用电阻分压,比如两个10K电阻串联,从中间取电压,这样5V就变成2.5V,安全范围。
噪音的分贝换算:模块输出的是电压,要换算成分贝值需要知道模块的灵敏度和参考电压。通常模块说明书会给出一个公式,比如dB = 20 * log10(Vout / Vref) + K,其中Vref是参考电压,K是校准常数。如果没有说明书,可以用手机的分贝APP做对比校准:在安静环境下记录模块输出电压和手机显示的分贝值,再在嘈杂环境下记录一组,两点确定公式。
采样频率:噪音是快速变化的信号,ADC采样率要足够高才能捕捉峰值。STM32的ADC在12位分辨率下最快约1MHz,但实际用的时候要考虑串口传输和处理的耗时。我建议噪音采样率至少1kHz,采集1秒的数据(1000个点),取最大值或RMS值作为这一秒的代表值。这样既能反映噪音水平,又不会数据量太大。
注意:噪音模块的输出是交流信号叠加直流偏置,ADC读到的值在偏置电压上下波动。计算RMS时要先减去偏置电压,再平方、平均、开方。如果直接对ADC原始值做RMS,结果会包含直流分量,偏大很多。
2.4 ESP8266的AT指令通信
ESP8266通过AT指令和STM32通信,STM32是主机,ESP8266是从机。整个通信流程包括:复位模块→设置WiFi模式→连接热点→设置MQTT参数→连接云平台→发布数据。
AT指令的坑:ESP8266的AT固件版本很多,不同版本的指令集有差异。比如连接MQTT的指令,有的固件用AT+MQTTCONN,有的用AT+MQTTUSERCFG加AT+MQTTCONN。买模块时一定要问清楚固件版本,或者自己刷一个稳定的AT固件。我建议用安信可官方的AT固件,版本选1.7.x以上,MQTT功能比较完善。
串口通信的可靠性:STM32和ESP8266之间的串口通信容易受干扰,尤其是WiFi发射时会产生电磁噪声。我遇到过ESP8266一发射数据,STM32就收到乱码的情况。解决办法是:串口线尽量短、加屏蔽层、在TX/RX线上串22Ω电阻、电源加磁珠和电容滤波。另外,STM32的串口接收要用中断或DMA,不要用轮询,否则会丢数据。
超时与重试:AT指令的响应时间不确定,尤其是联网和连接云平台时,可能几秒钟才返回。STM32端要设置合理的超时时间,比如5秒。如果超时,先重发一次,连续三次失败就复位ESP8266重新初始化。这个重试机制在实际部署中非常重要,因为WiFi网络偶尔会抖动。
// ESP8266 AT指令发送与等待响应示例 #define ESP8266_TIMEOUT 5000 uint8_t esp8266_send_cmd(char *cmd, char *expected, uint8_t retry) { for (uint8_t i = 0; i < retry; i++) { HAL_UART_Transmit(&huart2, (uint8_t *)cmd, strlen(cmd), 1000); if (wait_for_response(expected, ESP8266_TIMEOUT) == 0) { return 0; // 成功 } HAL_Delay(500); } return 1; // 失败 }2.5 云平台对接与数据上报
云平台对接的核心是MQTT协议。MQTT是一种发布/订阅模式的轻量级协议,设备作为客户端,连接到云平台的MQTT服务器(Broker),然后向特定主题(Topic)发布消息。
主题设计:主题的设计要清晰,方便后续管理和扩展。我通常这样设计:
- 上报数据主题:
/device/{device_id}/data - 报警主题:
/device/{device_id}/alarm - 命令下发主题:
/device/{device_id}/cmd
其中{device_id}是设备的唯一标识,可以用STM32的芯片ID或者自定义字符串。主题层级用/分隔,这是MQTT的惯例。
数据格式:上报的数据用JSON格式,可读性好,云平台解析也方便。比如:
{ "smoke": 125, "dust": 35, "noise": 58, "timestamp": 1234567890 }其中smoke是烟雾ADC原始值或换算后的浓度,dust是粉尘浓度,noise是分贝值,timestamp是时间戳。时间戳可以用STM32的RTC提供,或者由云平台在接收时打上。
上报频率:上报频率要根据实际需求定。环境监测通常不需要太高频率,1秒一次或者5秒一次都行。频率太高会消耗流量和云平台资源,频率太低会漏掉突发变化。我建议正常情况5秒一次,检测到异常时自动提高到1秒一次,这样兼顾了功耗和实时性。
断线重连:网络不稳定时MQTT会断线,设备要能自动重连。ESP8266的AT固件通常支持自动重连,但STM32端也要做检测。我的做法是:每次上报数据前检查MQTT连接状态,如果断开就先重连再上报。另外,云平台通常有心跳机制,设备要定期发送PING包,否则会被踢下线。
3. 实操过程与核心环节实现
3.1 硬件连接与电源设计
先列一下完整的硬件清单:
| 组件 | 型号 | 数量 | 备注 |
|---|---|---|---|
| 主控 | STM32F103C8T6最小系统板 | 1 | 核心板 |
| 烟雾传感器 | MQ-2模块 | 1 | 模拟输出 |
| 粉尘传感器 | GP2Y1010AU0F | 1 | 需脉冲驱动 |
| 噪音模块 | 成品噪音传感器模块 | 1 | 模拟输出 |
| WiFi模块 | ESP8266-01S | 1 | AT固件 |
| 电源 | 5V/2A适配器 | 1 | 或USB供电 |
| 降压模块 | AMS1117-3.3 | 1 | 如果不用核心板自带稳压 |
接线方面,MQ-2的AO接STM32的PA0(ADC通道0),DO可以不接。GP2Y1010AU0F的Vout接PA1(ADC通道1),LED控制脚接PA2(普通GPIO)。噪音模块的AO接PA3(ADC通道2)。ESP8266的TX接STM32的PA10(USART1_RX),RX接PA9(USART1_TX),VCC接3.3V,GND共地。
电源设计的坑:ESP8266在发射数据时瞬间电流可达300mA,如果和STM32共用一个小功率的3.3V稳压器,会导致电压跌落,STM32复位。我建议ESP8266单独用一个AMS1117-3.3供电,输入端并一个470μF电解电容,输出端并一个100μF电解电容加0.1μF陶瓷电容。STM32可以用另一个稳压器或者核心板自带的。两个稳压器的地要连在一起。
注意:MQ-2的加热丝需要5V供电,电流约150mA。如果整个系统用USB供电,总电流可能超过500mA,有些电脑的USB口会限流。建议用独立的5V/2A适配器供电。
3.2 STM32端软件框架
STM32端的代码用HAL库开发,整体框架分成几个模块:
main.c:主循环,调度各个任务adc.c:ADC初始化与采集uart.c:串口初始化与中断处理esp8266.c:AT指令封装与WiFi通信mqtt.c:MQTT协议封装sensor.c:传感器数据处理与换算
主循环的调度逻辑是:每100毫秒采集一次传感器数据,每5秒上报一次云平台,每1秒检查一次WiFi连接状态。用HAL_GetTick()做时间基准,不用delay阻塞,这样各个任务互不干扰。
// 主循环调度示例 uint32_t last_sample = 0, last_report = 0, last_check = 0; while (1) { uint32_t now = HAL_GetTick(); if (now - last_sample >= 100) { sample_sensors(); last_sample = now; } if (now - last_report >= 5000) { report_to_cloud(); last_report = now; } if (now - last_check >= 1000) { check_wifi_status(); last_check = now; } }3.3 传感器数据滤波与校准
原始ADC数据有噪声,直接上报会看到数值跳动。我通常用两种滤波:硬件滤波和软件滤波。
硬件滤波:在每个传感器的模拟输出和GND之间并一个0.1μF陶瓷电容,滤除高频噪声。如果噪声还是大,再加一个10μF电解电容。注意电容要尽量靠近STM32的ADC引脚,引线越短越好。
软件滤波:我用滑动平均滤波,取最近10次采样的平均值。这样既能平滑数据,又不会太滞后。对于噪音这种快速变化的信号,滑动平均会削峰,所以我用最大值滤波:取最近10次采样的最大值作为代表值。
// 滑动平均滤波示例 #define FILTER_SIZE 10 float filter_buf[FILTER_SIZE]; uint8_t filter_idx = 0; float moving_average(float new_val) { filter_buf[filter_idx] = new_val; filter_idx = (filter_idx + 1) % FILTER_SIZE; float sum = 0; for (uint8_t i = 0; i < FILTER_SIZE; i++) { sum += filter_buf[i]; } return sum / FILTER_SIZE; }校准:烟雾和粉尘传感器需要校准基础电压。校准方法是在洁净空气中采集100个样本,取平均值作为基础电压。这个值存在STM32的Flash里,掉电不丢失。每次上电时读取,如果Flash里没有(第一次使用),就重新校准并写入。
3.4 WiFi联网与MQTT连接流程
ESP8266的初始化流程如下:
- 发送
AT+RST复位模块,等待ready - 发送
AT+CWMODE=1设置为Station模式 - 发送
AT+CWJAP="SSID","password"连接WiFi热点 - 发送
AT+MQTTUSERCFG=0,1,"client_id","username","password",0,0,""配置MQTT参数 - 发送
AT+MQTTCONN=0,"broker_address",port,1连接MQTT服务器 - 发送
AT+MQTTSUB=0,"topic",1订阅命令主题
每一步都要等待预期的响应,超时就重试。连接WiFi热点时,如果密码错误或者信号太弱,会返回FAIL或ERROR,这时候要提示用户检查网络配置。
MQTT发布数据:连接成功后,用AT+MQTTPUB=0,"topic","data",0,0发布数据。data是JSON字符串,注意要转义引号。比如:
char json[128]; snprintf(json, sizeof(json), "{\"smoke\":%d,\"dust\":%d,\"noise\":%d}", smoke_val, dust_val, noise_val); char cmd[256]; snprintf(cmd, sizeof(cmd), "AT+MQTTPUB=0,\"/device/001/data\",\"%s\",0,0\r\n", json); HAL_UART_Transmit(&huart2, (uint8_t *)cmd, strlen(cmd), 1000);3.5 云平台配置与可视化
云平台的配置步骤因平台而异,但核心流程差不多:
- 注册账号,创建产品
- 在产品下创建设备,获取设备ID和密钥
- 定义数据模板(数据点),比如smoke、dust、noise三个属性
- 配置MQTT连接参数(Broker地址、端口、ClientID、Username、Password)
- 在Web端创建可视化面板,绑定数据点
数据模板的定义:数据模板决定了云平台如何解析设备上报的数据。如果上报的是JSON,数据模板要定义每个字段的名称、类型、单位。比如smoke定义为整数,单位ppm;dust定义为整数,单位μg/m³;noise定义为整数,单位dB。
可视化面板:大多数云平台提供拖拽式的仪表盘编辑器,可以添加折线图、仪表盘、数字显示等控件。我通常放三个仪表盘显示实时值,一个折线图显示历史趋势,再加一个报警列表显示异常记录。
报警规则:在云平台设置报警阈值,比如烟雾浓度超过200ppm、粉尘超过100μg/m³、噪音超过70dB时触发报警。报警方式可以是平台内通知、邮件、短信等。免费平台通常只支持平台内通知,如果需要短信报警,可能要付费或者用第三方服务。
3.6 系统联调与数据验证
联调是整个项目最耗时的环节。我的联调顺序是:
- 单独测试每个传感器:用串口打印ADC原始值,观察在洁净空气和模拟污染源下的变化。MQ-2用打火机的气体(不点火)靠近,看读数是否上升。粉尘传感器用香烟烟雾,看读数是否上升。噪音模块对着说话,看读数是否变化。
- 测试ESP8266联网:用串口助手手动发AT指令,确认能连接WiFi和MQTT服务器。这一步不要用STM32,直接用电脑串口助手发指令,排除STM32代码的问题。
- 测试STM32与ESP8266通信:STM32发AT指令,串口助手监听ESP8266的响应,确认指令和响应匹配。
- 测试完整链路:STM32采集数据→ESP8266上报→云平台接收。在云平台的设备日志里查看上报的数据,确认格式和数值正确。
- 压力测试:让系统连续运行24小时,观察是否有断线、数据丢失、数值漂移等问题。
注意:联调时一定要有耐心,一个问题一个问题解决。我见过新手同时改代码和硬件,结果出了问题不知道是软件还是硬件的原因。正确的做法是每次只改一个变量,改完验证,确认无误再改下一个。
4. 常见问题与排查技巧实录
4.1 传感器读数异常排查
问题一:MQ-2读数一直很高,降不下来
原因通常是预热时间不够。MQ-2冷启动时读数会从高到低缓慢下降,需要几分钟到几十分钟才能稳定。如果等了很久还是高,可能是负载电阻调得太小,或者传感器中毒了(长期暴露在高浓度气体中)。解决办法:先预热10分钟,如果还高,调大负载电阻,再不行就换传感器。
问题二:粉尘传感器读数飘忽,没有规律
原因可能是LED驱动时序不对、电源纹波大、或者镜头脏了。排查步骤:先用示波器看LED控制脚的波形,确认280μs和9680μs的延时准确;再用万用表测VCC电压,确认在5V±0.1V范围内;最后用棉签清洁镜头。如果都正常,可能是传感器本身质量问题,换一个试试。
问题三:噪音模块读数始终不变
原因可能是模块输出是数字信号而不是模拟信号。有些噪音模块同时有AO和DO输出,AO是模拟,DO是数字(超过阈值输出高电平)。如果你接的是DO,读数只有0和1。检查接线,确认接的是AO。另外,有些模块需要外部供电才能工作,检查VCC和GND是否接好。
4.2 WiFi连接失败排查
问题一:AT指令无响应
先检查串口接线:STM32的TX接ESP8266的RX,STM32的RX接ESP8266的TX,不要接反。再检查波特率:ESP8266默认波特率通常是115200,但有些固件是9600。用串口助手手动发AT,看是否返回OK。如果不返回,尝试不同的波特率。还要检查电源:ESP8266需要3.3V供电,5V会烧毁。
问题二:连接WiFi热点失败
检查SSID和密码是否正确,注意大小写和特殊字符。如果热点是5GHz频段,ESP8266不支持,必须用2.4GHz。如果信号太弱,靠近路由器再试。如果路由器开启了MAC地址过滤,把ESP8266的MAC地址加入白名单。
问题三:MQTT连接失败
检查Broker地址和端口是否正确。有些云平台的MQTT端口不是默认的1883,而是自定义端口。检查ClientID是否重复:如果两个设备用同一个ClientID,后连接的会把先连接的踢下线。检查Username和Password是否正确,有些平台用密钥做密码,注意不要复制错。
4.3 数据上报异常排查
问题一:云平台收不到数据
先在云平台的设备日志里看是否有连接记录。如果没有,说明MQTT没连上,回到上一步排查。如果有连接记录但没有数据,检查发布主题是否正确,有些平台对主题格式有严格要求。检查数据格式是否符合数据模板的定义,比如模板定义smoke是整数,你发的是浮点数,平台可能解析失败。
问题二:数据数值不对
先在STM32端用串口打印原始ADC值和换算后的值,确认STM32端数据正确。如果STM32端正确但云平台不对,检查JSON格式是否正确,特别是引号和逗号。如果JSON格式错误,云平台可能解析出默认值或空值。
问题三:数据断断续续
检查WiFi信号强度,如果RSSI低于-80dBm,连接不稳定。检查上报频率是否太高,超过云平台的限制会被限流。检查STM32的串口发送是否有阻塞,如果主循环被其他任务占用太久,上报会延迟。
4.4 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| MQ-2读数偏高 | 预热不足 | 等待10分钟观察 | 延长预热时间 |
| 粉尘读数飘忽 | 电源纹波大 | 示波器测VCC | 加滤波电容 |
| 噪音读数不变 | 接错引脚 | 检查AO/DO | 改接AO |
| AT指令无响应 | 接线错误 | 检查TX/RX | 交叉连接 |
| WiFi连接失败 | 频段不对 | 确认2.4GHz | 换2.4GHz热点 |
| MQTT连接失败 | ClientID重复 | 检查设备ID | 修改ClientID |
| 云平台无数据 | 主题错误 | 检查发布主题 | 修正主题格式 |
| 数据断断续续 | 信号弱 | 查看RSSI | 靠近路由器 |
4.5 独家避坑经验
坑一:ESP8266的AT固件版本混乱。不同批次的ESP8266-01S可能刷了不同的AT固件,指令集不兼容。我建议拿到模块后先发AT+GMR查看版本,然后去官网下载对应的AT指令手册。如果版本太老,自己刷一个新固件,刷固件的方法网上有详细教程。
坑二:STM32的ADC多通道采集冲突。STM32的ADC1有多个通道,但同一时间只能采集一个通道。如果代码里同时启动多个通道的采集,会互相干扰。正确做法是用扫描模式,配置规则组,按顺序采集多个通道。或者用DMA搬运,避免CPU干预。
坑三:JSON字符串的转义问题。在C语言里拼接JSON字符串时,引号需要转义,比如\"。如果忘记转义,编译会报错。另外,JSON里的逗号和冒号必须是英文半角,中文全角会导致解析失败。我建议用sprintf或snprintf拼接,不要手动拼字符串。
坑四:云平台的免费额度限制。有些云平台每月只有100万条消息的免费额度,如果上报频率太高,几天就用完了。计算一下:5秒上报一次,一天是17280条,一个月是51.8万条。如果三个数据点分开上报,就是155万条,超了。解决办法是把三个数据打包成一条JSON上报,或者降低上报频率。
坑五:STM32的Flash写入寿命。如果频繁把校准值写入Flash,会缩短Flash寿命。STM32F103的Flash擦写次数约1万次,如果每天写10次,三年就坏了。解决办法是只在校准值变化时才写入,或者用备份寄存器(BKP)存储,BKP由VBAT供电,掉电不丢失,而且没有擦写次数限制。
这个项目后续还可以这样扩展:加一个OLED显示屏,本地显示实时数据;加一个SD卡模块,本地存储历史数据;加一个继电器模块,浓度超标时自动启动排风扇;加一个蜂鸣器,本地报警。这些扩展都不难,核心链路跑通后,加外设就是复制粘贴的工作。