1. 项目概述:当STM32遇上环境监测
去年帮朋友改造老房子时,发现传统的温湿度计功能单一且无法记录历史数据。于是用STM32F103C8T6开发板搭配DHT11传感器和1.44寸LCD屏,做了这个带实时显示功能的家庭环境监测系统。它不仅能够同时监测温湿度、空气质量(通过MQ-135传感器)和光照强度(BH1750),还能在LCD屏上直观展示数据曲线,成本不到50元却实现了商业级监测仪80%的功能。
这个项目的核心价值在于:
- 实时可视化:所有数据通过彩色LCD屏动态展示
- 多参数融合:温湿度+空气质量+光照三合一监测
- 低功耗设计:待机电流仅8mA,纽扣电池可续航2周
- 模块化架构:各传感器独立工作,方便后期扩展
硬件选型心得:STM32F103C8T6(蓝色pill开发板)虽然性能不是最强,但72MHz主频处理传感器数据绰绰有余,且价格仅10元左右,是性价比之选。
2. 硬件设计与核心元件选型
2.1 主控板:STM32最小系统方案
采用STM32F103C8T6最小系统板作为主控,具体配置如下:
- 核心:Cortex-M3内核,72MHz主频
- 存储:64KB Flash + 20KB SRAM
- 接口:2xSPI、2xI2C、3xUSART
- 供电:3.3V(可直接用USB 5V输入)
c复制// 时钟配置示例(使用HSE 8MHz晶振)
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
2.2 传感器阵列配置
温湿度模块DHT11:
- 单总线通信协议
- 测量范围:20-90%RH,0-50℃
- 精度:±5%RH,±2℃
- 接线:3.3V-GND-Data(PB12)
空气质量MQ-135:
- 检测NH3/NOx/CO2等气体
- 模拟量输出(PA0)
- 需预热20分钟稳定
光照传感器BH1750:
- I2C接口(PB6-SCL, PB7-SDA)
- 量程1-65535 lux
- 0.5lx分辨率
2.3 显示模块优化方案
选用1.44寸IPS LCD屏(ST7735S驱动)关键参数:
- 分辨率:128x128 RGB
- 接口:SPI(PA5-SCK, PA7-MOSI, PA4-CS, PA2-RST, PA1-DC)
- 刷新率:30fps(实测全屏刷新需18ms)
布线技巧:SPI时钟线要尽量短(<10cm),否则会出现雪花噪点。我在第一次测试时因为排线过长导致显示异常,后来改用杜邦线直连解决问题。
3. 软件架构与关键代码实现
3.1 多任务调度设计
采用时间片轮询方式管理三个核心任务:
- 传感器数据采集(100ms周期)
- 屏幕刷新(500ms周期)
- 异常检测(1s周期)
c复制void TIM3_IRQHandler() { // 定时器3中断服务函数
static uint8_t counter = 0;
if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
if(++counter >= 10) {
counter = 0;
Sensor_Update(); // 每100ms执行一次
}
if(counter % 5 == 0) LCD_Refresh();
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
3.2 传感器数据处理算法
温湿度数据平滑处理:
c复制#define FILTER_LEN 5
float temp_history[FILTER_LEN];
float Get_FilteredTemp() {
static uint8_t index = 0;
temp_history[index] = DHT11_GetTemp();
index = (index + 1) % FILTER_LEN;
float sum = 0;
for(uint8_t i=0; i<FILTER_LEN; i++) {
sum += temp_history[i];
}
return sum/FILTER_LEN;
}
MQ-135校准公式(针对CO2):
code复制Rs/R0 = 1.0 + 0.0002*(ppm)^1.5
其中R0在清洁空气中测得(通常50kΩ)
3.3 LCD界面渲染优化
采用双缓冲机制避免闪烁:
- 在内存中构建完整帧
- 使用DMA传输到LCD GRAM
- 仅更新变化区域
c复制void LCD_DrawDynamicWave(uint16_t x, uint16_t y, uint16_t width, uint16_t height,
int16_t *values, uint8_t count, uint16_t color) {
int16_t prev_y = y + height/2 - values[0]*height/200;
for(uint8_t i=1; i<count; i++) {
int16_t curr_y = y + height/2 - values[i]*height/200;
LCD_DrawLine(x+(i-1)*width/count, prev_y, x+i*width/count, curr_y, color);
prev_y = curr_y;
}
}
4. 电源管理与低功耗实现
4.1 供电方案对比
| 供电方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| USB 5V | 稳定可靠 | 需有线连接 | 固定位置监测 |
| 3.7V锂电 | 移动灵活 | 需充电管理 | 便携式应用 |
| 纽扣电池 | 超小体积 | 容量有限 | 低功耗节点 |
最终选择TP4056充电模块+500mAh锂电池方案,关键配置:
- 充电电流:200mA(RPROG=5KΩ)
- 低压保护:2.7V(DW01芯片)
- 升压输出:3.3V(MT3608)
4.2 STM32低功耗技巧
- 时钟优化:
c复制RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
- 外设智能控制:
- 传感器供电用MOSFET控制(PB8)
- LCD背光PWM调光(TIM4_CH3)
- 中断唤醒配置:
c复制void EXTI0_IRQHandler() { // 按键唤醒
if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
EXTI_ClearITPendingBit(EXTI_Line0);
SystemInit(); // 重新初始化时钟
}
}
5. 常见问题与调试实录
5.1 传感器数据异常排查
现象:DHT11偶尔返回255值
- 检查1:电源电压(需>3V)
- 检查2:上拉电阻(4.7KΩ最佳)
- 检查3:时序精度(微秒级延迟)
MQ-135输出不稳定解决方案:
- 增加RC滤波(10KΩ+1μF)
- 预热至少20分钟
- 定期自动校准(每24小时)
5.2 LCD显示问题处理
花屏可能原因:
- SPI时钟相位设置错误
c复制SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
- 复位时序不足(至少10ms低电平)
- 电源噪声(并联100μF电容)
提高刷新速度的技巧:
- 使用硬件SPI(禁用软件模拟)
- 减少全屏刷新(局部更新)
- 开启SPI时钟预分频(PCLK/2)
6. 项目扩展与进阶玩法
6.1 无线传输扩展
添加ESP-01S WiFi模块实现数据上传:
-
接线方式:
- UTXD -> PA3 (USART2_RX)
- URXD -> PA2 (USART2_TX)
- CH_PD -> 3.3V
- VCC -> 3.3V
-
AT指令示例:
c复制void ESP_SendData(float temp, float humi) {
USART2_SendString("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80\r\n");
Delay_ms(1000);
sprintf(buffer,"GET /update?api_key=XXX&field1=%.1f&field2=%.1f\r\n",temp,humi);
USART2_SendString("AT+CIPSEND=");
USART2_SendString(itoa(strlen(buffer),num,10));
USART2_SendString("\r\n");
Delay_ms(500);
USART2_SendString(buffer);
}
6.2 外壳设计与安装建议
使用3D打印外壳的注意事项:
-
传感器开孔位置:
- DHT11距顶部至少5mm
- MQ-135需要通风孔
- 光敏传感器避免遮挡
-
结构设计要点:
- 预留LCD可视角度(15°倾斜)
- 电池仓可拆卸设计
- 按键防误触凹槽
实测发现将设备安装在离地面1.5米高度(墙面)时,温湿度监测数据最接近实际体感。避免安装在空调直吹或阳光直射位置。