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噪音传感器用ADCWiFi模块用串口云平台通信再用一个串口调试——这些外设需求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的指令有的固件用ATMQTTCONN有的用ATMQTTUSERCFG加ATMQTTCONN。买模块时一定要问清楚固件版本或者自己刷一个稳定的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模拟输出粉尘传感器GP2Y1010AU0F1需脉冲驱动噪音模块成品噪音传感器模块1模拟输出WiFi模块ESP8266-01S1AT固件电源5V/2A适配器1或USB供电降压模块AMS1117-3.31如果不用核心板自带稳压接线方面MQ-2的AO接STM32的PA0ADC通道0DO可以不接。GP2Y1010AU0F的Vout接PA1ADC通道1LED控制脚接PA2普通GPIO。噪音模块的AO接PA3ADC通道2。ESP8266的TX接STM32的PA10USART1_RXRX接PA9USART1_TXVCC接3.3VGND共地。电源设计的坑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.cADC初始化与采集uart.c串口初始化与中断处理esp8266.cAT指令封装与WiFi通信mqtt.cMQTT协议封装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的初始化流程如下发送ATRST复位模块等待ready发送ATCWMODE1设置为Station模式发送ATCWJAPSSID,password连接WiFi热点发送ATMQTTUSERCFG0,1,client_id,username,password,0,0,配置MQTT参数发送ATMQTTCONN0,broker_address,port,1连接MQTT服务器发送ATMQTTSUB0,topic,1订阅命令主题每一步都要等待预期的响应超时就重试。连接WiFi热点时如果密码错误或者信号太弱会返回FAIL或ERROR这时候要提示用户检查网络配置。MQTT发布数据连接成功后用ATMQTTPUB0,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), ATMQTTPUB0,\/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定义为整数单位ppmdust定义为整数单位μ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的RXSTM32的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改接AOAT指令无响应接线错误检查TX/RX交叉连接WiFi连接失败频段不对确认2.4GHz换2.4GHz热点MQTT连接失败ClientID重复检查设备ID修改ClientID云平台无数据主题错误检查发布主题修正主题格式数据断断续续信号弱查看RSSI靠近路由器4.5 独家避坑经验坑一ESP8266的AT固件版本混乱。不同批次的ESP8266-01S可能刷了不同的AT固件指令集不兼容。我建议拿到模块后先发ATGMR查看版本然后去官网下载对应的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卡模块本地存储历史数据加一个继电器模块浓度超标时自动启动排风扇加一个蜂鸣器本地报警。这些扩展都不难核心链路跑通后加外设就是复制粘贴的工作。