STM32与DHT11传感器集成使用指南——速成教程
DHT11 是一款常用的数字温湿度传感器,它内部集成了 NTC 温度传感器 和 电容式湿度传感器,并带有 单总线数字输出接口。采集温湿度的原理可以分为两个部分:
一、硬件测量原理
1. 湿度测量
DHT11 使用 电容式湿度传感器 来测量空气湿度。
电容器的介质对空气中的水分敏感,湿度变化会导致电容值变化。
传感器内部会将电容值变化转换成数字信号。
2. 温度测量
使用 NTC 热敏电阻(负温度系数),温度升高时电阻减小。
模拟信号通过 A/D 转换器转换为数字温度值。
二、硬件参数一览表
1. DHT11模组
如下图

| 参数类别 | 项目 | 参数值 |
|---|---|---|
| 电气特性 | 工作电压 | 3.3V ~ 5.5V(针对于DHT11模组) |
| 最大电流(采样时) | ~2.5mA | |
| 静态电流 | ~60µA | |
| 湿度测量 | 测量范围 | 20%RH ~ 90%RH |
| 精度 | ±5%RH | |
| 分辨率 | 1%RH | |
| 响应时间 | <5s | |
| 温度测量 | 测量范围 | 0°C ~ 50°C |
| 精度 | ±2°C | |
| 分辨率 | 1°C | |
| 响应时间 | <5s | |
| 输出 | 通信方式 | 单总线数字信号 |
| 输出格式 | 40位(8湿度高 + 8湿度低 + 8温度高 + 8温度低 + 校验) | |
| 其他 | 封装 | 4-pin 单排直插封装(蓝色外壳) |
| 尺寸 | 15.5mm x 12mm x 5.5mm | |
| 推荐采样周期 | ≥1秒 | |
| 使用寿命 | ≥10 万次测量 |
DHT11模组:数据线需接上拉电阻(建议 10kΩ)以实现单总线闲置时,其处于高电平状态
2.注意事项
读取间隔应 ≥1 秒,频繁读取会导致数据错误
湿度和温度精度相对较低,不适合对精度要求高的场合
避免在强腐蚀、强磁场、高静电等环境下使用
三、数据通信原理(单总线协议)
1. 主机启动信号(MCU → DHT11)
| 动作 | 参数 | 注意事项 |
|---|---|---|
| MCU拉低数据线 | 18~30ms(推荐20ms) | 确保DHT11检测到启动信号(时间不足可能导致无响应) |
| MCU释放总线(拉高) | 20~40μs(推荐30us) | 释放后需切换GPIO为输入模式(否则无法接收DHT11响应) |
目的:MCU通过输出启动信号唤醒DHT11并触发数据采集;MCU再切换至输入模式等待DHT11的自检测
/****************************************************************************
函数名称:void DHT11_Start(void)
函数参数:无
函数返回值:无
描述:MCU启动DHT11+MCU等待DHT11的数据输入
****************************************************************************/
void DHT11_Start(void)
{
DHT11_OUT(); //设置为推挽输出模式
DHT11_DQ_L; //设置输出模式为0
Delay_ms(20); // 拉低至少18ms
DHT11_DQ_H; //设置输出模式为1,确保0输出的时间维持在18~30ms之间
Delay_us(30); // 拉高 20~40us
DHT11_IN(); // 切换为输入模式,等待响应
}
2. DHT11自检阶段(DHT11 → MCU)
主机检测到:
-
数据线被 DHT11 拉低(约 80us)
-
然后数据线被拉高(约 80us)
这两个阶段构成了完整的 “自检测信号”。
DHT11 的自检测信号就是“80us低 + 80us高”的响应时序
也就是说DHT11在响应阶段一直给MCU发送一个周期为160us的周期信号
主机在发送起始信号后必须正确检测这个过程,否则说明模块未连接或损坏。这个过程是数据传输的关键前提。
| 信号变化 | 时间 | 检测方法 |
|---|---|---|
| DHT11拉低总线 | 持续约80μs | DHT11 会拉低表示响应主机,主机需检测到低电平 |
| DHT11拉高总线 | 持续约80μs | DHT11 拉高准备发送数据;主机需检测到高低电平 |
目的:DHT11自检测功能,确保DHT11能稳定输出高低电平并且在输出一定时长的高电平后进行数据传输
/****************************************************************************
函数名称:uint8_t DHT11_Check(void)
函数参数:无
函数返回值:返回值:1:失败 0:成功
描述:
第一个 while:目的是等待DHT11对MCU响应的低电平
1.在启动信号发出后,若高电平持续时长>=100us,即DHT11未对MCU响应的低电平,DHT11自检失败;返回1
2.在启动信号发出后,若高电平持续时长<=100us,即DHT11对MCU响应的低电平
第二个 while:目的是等待DHT11对MCU响应的高电平
1.在DHT11对MCU响应的低电平后,若低电平持续时长>=100us,即DHT11自检失败;返回1
2.在DHT11对MCU响应的低电平后,若低电平持续时长<=100us,即DHT11对MCU响应的高电平,自检成功;返回0
****************************************************************************/
uint8_t DHT11_Check(void)
{
uint8_t retry = 0;
while(DHT11_READ && retry < 100) // 等待 DHT11 拉低响应
{
retry++;
Delay_us(1);
}
if(retry >= 100) return 1;
retry = 0;
while(!DHT11_READ && retry < 100) // 等待 DHT11 拉高
{
retry++;
Delay_us(1);
}
return (retry >= 100) ? 1 : 0;
}
3. 数据传输阶段(DHT11 → MCU)
(1)数据帧分析
DHT11 一次传输共 40 位数据,即 5 个字节,按照如下顺序发送:
数据帧构成:
[ 8位湿度整数 ] + [ 8位湿度小数 ] + [ 8位温度整数 ] + [ 8位温度小数 ] + [ 8位校验和 ]
数据格式说明:
| 字节序号 | 名称 | 内容示例 |
|---|---|---|
| Byte 1 | 湿度整数部分 | 25(即 25%RH) |
| Byte 2 | 湿度小数部分 | 0(通常为 0) |
| Byte 3 | 温度整数部分 | 26(即 26°C) |
| Byte 4 | 温度小数部分 | 0(通常为 0) |
| Byte 5 | 校验和(Checksum) | Byte1+Byte2+Byte3+Byte4 的和,对 256 取余 |
举个例子:
如果 DHT11 发送以下 5 个字节数据(十六进制):
湿度整数 湿度小数 温度整数 温度小数 校验和
0x19 0x00 0x1A 0x00 0x33
换算后:
湿度:0x19 = 25%RH
温度:0x1A = 26°C
校验:0x19 + 0x00 + 0x1A + 0x00 = 0x33
注意:如果接收到的数据和与校验和不一致,说明本次通信有误,应丢弃本次数据。
(2)数据传输分析
DHT11 的单个位传输时序
每一位数据的时序如下:
| 阶段 | 状态 | 持续时间 |
|---|---|---|
| DHT11 拉低 | 固定为 50μs | 表示准备发送一个 bit |
| DHT11 拉高 | 26~28μs 表示 0;70μs 表示 1 | 主机据此判断是 0 还是 1 |
/****************************************************************************
函数名称:uint8_t DHT11_Read_Bit(void),从DHT11的数据线上读取1位数据
函数参数:无;
函数返回值:0:该位数据为0 1:该位数据为1 0XFF:超时,返回错误标志(非法值)
描述:
第一个 while:目的等待50us的低电平作为数据传输的初始信号
1.在DHT11自检测成功后,若高电平持续时长>=100us,
即为超时,DHT11未对MCU响应的低电平,DHT11未准备发送一个 bit,返回0XFF非法值
2.在DHT11自检测成功后,若高电平持续时长<=100us,
即DHT11未对MCU响应的低电平,(执行下一个while)来确保输入的数据是1还是0
第二个 while:目的确定高电平信号的持续时间来判断输入的数据是1还是0
1.等待接收高电平信号,若低电平持续时长>=100us,即为超时,该数据有问题,返回0XFF非法值
2.等待接收高电平信号,若低电平持续时长<=100us,则接收到到高电平信号,
在40us后再次测量此电平信号来确定改位的数据是0还是1,返回0或1
****************************************************************************/
uint8_t DHT11_Read_Bit(void)
{
uint8_t retry = 0;
// 1. 等待 DHT11 拉低(开始发送位)
while(DHT11_READ)
{
if (++retry > 100)
return 0xFF; // 低电平等待超时
Delay_us(1);
}
// 2. 等待 DHT11 拉高(开始计时)
retry = 0;
while(!DHT11_READ)
{
if (++retry > 100)
return 0xFF; // 高电平等待超时
Delay_us(1);
}
// 3. 延迟 40us 后读取电平判断是 0 还是 1
Delay_us(40);
return DHT11_READ ? 1 : 0;
}
进阶整理到一个字节接收
/****************************************************************************
函数名称:uint8_t DHT11_Read_Byte(void)
函数参数:0XFF数据采集失败
函数返回值:无
描述:采集一个字节的数据
****************************************************************************/
uint8_t DHT11_Read_Byte(void)
{
uint8_t i, data = 0,bit;
for(i = 0; i < 8; i++)
{
bit = DHT11_Read_Bit(); // 读取一位
if(bit == 0xFF) return 0xFF; // 超时错误
data <<= 1; // 左移准备放下一个 bit
data |= bit; // 累加当前 bit 到低位
}
return data;
}
关于器件的原理就是这些,剩下的就是基本功了。
完整代码:https://github.com/SusuperPeng/STM32_Commonly_Used_Sensors/tree/STM32-DHT11
作者:<<梅干菜