智能家居DIY:用STM32F103和DHT11搭建本地温湿度监控站(附串口/OLED多方案)
在智能家居的浪潮中,环境监测是最基础却最实用的功能之一。想象一下,当你需要监控书房古籍的保存环境、花房植物的生长条件,或是地下室储物间的防潮情况时,一个不依赖网络的本地温湿度监测站就显得尤为重要。本文将带你用STM32F103和DHT11传感器,打造一个成本低廉但功能完善的解决方案。
与常见的教程不同,我们不仅会实现基础功能,还会探讨多种数据显示方案(串口、OLED等),并设计可扩展的代码架构,为后续添加光照、空气质量等传感器预留接口。这个项目特别适合电子爱好者、创客,以及对物联网DIY感兴趣的初学者。
1. 硬件选型与电路设计
1.1 核心元件介绍
STM32F103C8T6(俗称"蓝莓板")是本次项目的主控芯片选择,原因有三:
- 价格亲民(约10-15元)
- 丰富的GPIO和外设资源
- 强大的社区支持和完善的库函数
DHT11温湿度传感器则是环境监测的经济之选:
- 测量范围:温度0-50℃(±2℃精度),湿度20-90%RH(±5%RH精度)
- 单总线通信,仅需一个GPIO引脚
- 典型响应时间2秒,适合低频次监测场景
提示:若需要更高精度,可考虑DHT22或SHT3x系列传感器,但成本会相应提高。
1.2 电路连接方案
基础接线非常简单,只需3根导线:
| 引脚 | 连接目标 | 备注 |
|---|---|---|
| VCC | 3.3V电源 | 建议加装0.1μF去耦电容 |
| GND | 地线 | 确保共地 |
| DATA | PA11 | 需配置4.7K上拉电阻 |
对于需要显示数据的场景,我们提供两种扩展方案:
方案A:0.96寸OLED显示
// I2C初始化代码示例 void OLED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; // 初始化I2C时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // 配置I2C引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // I2C参数配置 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x00; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 400000; I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); }方案B:串口输出到电脑
# Python端接收代码示例 import serial from time import sleep ser = serial.Serial('COM3', 115200, timeout=1) while True: data = ser.readline().decode('ascii').strip() if data: temp, humi = data.split(',') print(f"温度: {temp}℃ 湿度: {humi}%") sleep(2)2. 软件架构设计
2.1 驱动程序开发
DHT11的通信协议需要精确的时序控制。我们采用模块化设计,将传感器驱动独立封装:
// dht11.h 头文件定义 typedef struct { uint8_t temp_int; // 温度整数部分 uint8_t temp_frac; // 温度小数部分 uint8_t humi_int; // 湿度整数部分 uint8_t humi_frac; // 湿度小数部分 uint8_t checksum; // 校验和 } DHT11_Data; uint8_t DHT11_Init(void); uint8_t DHT11_Read(DHT11_Data *data);关键时序实现要点:
- 主机拉低至少18ms后拉高20-40μs
- 传感器响应信号为80μs低电平+80μs高电平
- 每位数据以50μs低电平开始,高电平持续时间决定数据位(26-28μs为0,70μs为1)
2.2 多显示方案适配
采用策略模式实现显示输出的灵活切换:
// display.h 抽象接口 typedef struct { void (*init)(void); void (*show)(DHT11_Data data); } DisplayDriver; // 注册当前使用的显示驱动 void Display_RegisterDriver(DisplayDriver *driver); // 具体实现示例:OLED驱动 const DisplayDriver OLED_Display = { .init = OLED_Init, .show = OLED_ShowData }; // 串口显示实现 void UART_ShowData(DHT11_Data data) { printf("%d.%d,%d.%d\r\n", data.temp_int, data.temp_frac, data.humi_int, data.humi_frac); }这种设计允许运行时动态切换显示方式,也便于后续扩展其他显示设备。
3. 系统优化与扩展
3.1 低功耗设计
对于电池供电场景,可采取以下优化措施:
间歇工作模式:
- 每5分钟唤醒一次采集数据
- 其余时间进入STOP模式
硬件优化:
- 选用低功耗LDO(如HT7333)
- 关闭未使用的外设时钟
// 进入低功耗模式示例 void Enter_LowPowerMode(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); SystemInit(); // 唤醒后需重新初始化时钟 }3.2 数据记录与分析
添加SD卡模块可实现长期数据记录:
// FATFS文件系统记录示例 FRESULT Log_Data(DHT11_Data data) { FIL file; char buffer[64]; FRESULT res; res = f_open(&file, "datalog.txt", FA_OPEN_APPEND | FA_WRITE); if (res != FR_OK) return res; sprintf(buffer, "%lu,%d.%d,%d.%d\r\n", get_timestamp(), data.temp_int, data.temp_frac, data.humi_int, data.humi_frac); UINT bw; res = f_write(&file, buffer, strlen(buffer), &bw); f_close(&file); return res; }3.3 多传感器集成框架
预留的扩展接口可以方便地添加新传感器:
// sensor_interface.h typedef struct { uint8_t (*init)(void); uint8_t (*read)(void *data); uint32_t interval; // 采样间隔(ms) } Sensor; // 传感器管理器 void SensorMgr_Add(Sensor *sensor); void SensorMgr_Run(void); // 使用示例 Sensor dht11_sensor = { .init = DHT11_Init, .read = DHT11_Read, .interval = 2000 };4. 实际应用案例
4.1 书房环境监测站
配置建议:
- 使用OLED显示实时数据
- 每30分钟记录一次数据到SD卡
- 当湿度超过70%时触发蜂鸣器报警
// 报警条件检测 void Check_Alarm(DHT11_Data data) { static uint8_t alarm_on = 0; if (data.humi_int > 70 || data.temp_int > 35) { if (!alarm_on) { Buzzer_On(); alarm_on = 1; } } else if (alarm_on) { Buzzer_Off(); alarm_on = 0; } }4.2 花房监控系统
特殊需求处理:
- 增加土壤湿度传感器(如电容式传感器)
- 集成光照强度检测(BH1750)
- 通过继电器控制补光灯和喷雾装置
硬件连接示意图:
[STM32F103] <-I2C-> [OLED] | | v v [DHT11] [BH1750] | v [Soil Moisture] | v [Relay Board]4.3 低成本方案实现
对于预算特别有限的场景:
- 省略显示模块,仅通过串口输出
- 用内置Flash替代SD卡存储(约可存储7天数据)
- 采用18650电池供电
// 内部Flash存储实现 #define DATA_ADDR 0x0801F000 void Save_To_Flash(DHT11_Data data) { FLASH_Unlock(); FLASH_ErasePage(DATA_ADDR); uint32_t temp = (data.temp_int << 24) | (data.temp_frac << 16) | (data.humi_int << 8) | data.humi_frac; FLASH_ProgramWord(DATA_ADDR, temp); FLASH_Lock(); }在完成基础功能后,我发现在实际部署中最常遇到的问题是电源干扰导致的传感器读数异常。通过增加10μF钽电容和0.1μF陶瓷电容并联到传感器电源端,同时缩短连接线长度,能显著提高系统稳定性。