1. 项目概述:室内空气质量监测的硬件实现方案
去年帮朋友改造智能家居系统时,发现市面上大多数空气质量检测设备存在两个痛点:要么功能单一(只能测PM2.5或温湿度),要么数据精度堪忧。于是萌生了用STM32开发多功能检测设备的想法,这个方案最终实现了0.1℃温度精度、±3%RH湿度精度、0.01mg/m³甲醛分辨率和±10μg/m³的PM2.5检测能力。
整套系统包含硬件设计(原理图+PCB)、嵌入式程序(HAL库开发)、上位机软件(Qt编写)三大部分,采用模块化设计思路。主控使用STM32F103C8T6最小系统板,传感器阵列包含DHT22(温湿度)、ZE08-CH2O(甲醛)、攀藤PMS5003(PM2.5),数据通过ESP-01S WiFi模块上传到云端,本地还配有1.3寸OLED显示屏实时展示数据。
关键设计原则:在保证精度的前提下,将BOM成本控制在150元以内,这比商用设备便宜60%以上。实测发现,甲醛传感器预热时间对精度影响最大,需要特别处理。
2. 硬件设计详解
2.1 核心器件选型对比
传感器选型经历了三次迭代,最终确定的方案如下表所示:
| 检测项目 | 候选型号 | 最终选择 | 关键参数 | 单价 |
|---|---|---|---|---|
| 温湿度 | DHT11/AM2302/DHT22 | DHT22 | ±0.5℃, ±2%RH, 0.1℃分辨率 | 18元 |
| 甲醛 | ZE08-CH2O/SH-300 | ZE08-CH2O | 0-5ppm, ±5%FS | 65元 |
| PM2.5 | PMS5003/SDS011 | PMS5003 | 0-1000μg/m³, ±10% | 85元 |
| WiFi模块 | ESP-01S/ESP8266-12F | ESP-01S | 支持AT指令透传 | 12元 |
选择DHT22而非更便宜的DHT11,是因为后者湿度检测误差可达±5%RH,在梅雨季节会产生明显偏差。甲醛传感器选用电化学原理的ZE08-CH2O,比半导体式传感器抗干扰能力更强,但需要注意以下两点:
- 需要至少24小时持续通电激活电解液
- 每半年需进行48小时连续校准
2.2 PCB设计踩坑记录
第一版PCB犯了个低级错误 - 把PMS5003的UART接口直接连到了STM32的USART1,结果发现这个激光粉尘传感器工作时会产生200mA的电流波动,导致串口通信异常。改进方案:
- 使用单独的LDO给PMS5003供电
- 串口线路添加TVS二极管防护
- 硬件流控引脚一定要引出
电源部分采用两级稳压设计:
- 第一级:MP2307DN降压到5V(给传感器供电)
- 第二级:AMS1117-3.3V(给MCU和WiFi模块供电)
血泪教训:DHT22的数据线记得加上拉电阻!这个传感器是单总线协议,没有内置上拉,初期调试时因为这个问题浪费了两天时间。
3. 嵌入式软件设计
3.1 传感器驱动开发
使用STM32CubeMX生成HAL库基础工程,关键外设配置:
- USART1:连接PMS5003(115200bps)
- USART2:连接ZE08-CH2O(9600bps)
- USART3:连接ESP-01S(115200bps)
- I2C1:驱动OLED显示屏
- GPIOB12:单总线接口连接DHT22
传感器数据采集采用状态机模式,避免阻塞主循环。以DHT22为例,其读取时序分为三个状态:
c复制typedef enum {
DHT_START_SIGNAL,
DHT_WAIT_RESPONSE,
DHT_READ_DATA
} DHT_State;
void DHT_ReadProcess(void) {
static DHT_State state = DHT_START_SIGNAL;
static uint8_t data[5] = {0};
switch(state) {
case DHT_START_SIGNAL:
HAL_GPIO_WritePin(DHT_GPIO_Port, DHT_Pin, GPIO_PIN_RESET);
delay_ms(18); // 必须大于18ms
state = DHT_WAIT_RESPONSE;
break;
// ...其他状态处理
}
}
3.2 数据融合算法
直接显示传感器原始数据会有跳变现象,采用滑动加权平均算法进行平滑处理:
c复制#define SAMPLE_SIZE 10
typedef struct {
float buffer[SAMPLE_SIZE];
uint8_t index;
float sum;
} SmoothFilter;
float smooth_update(SmoothFilter* filter, float new_val) {
filter->sum -= filter->buffer[filter->index];
filter->sum += new_val;
filter->buffer[filter->index] = new_val;
filter->index = (filter->index + 1) % SAMPLE_SIZE;
return filter->sum / SAMPLE_SIZE;
}
对甲醛传感器特别增加了温度补偿算法,因为电化学传感器输出会受环境温度影响:
code复制补偿后值 = 原始值 × (1 + 0.003 × (25 - 当前温度))
4. 云端数据传输方案
4.1 ESP-01S固件配置
使用AT固件需要特别注意以下指令序列:
- 先发送AT+RST复位模块
- 等待"ready"提示后发送AT+CWMODE=1(STA模式)
- AT+CWJAP="SSID","password" 连接WiFi
- AT+CIPSTART="TCP","api.thingspeak.com",80 建立连接
- AT+CIPSEND=长度 发送数据
数据上传采用HTTP GET请求,格式示例:
code复制GET /update?api_key=XXX&field1=23.5&field2=45&field3=0.08&field4=35 HTTP/1.1\r\n
Host: api.thingspeak.com\r\n\r\n
4.2 本地数据存储
考虑到网络可能中断,在STM32内部Flash最后1页(Page 127)实现了环形存储队列,每5分钟保存一次数据,可存储24小时的历史记录。关键实现:
c复制#define FLASH_PAGE_SIZE 1024
#define FLASH_LAST_PAGE 127
#define FLASH_END_ADDR 0x0801FC00
void flash_write(uint32_t addr, uint16_t *data, uint16_t len) {
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR);
for(uint16_t i=0; i<len; i++) {
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, addr, data[i]);
addr += 2;
}
HAL_FLASH_Lock();
}
5. 系统校准与优化
5.1 传感器校准流程
甲醛传感器必须按照以下步骤校准:
- 通电后在清洁空气中静置24小时
- 使用专业甲醛检测仪作为基准
- 通过串口发送校准命令:FF 01 78 41 00 00 00 00 1A
- 等待传感器返回确认帧
PM2.5传感器校准更简单:
- 在空气良好的室外环境运行2小时
- 发送命令:42 4D E1 00 01 01 71
- 设备会自动计算零点偏移
5.2 低功耗优化技巧
虽然本设计主要接市电使用,但通过以下改动可使整机功耗从85mA降到12mA:
- 将OLED改为间歇刷新(每10秒更新一次)
- PMS5003启用睡眠模式(发送42 4D E4 00 01 01 74)
- STM32进入STOP模式,通过RTC定时唤醒
- 关闭所有不用的外设时钟
实测发现,ZE08-CH2O在连续工作模式下功耗达45mA,改为每5分钟唤醒一次后,平均功耗降至8mA。
6. 常见问题排查指南
6.1 数据异常排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| PM2.5值始终为0 | 传感器风扇未启动 | 检查5V供电是否达到500mA |
| 甲醛读数波动大 | 传感器未充分预热 | 连续通电24小时以上 |
| WiFi频繁断开 | 电源纹波过大 | 在ESP-01S的VCC加100μF电容 |
| OLED显示乱码 | I2C上拉电阻缺失 | 在SCL/SDA线加4.7k上拉 |
| 温度比实际低2-3℃ | DHT22被自身发热影响 | 将传感器移至PCB边缘 |
6.2 典型通信故障
UART通信中最容易遇到以下问题:
- 波特率不匹配:特别是PMS5003必须精确设置为115200bps
- 字节间隔超时:DHT22要求位间隔>50μs
- 缓冲区溢出:HAL库默认接收缓冲区只有64字节,对于PMS5003这种一次发送32字节的传感器需要调整
c复制// 修改HAL库缓冲区大小方法
#define UART_BUFFER_SIZE 128
uint8_t rx_buf[UART_BUFFER_SIZE];
HAL_UART_Receive_IT(&huart1, rx_buf, UART_BUFFER_SIZE);
这个项目最让我意外的是甲醛传感器的响应特性 - 在密闭空间喷洒酒精后,读数会先飙升然后缓慢下降,这与真实甲醛的持续高值特性完全不同。后来通过软件增加了突变检测算法,当检测到数值快速变化时自动进入抗干扰模式。