51单片机驱动DHT11温湿度传感器——单总线通信
一、DHT11传感器概述
DHT11是一款非常经典的数字温湿度传感器,由广州奥松电子研发。它内部集成了一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连,直接输出已校准的数字信号。每个DHT11传感器出厂前都在精密的湿度校验室中进行校准,校准系数以程序形式储存在OTP内存中。
核心参数
| 参数 | 规格 |
|---|---|
| 供电电压 | 3V ~ 5.5V |
| 温度测量范围 | 0℃ ~ 50℃,精度 ±2℃ |
| 湿度测量范围 | 20% ~ 90% RH,精度 ±5% RH |
| 采样周期 | ≥1秒/次 |
| 待机电流 | 0.06mA,测量电流1.0mA |
信号传输距离可达20米以上,具有抗干扰能力强、性价比高等优点。
引脚说明
DHT11采用4针单排引脚封装:
-
VCC引脚:电源正极,接单片机3.3V或5V
-
GND引脚:电源负极,接单片机GND
-
DAT引脚:单总线数据引脚,接单片机P1.2(或任意I/O口)
-
NC引脚:空脚,不接
二、硬件电路设计
2.1 上拉电阻
DHT11采用漏极开路输出,因此数据线必须外接上拉电阻,使得总线空闲时保持高电平。
上拉电阻的阻值选择建议:
-
连接线长度 < 20米:使用 5kΩ 上拉电阻
-
连接线长度 > 20米:根据实际情况选择合适阻值
在代码对应的硬件中,main.h里定义了数据引脚:
sbit DHT11_IO = P1^2;

2.2 电源去耦
传感器上电后,需要等待约1秒以越过不稳定状态。为了提高稳定性,建议在VDD和GND之间并联一个100nF的陶瓷电容,用于滤除电源噪声。
2.3 硬件连接总结
| DHT11引脚 | 连接目标 |
|---|---|
| VCC | 单片机3.3V或5V |
| GND | 单片机GND |
| DAT | 单片机P1.2(通过5kΩ上拉电阻接VCC) |

三、单总线通信协议详解
3.1 什么是单总线(1-Wire)
DHT11采用简化的单总线通信方式。单总线即只有一根数据线,系统中的数据交换、控制均由这一根线完成。设备通过漏极开路或三态端口连接至数据线,在不发送数据时释放总线。
总线空闲状态为高电平。整个通信过程是主从结构,只有主机(单片机)呼叫从机(DHT11)时,从机才能应答。
3.2 通信过程概览
一次完整的通信过程如下图所示:

整个过程分为三个主要阶段:
-
开始信号:主机拉低总线,发起通信
-
数据传输:DHT11发送40位数据
-
结束信号:总线恢复高电平,进入空闲状态
3.3 第一阶段:开始信号

步骤1:主机拉低总线(至少18ms)
主机(单片机)先将数据线拉低,持续至少18ms的低电平。代码实现为:
DHT11_IO = 0;
Delay_xms(20); // 拉低20ms,超过18ms的最低要求
步骤2:主机拉高总线(20-40μs)
主机拉高总线,持续20-40μs:
DHT11_IO = 1;
Delay30us(); // 拉高约30μs
步骤3:DHT11响应(80μs低电平 + 80μs高电平)
DHT11检测到开始信号结束后,会发送响应信号:
-
先拉低总线 80μs,作为应答
-
再拉高总线 80μs,准备发送数据
代码通过循环检测总线状态来确认响应:
while(!DHT11_IO && count < 80) // 等待DHT11拉低(响应低电平)
{
_nop_();
count++;
}
while(DHT11_IO && count < 80) // 等待DHT11拉高(响应高电平)
{
_nop_();
count++;
}
如果检测到响应信号异常(超时),函数返回错误。
3.4 第二阶段:数据传输(40位)
握手成功后,DHT11开始传送40位数据。
数据格式

40位数据的格式为:
| 字节 | 内容 |
|---|---|
| 第1字节(8bit) | 湿度整数数据 |
| 第2字节(8bit) | 湿度小数数据(通常为0) |
| 第3字节(8bit) | 温度整数数据 |
| 第4字节(8bit) | 温度小数数据(通常为0) |
| 第5字节(8bit) | 校验和 |
高位先出(MSB First)。
校验和
校验和数据等于前四个字节相加所得结果的末8位:
校验和 = (湿度整数 + 湿度小数 + 温度整数 + 温度小数) & 0xFF
代码的校验逻辑:
if(dht_buf[0] + dht_buf[1] + dht_buf[2] + dht_buf[3] == dht_buf[4])
{
*humi = dht_buf[0];
*temp = dht_buf[2];
}
如果校验和不匹配,说明数据传输有误,函数返回错误。
每一位数据的传输方式

