前阵子有朋友跟我聊说想做一个能监测室内烟雾、粉尘和噪音的小设备数据能传到手机上看还要能报警。我第一反应就是别想复杂了STM32 几个传感器 WiFi模块 云平台这套组合就是最经典的方案。真正做完你会发现难点不在“能不能测”而在于“测出来的数到底可不可信”“数据能不能稳定送到云端”。这篇文章把我从硬件选型、接线、STM32采集代码、ESP8266上云到云平台告警的完整过程整理出来顺便把我在调试中踩过的三个大坑也一起写了给想复刻这个项目的人一条能直接走通的路。整个项目做的事情很简单用STM32采集三路模拟传感器信号软件滤波和换算之后通过ESP8266 WiFi模块把打包好的JSON数据定时上报到云平台然后在云平台上看到实时曲线、历史数据和告警通知。适合正在做物联网课设、嵌入式入门项目、智能家居DIY或者想快速验证环境监测产品原型的朋友参考。1. 先定整体架构MCU采集 WiFi透传 云平台这套组合怎么搭很多新手一上来就想用Linux开发板加Python觉得生态好、写起来快。真到做环境监测这种设备端项目你会发现MCU才是主流选择。不是Linux板不能用而是场景不匹配。1.1 为什么采集端用STM32而不是Linux开发板环境监测设备通常需要7x24小时通电运行采集频率不高但要求稳定、功耗低、成本可控。拿STM32F103C8T6这种最普通的MCU来说整板工作电流也就几十毫安级别而Linux单板随便跑个系统就是几百毫安起。工业现场、配电箱、壁挂设备里功耗就是硬指标。另外MCU上电几百毫秒就能进主循环Linux板光系统启动就要几十秒中途断电重启一次数据断档就是一大段。还有成本。STM32F103C8T6核心板市场上十多元就能搞定加上传感器和外设整套硬件成本压到六七十元毫无压力。Linux板动辄一两百元起批量部署的时候差距非常明显。当然如果你后续要做摄像头图像识别、跑神经网络推理这种重计算任务那Linux板是合理的。但纯环境数据采集MCU方案是更务实的选择。STM32资源也够12位ADC采集模拟传感器多路UART和ESP8266通信I2C接OLED显示屏GPIO控制继电器这个项目恰好把F103的常用外设都用上了。1.2 整条数据链路拆解与模块划分这套系统的数据流向我习惯按四个环节拆开看传感层烟雾传感器、粉尘传感器、噪音传感器分别输出模拟电压。烟雾和粉尘输出的是随浓度缓慢变化的直流电压噪音模块输出的是一路交流波形处理方式不同后面会细说。采集层STM32的ADC把三路模拟信号转成数字量经过软件滤波、数据换算得到电压值、浓度估算值和分贝数值。传输层STM32通过串口给ESP8266下发AT指令ESP8266连接WiFi、建立TCP连接把JSON数据POST到云平台接口。平台层云平台上创建设备、设置数据解析规则就能看到实时数据和曲线再配好告警规则超阈值就推送通知。这四个环节是串联的哪个环节出了问题整条链路就断了。所以调试的时候一定分模块验证先确认传感器输出有反应再确认ADC读数在跳再确认串口能收到数据最后看云平台是否收到。不要一上来就盯着某一端猜这是我做了几个物联网项目之后最深刻的体会。1.3 硬件清单与成本估算我在这个项目里用的硬件清单如下都是很容易买到的通用型号模块型号/类型作用说明主控板STM32F103C8T6最小系统板采集、逻辑处理板载AMS1117-3.3稳压IO引出齐全WiFi模块ESP-01S串口转WiFiAT指令固件成本低、资料多烟雾传感器MQ-2模块检测烟雾/可燃气体模拟量输出带比较器、电位器粉尘传感器GP2Y1010AU0F模块检测粉尘浓度需要MCU提供LED脉冲驱动噪音传感器驻极体麦克风放大模块MAX4466/MAX9814类采集环境声压输出交流波形增益可调显示可选OLED 0.96寸 I2C本地实时显示方便现场调试这套硬件总成本大约在60到80元之间具体取决于模块的做工和运费。如果你手里已经有STM32核心板那后面几个传感器模块加起来也就四五十元。预算很亲民。2. 烟雾、粉尘、噪音三路传感器的选型与接线细节传感器是整个系统的“眼睛”。我用过几套不同方案的传感器最后定下来的这三款是在性能、成本、接线难度三者之间权衡后的结果。2.1 三路传感器的选型思路与参数对照先说烟雾传感器。MQ-2能检测液化气、丁烷、丙烷、烟雾等多种可燃气体响应速度快输出是模拟电压非常适合做定性告警和粗略的浓度指示。它的核心是一个加热丝和氧化锡气敏材料气体浓度升高时,材料电导率变化模块输出电压跟着变化。缺点是功耗相对大因为要保持加热温度。粉尘传感器我选了GP2Y1010AU0F方案的模块。它内部有一个红外LED和一个光电晶体管通过检测空气中的颗粒物反射光来判断粉尘浓度。这个芯片本身对驱动时序有严格要求LED必须以10ms周期、0.32ms脉宽的方式脉冲点亮MCU要在LED亮起后的特定窗口内采样输出电压。很多模块已经把外围电路做好了你只需要接一个IO口来控制LED引脚。噪音传感器用的是驻极体麦克风放大模块这类模块以MAX4466、MAX9814为代表。它们的输出是跟随声音波动的交流电压信号幅度通常在几十到几百毫伏量级。通过计算这个交流信号的RMS电压可以换算成一个相对的分贝值。传感器输出信号供电ADC处理方式主要坑点MQ-2烟雾0~VCC 模拟直流5V加热直接采样电压做阈值告警预热漂移、输出可能超3.3VGP2Y1010粉尘0.9V~约3.6V 直流5VLED脉冲驱动后采样时序不对读数恒为0或偏高MAX4466噪音交流波形3.3~5V采样后软件算RMS增益太大会削波失真2.2 接线引脚与供电设计这里藏着多数翻车点接线前先说一个最容易踩的坑STM32的ADC输入范围是0到3.3V而MQ-2模块如果按5V供电它的模拟输出范围理论上可以到接近VCC直接接PA0可能超量程。GP2Y1010的输出最大也可能超过3.3V。不能想当然地直连。我采用的接线方案如下STM32引脚连接对象说明PA0ADC1_IN0MQ-2模块AO经分压电阻5V供电时用10kΩ5.1kΩ分压或者改给模块采样部分供3.3VPA1ADC1_IN1GP2Y1010模块Vout最好也做分压限幅PA2ADC1_IN2MAX4466模块OUT幅度小直连一般没问题PB0GP2Y1010模块LED驱动引脚由MCU输出10ms周期方波脉冲PA9/PA10USART1ESP8266 RX/TX接ESP8266前确认电平匹配PA2/PA3USART2调试串转USB打印日志强烈建议保留供电方面我把5V和3.3V分开规划。STM32核心板通过USB或外部5V供电板载稳压到3.3V。ESP8266对供电最挑剔WiFi发射瞬间电流能达到300mA如果和STM32共用一个3.3V LDO电压容易被拉低导致模块重启。我的做法是给ESP8266单独用一个AMS1117-3.3稳压模块供电并在ESP8266的VCC和GND之间并一个大电容比如470uF电解电容实测能显著减少重启问题。GP2Y1010的LED引脚驱动也要注意电流能力STM32 GPIO直接推LED是没问题的但如果模块说明里要求LED驱动波形就需要用GPIO输出脉冲别图省事把LED引脚直接接高电平。2.3 模拟信号进ADC前的电平处理模拟信号进ADC之前我做了两个处理第一是限幅。对MQ-2和GP2Y1010如果模块按5V供电输出超过3.3V的概率存在稳妥的做法是在ADC引脚前加电阻分压。MQ-2我串了一个10kΩ电阻到PA0再从PA0对地接一个5.1kΩ电阻这样即使模块输出5V到PA0也只有约1.7V始终在安全范围内。代价是分辨率降低但对烟雾告警场景完全够用。第二是滤波。每个模块输出脚和GND之间并一个100nF电容滤掉高频耦合噪声。这个电容离STM32引脚越近越好最好直接焊接在杜邦线末端或PCB上靠近MCU的位置。如果你用面包板飞线走线太长又没电容ADC读数会明显抖动。电源侧同样要处理传感器的模拟地线和STM32的数字地建议单点汇接不要形成地环路。三路传感器供电脚各自并一个10uF100nF电容组合能显著改善数据稳定性。3. STM32采集代码ADC配置、数值换算与软件滤波传感器接好了下一步是让STM32把这些模拟信号变成“稳定、可解释”的数据。这一部分也是技术含量最集中的地方。3.1 ADC多通道DMA的初始化配置STM32F103的ADC有12位分辨率3路传感器刚好对应三个通道。我建议用ADC扫描模式加DMA搬运让三路数据在硬件上自动连续采集CPU只管从数组里取数据省心而且数据一致性更好。核心初始化代码如下/* 使用ADC1扫描模式3个通道软件触发 */ ADC_ChannelConfTypeDef sConfig {0}; hadc1.Instance ADC1; hadc1.Init.ScanConvMode ADC_SCAN_ENABLE; // 扫描模式 hadc1.Init.ContinuousConvMode DISABLE; // 单次转换由软件或定时器触发 hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START; // 软件触发简单可控 hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion 3; // 3个通道 HAL_ADC_Init(hadc1); /* 通道0PA0烟雾 */ sConfig.Channel ADC_CHANNEL_0; sConfig.Rank 1; sConfig.SamplingTime ADC_SAMPLETIME_239CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sConfig); /* 通道1PA1粉尘 */ sConfig.Channel ADC_CHANNEL_1; sConfig.Rank 2; HAL_ADC_ConfigChannel(hadc1, sConfig); /* 通道2PA2噪音 */ sConfig.Channel ADC_CHANNEL_2; sConfig.Rank 3; HAL_ADC_ConfigChannel(hadc1, sConfig); /* 定义DMA缓存 */ uint32_t adc_buf[3]; /* 触发一次采集为下一次采集做准备时需要重新调用 */ void Adc_Sample(void) { HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_buf, 3); } /* 转换完成后在回调里取数据 */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { static uint8_t data_ready 0; if (hadc-Instance ADC1) { /* adc_buf[0] 烟雾通道原始值 */ /* adc_buf[1] 粉尘通道原始值 */ /* adc_buf[2] 噪音通道原始值 */ data_ready 1; } }采样时间我特意选了最长的239.5个周期。传感器模块的输出阻抗通常不低如果采样时间太短内部采样电容来不及充满读出的值会偏低且不稳定。长采样时间多花的那点时间对低频环境信号来说完全无所谓。这里有个容易被忽略的细节GP2Y1010粉尘传感器的LED脉冲和ADC采样必须同步。我在主循环里用一个软件定时器每10ms执行一次下面这段逻辑/* 粉尘传感器 LED 脉冲控制的伪代码逻辑 */ void Dust_Led_Sample(void) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 点亮LED delay_us(280); // 等待280us光源稳定 Adc_Sample(); // 启动ADC采集粉尘通道 delay_us(40); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 熄灭LED }原理是GP2Y1010的手册规定LED脉冲点亮约0.28ms后光电输出达到峰值此时必须读取电压然后在0.04ms内关断LED进入下一个周期。如果LED常亮或者ADC触发时机不对读出的粉尘电压要么恒高要么无反应。这个时序问题是粉尘传感器调试中最隐蔽的坑。3.2 粉尘和噪音的数据换算逻辑ADC原始值要先换算成电压公式很简单float voltage (float)adc_value * 3.3f / 4095.0f;但这里有个前提如果我在2.3节加了分压电阻必须把分压比例还原回去。比如MQ-2经过10k和5.1k分压实际进入ADC的电压只有原始电压的5.1/15.1所以真正的模块输出电压要除以这个比例。粉尘浓度换算GP2Y1010数据手册给出的典型特性是无尘环境下输出约0.9V浓度每增加1mg/m3电压大约上升0.5V。所以估算公式为float dust_density (voltage_dust - 0.9f) / 0.5f; if (dust_density 0) dust_density 0;这个公式只能做相对估算因为每颗传感器之间存在个体差异环境湿度、灰尘成分也会影响结果。如果你只是做告警和趋势观察这个精度完全够用如果要绝对准确就需要用标准粉尘源标定写一个校准系数进去。噪音换算和前面两路不同。噪音模块输出的是交流信号不能直接拿单次ADC值当音量。我采用的方法是连续采样一段时间计算RMS值再换算成相对分贝。#define SAMPLE_NUM 1000 float Noise_CalculateDb(void) { float sum_sq 0; float v; for (int i 0; i SAMPLE_NUM; i) { v get_adc_voltage(CH_NOISE); sum_sq v * v; delay_us(100); /* 10kHz采样率覆盖100ms声音信号 */ } float rms sqrtf(sum_sq / SAMPLE_NUM); /* 以1V为参考电平换算相对分贝。实际场景中可再用手机分贝计校准偏移 */ float db 20.0f * log10f(rms 1e-6f); return db; }这个公式算出的分贝值不是绝对声压级因为模块的增益、参考电压都影响最终数值。我的做法是先用手机上的分贝计App在安静办公室和嘈杂路边分别测一下真实值再和模块读数对比记下两个校准偏移量在代码里做线性修正。这样虽然没有专业声学仪器那么准但对环境监测足够。3.3 滑动平均限幅滤波让数据曲线不再发抖传感器原始数据尤其是粉尘和噪音波动非常大。直接上云的话曲线像心电图一样没法看。我用了两层滤波第一层是滑动平均窗口选8个点。窗口太小滤不干净太大又会让数据反应迟钝8到16是一个比较舒服的区间。第二层是限幅滤波专门对付WiFi发射瞬间产生的偶发尖峰。#define FILTER_WIN 8 float filter_buf[3][FILTER_WIN]; uint8_t filter_index[3]; float SmoothFilter(uint8_t ch, float new_value) { float sum 0; filter_buf[ch][filter_index[ch]] new_value; filter_index[ch] (filter_index[ch] 1) % FILTER_WIN; for (int i 0; i FILTER_WIN; i) { sum filter_buf[ch][i]; } return sum / FILTER_WIN; } /* 限幅滤波如果新值与上次值差超过阈值判定为毛刺丢弃 */ float LimitFilter(uint8_t ch, float new_value, float max_delta) { static float last[3] {0}; if (fabsf(new_value - last[ch]) max_delta) { return last[ch]; } last[ch] new_value; return new_value; }粉尘传感器每10ms采集一次8个窗口就是80ms一个周期80ms反应速度足够。实测下来滤波前粉尘电压在0.85V到1.3V之间乱跳滤波后基本稳定在0.9V左右很直观。4. ESP8266上云从AT指令初始化到断线重连数据采出来了接下来要把数据送到云端。这块我用的是ESP8266的AT指令方案虽然看起来“土”但胜在稳定、逻辑清晰、容易排查问题。4.1 ESP-01S最小系统与STM32的串口接线ESP-01S一共8个引脚真正用起来比想象中简单。接线如下ESP-01S引脚连接说明VCC3.3V单独供电模块绝不能接5V会烧GNDGND与STM32共地TXSTM32 USART1 RX3.3V电平可直连RXSTM32 USART1 TX3.3V电平可直连GPIO0上拉10k到3.3V复位时保持高电平进入运行模式GPIO2悬空或上拉不要强制拉低这里强调一下GPIO0。ESP8266复位时如果GPIO0为低电平会进入UART下载固件模式表现为模块不响应AT指令串口输出乱码或“ready”反复出现。所以GPIO0必须默认上拉到3.3V。GPIO2同理启动时内部默认是上拉外部不要把它拉低。4.2 AT指令初始化流程WiFi连接、TCP建链、POST数据ESP8266拿到的是官方AT固件所以一切操作都可以通过串口指令完成。初始化顺序固定/* 1. 测试AT指令是否正常 */ AT - OK /* 2. 设置Station模式 */ ATCWMODE1 - OK /* 3. 连接WiFi注意替换为自己的WiFi名称和密码 */ ATCWJAPMyWiFi,MyPassword - WIFI CONNECTED WIFI GOT IP /* 4. 关闭多连接模式只保留一个TCP连接 */ ATCIPMUX0 - OK /* 5. 建立TCP连接到云平台服务器域名或IP */ ATCIPSTARTTCP,your.cloud.server,80 - CONNECT OK /* 6. 准备发送数据n是下面数据的字节数 */ ATCIPSEND89 - OK /* 7. 发送HTTP POST请求 */ POST /api/envdata HTTP/1.1\r\n Host: your.cloud.server\r\n Content-Type: application/json\r\n Content-Length: 44\r\n \r\n {smoke:0.42,dust:0.38,noise:52.3}代码里我封装了一个发送函数底层逻辑是发指令等待“OK”发数据等待“SEND OK”然后判断服务器是否返回了HTTP 200。uint8_t ESP8266_SendData(float smoke_v, float dust_mg, float noise_db) { char payload[128]; char cmd[160]; int len; snprintf(payload, sizeof(payload), {\smoke\:%.2f,\dust\:%.2f,\noise\:%.1f}, smoke_v, dust_mg, noise_db); /* 拼HTTP请求 */ len snprintf(cmd, sizeof(cmd), POST /api/envdata HTTP/1.1\r\n Host: your.cloud.server\r\n Content-Type: application/json\r\n Content-Length: %d\r\n\r\n%s, strlen(payload), payload); /* 先建立连接如果失败就返回0 */ if (!ESP_SendCmd(ATCIPSTART\TCP\,\your.cloud.server\,80\r\n, CONNECT OK, 5000)) { return 0; } /* 通知ESP8266即将发送的数据长度 */ char send_len[32]; snprintf(send_len, sizeof(send_len), ATCIPSEND%d\r\n, len); if (!ESP_SendCmd(send_len, OK, 1000)) { return 0; } /* 发送实际数据 */ if (!ESP_SendDataRaw(cmd, SEND OK, 3000)) { return 0; } return 1; }上报频率我设成了10秒一次。环境量变化本来就很慢10秒足够及时也不会给云平台造成压力。如果要做产品级方案上报间隔需要根据业务需求动态调整甚至可以在传感器数值变化剧烈时主动临时上报。4.3 上云协议的取舍HTTP先跑通MQTT再做精这套流程我一开始用的HTTP POST图的是简单直观。但HTTP每次上报都要建立连接、传输、断开数据传输效率不高Server端也需要配套HTTP接口。如果你想把方案做得更规范、更省流量建议换MQTT协议。MQTT的优势是长连接、订阅发布模型、QoS保证适合物联网设备这类小报文、频繁上报的场景。ESP8266的高版本AT固件已经内置MQTT指令大致流程是/* MQTT配置 */ ATMQTTUSERCFG0,1,clientId,username,password,0,0, /* 连接服务器 */ ATMQTTCONN0,your.mqtt.server,1883,1 /* 发布数据到主题 */ ATMQTTPUB0,device/001/data,{\smoke\:0.42},0,0MQTT对云平台的接入也更标准。如果你用某免费物联网云平台或者自己搭了开源MQTT Broker这段AT指令基本是通用的。我的建议是第一次跑通项目用HTTP确定方案能转了再切MQTT不要一上来就两套协议并行容易把自己绕进去。4.4 断电重连与看门狗式恢复逻辑WiFi链路不可能永远稳定。路由器重启、信号干扰、ESP8266固件偶发卡死都是我实际遇到过的。没有重连机制的项目跑一天就“失联”了。我加了三层保障一是主循环里定期检查TCP连接状态。用ATCIPSTATUS查询如果返回值里没有“CONNECTED”或者返回错误就主动重新ATCIPSTART。二是连续上报失败计数。如果连续5次通信失败说明ESP8266可能已经卡死用GPIO控制一个三极管拉低ESP8266的RST引脚强制硬件复位然后重新走一遍初始化流程。这个“看门狗式”复位逻辑我用下来非常有效。三是掉线重连的防抖处理。WiFi刚断开的时候不要立即疯狂重连退避机制是失败1次等5秒失败2次等10秒失败3次以上等30秒。不然ESP8266会陷入“疯狂重连-发烫-更不稳定”的恶性循环。5. 云平台侧数据解析、曲线面板与告警联动设备端的数据发出去了云平台这一侧才是用户真正能看到价值的地方。大部分人觉得云平台复杂其实现在的物联网平台已经把大部分流程标准化了。5.1 产品/设备/主题三层结构与接入参数主流的物联网云平台基本都采用“产品-设备-数据主题”的三层结构。产品定义一类设备的属性设备是具体的一个硬件实例数据通过主题或数据流上传。这个项目里我在云平台上创建了一个“环境监测器”产品产品下添加了一个测试设备。设备上报的数据格式我定义为{ smoke: 0.42, dust: 0.38, noise: 52.3 }smoke单位用电压值Vdust单位是估算的mg/m3noise单位是分贝。这里的单位定义在云平台上要提前配好方便后面搭建曲线面板。接入方式上由于我设备端用的是HTTP POST我在平台里创建了一个数据接口把设备唯一标识放在URL路径里平台根据设备ID自动关联数据流。如果你用MQTT方式操作更直接设备订阅/发布对应Topic平台自动解析JSON里的字段。5.2 数据可视化面板和阈值告警配置数据一旦到达平台剩下的就是配置问题。实时曲线基本是每个平台的标配功能。我把smoke、dust、noise三个字段分别绑定到一个折线图时间窗口选1小时和24小时两个维度这样既能看到实时波动也能看长期趋势。实测下来办公室的噪音曲线在工作时间会出现明显的规律性波动粉尘曲线在开窗通风时会下降这些趋势用曲线面板看非常直观。告警规则我是这样设计的指标告警阈值触发条件通知方式烟雾电压 1.2V持续2次以上超过阈值平台消息推送粉尘浓度 0.8 mg/m3持续5分钟超标平台消息推送噪音分贝 75dB持续1分钟超标仅记录不推送告警阈值不能设置得太灵敏。我一开始把烟雾告警设成电压超过0.8V就触发结果厨房炒个菜的油烟都能被判定为“火灾隐患”一晚上狂推消息。后来改成“连续2次采样都超标”才触发误报率明显下降。做告警一定要有去抖机制这和前面说的软件滤波是一个道理。5.3 可扩展方向继电器控制、小程序通知、本地缓存这套系统做出来后可扩展的方向非常多我说几个我实践过或者规划中的继电器联动STM32留出两个GPIO接继电器模块当粉尘或烟雾超阈值时自动开启排风扇。这是很多环境监测产品的核心卖点——监测不是目的联动控制才是。小程序/App通知云平台一般都提供小程序或App SDK配置好告警推送后消息直达手机。这类工作基本是配置工作不需要设备端改代码。本地缓存现在设备断网后就傻眼了数据全丢。可以外接一个SPI Flash芯片把采样数据按分钟写入缓存网络恢复后再补传。这块会增加不少工作量但对于数据连续性要求高的工业场景很有价值。6. 实测数据与排查实录这几个坑不提前知道会很伤项目做完、跑了一周之后我记录了一些实测数据也把几个高频问题的完整排查思路写在这里。如果你也准备做类似项目这些经验能帮你省下好几个晚上的调试时间。6.1 三种场景下的实测原始数据我在三个场景下各记录了10分钟数据取平均值场景烟雾电压(V)粉尘估算(mg/m3)噪音分贝(dB)安静办公室0.280.0348有人走动的走廊0.310.1258点燃线香附近的桌面1.750.8555可以看到烟雾传感器对线香这类燃烧产物反应非常明显电压从0.3V直接跳到1.7V以上粉尘传感器的响应也很直观但它的数据波动更大必须靠滤波后的值判断趋势。噪音分贝值做了手机分贝计校准误差在正负3dB以内作为环境监测够用。6.2 坑1ESP8266一连接WiFi就重启问题出在供电现象是系统单独跑传感器采集一切正常可一旦ESP8266执行ATCWJAP连接WiFi模块就开始反复重启串口日志里出现乱码和“ready”过一会儿又消失。排查链路是这样的我先接一个LED在ESP8266的VCC上观察供电电压。结果发现WiFi建立连接的一瞬间VCC电压从3.3V掉到了2.7V左右而模块的欠压复位阈值大概在2.8V电压一跌破就重启。根因是供电不足。STM32核心板上的3.3V稳压芯片输出能力有限ESP8266发射脉冲电流大直接把电压拉垮。解决方法是独立供电用一个单独的AMS1117-3.3模块给ESP8266供电并在VCC和GND之间并联470uF电解电容。这样处理后连接WiFi时电压波动降到0.2V以内问题彻底消失。6.3 坑2粉尘传感器读数恒为0或偏高先查LED脉冲时序GP2Y1010这个传感器有一个朋友照着我的电路接好ADC值恒为0。我远程帮他看代码发现他把LED引脚直接置成高电平没有脉冲。这个芯片的LED必须周期脉冲驱动常亮状态下光电接收端处于饱和状态输出反而异常。另一种现象是读数恒偏高且不受环境粉尘影响。这种情况一般是ADC采样时机不对没有在LED脉冲点亮后的0.28ms窗口附近采样。因为GP2Y1010的输出电压是“LED亮起后迅速爬升随后回落”的尖峰波形如果你采样采在波形回落之后读到的就是一个偏高且相对固定的值。正确的做法就是我3.1节里写的那样先拉高LED延时280us启动ADC转换再延时40us拉低LED。这个顺序不能乱延时也不能随意改。用逻辑分析仪看波形来调时序是最直观的。6.4 坑3MQ-2刚上电数值乱飘需要预热和基线校准MQ-2刚上电时加热丝要一段时间才能达到工作温度气敏材料表面也在逐渐稳定。这期间输出电压会持续漂移有时候能漂好几分钟。如果你一上电就做阈值判断很容易误报。我的基线校准方法是代码里加一个“预热模式”系统上电后前2分钟不断采集烟雾电压并计算平均值作为当前环境的基线电压。正常工作时的烟雾电压要减去这个基线再做告警判断。/* 预热完成后记住基线 */ float smoke_baseline 0.0f; uint8_t warmup_flag 0; void Smoke_Calibration(void) { static uint32_t sample_count 0; static float sum 0; if (!warmup_flag) { if (sample_count 1200) { /* 2分钟每100ms采一次 */ sum smoke_voltage; sample_count; } else { smoke_baseline sum / sample_count; warmup_flag 1; sum 0; sample_count 0; } } }这个基线在设备长时间运行后也会缓慢变化所以我还会每24小时悄悄重新校准一次基线保证长期部署的稳定性。6.5 最后给一个校准技巧和调试习惯建议做环境监测这类项目校准永远是个绕不开的话题。我的经验是不要执着于绝对精度先保证相对趋势准确再用标准设备修正偏移。粉尘浓度用单点公式估算噪音分贝用手机App对比修正烟雾用浓度阈值告警而不是非要算PPM这套系统工程上足够用。调试习惯方面强烈建议在STM32上留一路UART调试串口把时间戳、三路原始电压、滤波后数值、ESP8266返回状态全部打印出来。说句实在话我做这个项目的后半程几乎全靠这路日志定位问题。没有它光靠云平台上的数据根本猜不到是采集坏了、换算错了还是传输丢了。很多朋友做这类项目习惯把目光盯着“云平台多高大上”其实真正决定项目成败的恰恰是采集端那些不起眼的细节传感器时序、供电余量、滤波去抖、重连机制。把这些基础打扎实剩下的上云部分照文档配置就行。这套思路不光适用于烟雾粉尘噪音监测你把它换成温湿度、气压、光照传感器整个架构几乎不用改稍微动动采集通道和换算公式就能复用。这也是我当初选STM32的原因——它能让你把时间花在真正难的地方而不是不断搬家换平台。
阅读完成 · 觉得有帮助?