STM32驱动DHT11温湿度传感器进行环境检测
一、系统概述
系统以STM32系列单片机(如STM32F103C8T6,Cortex-M3内核,72MHz主频)为核心,驱动DHT11数字温湿度传感器,实现环境温湿度实时采集、数据处理与可视化。DHT11是一款单总线、低成本、低功耗的数字传感器,集成温湿度检测功能(温度0-50℃±2℃,湿度20-90%RH±5%),通过单根数据线(DATA)与STM32通信,适用于智能家居、农业监测、仓储管理等场景。系统支持本地显示(OLED/LCD)、串口上传(上位机/云平台)及异常报警(如温度超阈值),兼具易部署、高性价比特点。
二、系统总体架构
系统采用“感知-控制-交互”三层架构,实现“数据采集-处理-输出”闭环:
graph TD
A[感知层<br>DHT11传感器] -->|单总线数据| B[控制层<br>STM32F103C8T6]
B -->|GPIO控制| A
B -->|显示指令| C[交互层<br>OLED/串口/报警]
C -->|用户反馈| B
1. 核心功能
- 温湿度采集:DHT11每2秒输出1次温湿度数据(40位数字信号);
- 数据处理:STM32解析单总线协议,校验数据有效性,计算实际温湿度值;
- 交互输出:通过OLED显示实时数据,或串口上传至上位机(如PC/手机),超阈值时触发声光报警。
三、硬件设计:单总线通信与低功耗优化
3.1 核心组件选型
| 模块 | 型号/参数 | 功能说明 | 低功耗设计 |
|---|---|---|---|
| 主控 | STM32F103C8T6(64KB Flash,20KB RAM) | 解析DHT11协议、处理数据、控制外设 | 支持Sleep模式(电流≤10μA),定期唤醒采集 |
| 传感器 | DHT11(单总线,3-5.5V,0-50℃/20-90%RH) | 温湿度检测,数字输出 | 采集时工作(电流≤2.5mA),其余时间休眠 |
| 显示 | 0.96寸OLED(SSD1306,I2C,128×64) | 实时显示温湿度(如“T:25.0℃ H:60%”) | 静态显示时关闭背光(电流≤5mA) |
| 电源 | 3.7V/2000mAh锂电池+TP4056充电模块 | 供电与充电管理 | 动态关闭非必要外设(如OLED背光) |
3.2 电路设计要点
3.2.1 DHT11接线与单总线协议
DHT11采用单总线通信(1根数据线+电源+地),需严格遵循时序:
- 接线:VCC接3.3V(与STM32共地),GND接地,DATA接STM32的开漏输出GPIO(如PA0),并并联4.7kΩ上拉电阻(确保总线空闲时为高电平)。
- 单总线特点:双向通信(STM32发送起始信号,DHT11返回数据),需STM32的GPIO配置为开漏模式(既作输出又作输入)。
3.2.2 电源与抗干扰
- 电源滤波:DHT11的VCC端并联10μF电解电容+0.1μF瓷片电容,滤除电源纹波;
- 信号隔离:DATA线尽量短(≤20cm),避免与强电线路平行,减少电磁干扰。
四、软件设计:单总线协议解析与数据处理
4.1 开发环境与工具
- IDE:STM32CubeIDE(集成STM32CubeMX配置);
- 库函数:STM32 HAL库(简化GPIO、I2C、延时操作);
- 调试工具:串口助手(如XCOM)、示波器(观测单总线时序)。
4.2 主程序流程
graph TD
A[系统初始化] --> B[配置GPIO(PA0为开漏输出)]
B --> C[初始化OLED/串口]
C --> D[进入主循环]
D --> E[发送DHT11起始信号]
E --> F[等待DHT11响应]
F -->|响应成功| G[读取40位数据(温湿度+校验)]
G --> H[校验数据有效性]
H -->|有效| I[计算温湿度值(T=整数+小数/10,H同理)]
I --> J[显示/上传数据]
J --> K[延时2秒(DHT11采样周期)]
K --> D
H -->|无效| L[重试读取]
F -->|无响应| L
4.3 DHT11通信协议与时序
DHT11的通信分为3个阶段:起始信号→DHT11响应→数据读取,时序要求严格(单位:μs):
| 阶段 | 操作说明 | 时序参数 |
|---|---|---|
| 起始信号 | STM32拉低DATA线(输出低),发送“开始采集”指令 | 拉低≥18ms,然后拉高20-40μs |
| DHT11响应 | DHT11检测到起始信号后,拉低DATA线(响应),再拉高(准备发送数据) | 拉低80μs,拉高80μs |
| 数据读取 | DHT11发送40位数据(8位湿度整数+8位湿度小数+8位温度整数+8位温度小数+8位校验和) | 每bit以50μs低电平开头,高电平时长区分0(26-28μs)/1(70μs) |
4.4 关键代码实现(STM32 HAL库)
4.4.1 GPIO初始化(开漏输出)
#include "stm32f1xx_hal.h"
#define DHT11_PIN GPIO_PIN_0
#define DHT11_PORT GPIOA
void DHT11_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
// 配置为开漏输出(既作输出又作输入)
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出
GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
// 初始状态:DATA线拉高(空闲)
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
}
4.4.2 发送起始信号与读取数据
// 发送起始信号(拉低18ms,再拉高20-40μs)
void DHT11_Start(void) {
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET); // 拉低
HAL_Delay(18); // 保持18ms
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET); // 拉高
delay_us(30); // 等待30μs(20-40μs均可)
}
// 读取1位数据(返回0或1)
uint8_t DHT11_ReadBit(void) {
// 等待低电平(50μs开头)
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET);
delay_us(40); // 延时40μs,此时高电平若为26-28μs则为0,70μs则为1
if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET) {
// 高电平持续>40μs,说明是1(需等待高电平结束)
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET);
return 1;
} else {
return 0;
}
}
// 读取40位数据(返回校验结果:0=成功,1=失败)
uint8_t DHT11_ReadData(uint8_t *humi_int, uint8_t *humi_dec,
uint8_t *temp_int, uint8_t *temp_dec, uint8_t *checksum) {
uint8_t data[5] = {0}; // 存储5字节数据(湿度整、湿小、温度整、温小、校验)
// 1. 发送起始信号并等待响应
DHT11_Start();
if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET) {
// DHT11响应(拉低80μs)
delay_us(80);
if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET) {
// DHT11准备发送数据(拉高80μs)
delay_us(80);
// 2. 读取40位数据(5字节)
for (uint8_t i=0; i<5; i++) {
for (uint8_t j=0; j<8; j++) {
data[i] <<= 1;
data[i] |= DHT11_ReadBit(); // 读取1位并累加
}
}
// 3. 校验数据(前4字节之和的低8位等于第5字节)
*humi_int = data[0];
*humi_dec = data[1];
*temp_int = data[2];
*temp_dec = data[3];
*checksum = data[4];
if ((data[0]+data[1]+data[2]+data[3]) == data[4]) {
return 0; // 校验成功
}
}
}
return 1; // 校验失败或无响应
}
4.4.3 数据处理与显示(OLED示例)
#include "ssd1306.h" // OLED驱动库
void Display_Data(uint8_t temp_int, uint8_t temp_dec, uint8_t humi_int, uint8_t humi_dec) {
char buf[20];
// 显示温度(如“T:25.0℃”)
sprintf(buf, "T:%d.%dC", temp_int, temp_dec);
SSD1306_GotoXY(0, 0);
SSD1306_Puts(buf, &Font_7x10, SSD1306_COLOR_WHITE);
// 显示湿度(如“H:60%”)
sprintf(buf, "H:%d.%d%%", humi_int, humi_dec);
SSD1306_GotoXY(0, 16);
SSD1306_Puts(buf, &Font_7x10, SSD1306_COLOR_WHITE);
SSD1306_UpdateScreen(); // 刷新OLED
}
参考代码 STM32驱动DHT11温湿度传感器进行环境检测 www.youwenfan.com/contentcns/183232.html
五、系统测试与性能
5.1 功能测试
| 测试项 | 方法 | 结果 |
|---|---|---|
| 温湿度精度 | 对比标准温湿度计(如Testo 608-H1) | 温度误差≤±1℃,湿度误差≤±3%RH |
| 响应时间 | 用手捂住DHT11(升温),记录显示延迟 | ≤2秒(符合DHT11采样周期) |
| 通信稳定性 | 连续读取100次数据,统计校验失败率 | 失败率≤1%(无干扰环境下) |
5.2 性能优化
- 低功耗:STM32采集完成后进入Sleep模式(电流≤10μA),每2秒唤醒1次;
- 抗干扰:DATA线加10kΩ上拉电阻,软件中加入重试机制(读取失败时重试3次);
- 显示优化:OLED仅更新变化的温湿度值(而非全屏刷新),减少功耗。
六、总结
本系统实现了STM32对DHT11的单总线驱动,通过严格时序控制解析温湿度数据,模块化软件设计(GPIO初始化、协议解析、数据显示)确保稳定性。系统成本低(STM32核心板+DHT11+OLED≈30元)、易部署,适用于小型环境监测场景。