每一位数据都以50μs的低电平开始。随后是高电平,高电平的持续时间决定了该位是0还是1:
-
数据 '0':高电平持续 26-28μs
-
数据 '1':高电平持续 70μs
代码读取一个位的实现:
while(!DHT11_IO && count < 80) // 等待50μs低电平结束
{
_nop_();
count++;
}
Delay30us(); // 延时约30μs
if(1 == DHT11_IO) // 如果30μs后仍然是高电平 → 数据'1'
{
data_bit = 1;
while(DHT11_IO && count < 80) // 等待高电平结束
{
_nop_();
count++;
}
}
else // 30μs后已经是低电平 → 数据'0'
{
data_bit = 0;
}
这里的关键技巧是:延时30μs后检测电平——如果还是高电平,说明高电平至少持续了30μs,必然是数据'1'(因为数据'0'的高电平只持续26-28μs,30μs后已经变低了)。
3.5 第三阶段:结束信号
当最后一位数据传送完毕后,DHT11会拉低总线50μs,随后总线被上拉电阻拉高,进入空闲状态。
3.6 采样频率
DHT11的采样周期必须 ≥ 1秒。如果采集频率过高,传感器可能来不及完成新的测量,导致数据不准确。代码通过tim_count实现了1秒采集一次:
if(tim_count == 0)
{
if(1 == DHT11_Read(&humity, &temperature))
{
// 读取失败
}
else
{
// 显示数据
}
}
tim_count++;
tim_count = tim_count % 1000;
Delay_xms(1); // 每1ms累加一次,1000次正好1秒
四、代码实现解析
4.1 工程结构
项目采用模块化设计:
| 文件 | 功能 |
|---|---|
main.c |
主程序,OLED显示控制 |
dht11.c/h |
DHT11驱动程序 |
delay.c/h |
延时函数 |
iic.c/h |
IIC通信(用于OLED) |
oled.c/h |
OLED显示驱动 |
uart.c/h |
串口通信 |
4.2 DHT11驱动核心函数
DHT11_Start():发送开始信号并等待响应
DHT11_Read():读取40位数据,进行校验,返回温湿度值
4.3 延时函数的精确性
单总线通信对时序精度要求很高。代码针对11.0592MHz晶振设计了精确延时:
void Delay30us(void) // @11.0592MHz
{
unsigned char data i;
i = 11;
while (--i);
}
Delay30us()通过11次循环实现约30μs的延时,用于判断数据位是0还是1。
Delay_xms(20)实现20ms的延时,满足开始信号≥18ms的要求。
4.4 OLED显示
代码使用OLED显示屏显示温湿度数据:
OLED_ShowCHinese(0,0,0); // 温
OLED_ShowCHinese(18,0,1); // 湿
OLED_ShowCHinese(36,0,2); // 度
OLED_ShowCHinese(54,0,3); // 检
OLED_ShowCHinese(72,0,4); // 测
OLED_ShowCHinese(90,0,5); // 系
OLED_ShowCHinese(108,0,6); // 统
sprintf(buf,"H:%u%% T:%uC", (uint)humity, (uint)temperature);
OLED_ShowString(0,4,buf,16);
显示效果为"温湿度检测系统"标题,下方显示"H:xx% T:xxC"。
五、常见问题与调试技巧
5.1 读取失败(返回1)
可能的原因:
-
接线错误:检查VCC、GND、DAT是否连接正确
-
上拉电阻缺失:DAT引脚必须接上拉电阻
-
时序不匹配:晶振频率不同导致延时不准
-
电源不稳定:添加100nF去耦电容
5.2 数据跳变或异常
-
采样频率过快:确保采集间隔≥1秒
-
电源噪声:检查电源质量,靠近传感器放置去耦电容
-
总线干扰:数据线尽量短,远离高频信号源
5.3 调试建议
-
使用逻辑分析仪或示波器抓取总线波形,验证时序
-
通过串口输出原始数据,观察校验和是否正确
-
在关键位置添加LED指示,便于观察程序运行状态
六、总结
DHT11的单总线通信虽然协议简单,但对时序要求严格。理解其通信的三个阶段——开始信号、数据传输(40位)、结束信号——是成功驱动的关键。通过精确的延时控制和数据校验机制,我们可以在51单片机上稳定地读取温湿度数据。
完整的代码工程已开源,包含了DHT11驱动、OLED显示、串口输出等功能模块,可作为学习单总线通信和嵌入式开发的参考项目。
更多推荐
所有评论(0)