目录
[2.1 电气特性](#2.1 电气特性)
[2.2 引脚说明](#2.2 引脚说明)
[2.3 温湿度测试性能](#2.3 温湿度测试性能)
[3.1 DHT11简化单总线协议说明](#3.1 DHT11简化单总线协议说明)
[3.2 DHT11单总线数据格式](#3.2 DHT11单总线数据格式)
[3.3 DHT11通信时序说明](#3.3 DHT11通信时序说明)
[3.4 主从通信步骤](#3.4 主从通信步骤)
[3.5 注意事项](#3.5 注意事项)
[4.1 DHT11驱动代码](#4.1 DHT11驱动代码)
[4.2 主函数代码](#4.2 主函数代码)
[4.3 测试效果](#4.3 测试效果)
引言
本次学习一款温湿度传感器DHT11,学习之前需要具备STM32基础知识以及C语言基础。同时,本次学习我们参考奥松的温湿度模块 DHT11 产品手册进行DHT11的驱动代码编写。
一、DHT11概述
DHT11是一款含有已校准数字信号输出的温湿度 复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。
DHT11温湿度传感器应用广泛,常见于暖通空调、除湿器、农业、冷链仓储、测试及检测设备、消费品、 汽车、自动控制、数据记录器、气象站、家电、湿度调节器、医疗、其他相关湿度检测控制。
DHT11具有成本低、长期稳定、相对湿度和温度测量、品质卓越、超快响应、抗干扰能力强、超长的 信号传输距离、数字信号输出、精确校准等优点。

二、相关参数
2.1 电气特性

使用时一定要注意DHT11的供电电压范围,尽可能处于给定范围之间,避免电压过低或过高影响测量效果。
2.2 引脚说明
1、VDD供电3.3~5.5VDC
2、DATA串行数据,单总线
3、NC空脚(通常不引出)
4、GND接地,电源负极
2.3 温湿度测试性能

可见,DHT11的相对湿度测量范围是5~95 %RH。其中在温度为25℃时,精度±5 %RH等。

可见,DHT11的温度测量范围是-20~60℃,其中在温度为25℃时,±2℃的浮动范围等。
三、通信方式(单线双向)
3.1 DHT11简化单总线协议说明
手册上写的已经非常详细了,这里就不再赘述,直接上截图了,相信大家也能理解,如下图所示。

3.2 DHT11单总线数据格式


3.3 DHT11通信时序说明
如下图为DHT11与微控制器(主设备)进行通信时的数据时序图。


3.4 主从通信步骤
主机和从机之间的通信可通过如下几个步骤完成(外设(如微处理器)读取DHT11的数据 的步骤)。
1、DHT11上电后等待1s稳定后处于输入状态,检测外部信号,此时总线空闲,默认拉高;
2、主机获取总线控制权,并拉低总线18~30ms,随后释放总线。总线空闲,默认拉高;
3、DHT11占据总线,拉低总线83us,产生应答;接着拉高总线87us,提示主机准备接收数据;
此时,对于主机来说,即检测总线是否拉低判断DHT11是否产生应答,接着若应答了,则继续等待DHT1应答信号结束,接着等待DHT11的拉高结束,完成响应信号的时序。
4、DHT继续占据总线,开始连续发送40位数据。发送数据"0",DHT11先拉低总线54us,再拉高总线23~27us;发送数据"1",DHT11先拉低总线54us,再拉低总线68~74us,连续重复40次;
对于主机来说,即读取每一位数据,连续8次进而读取一字节数据,连续读取5次字节数据进而获取完整40位数据。所以理解读取一位数据的方法即可以此类推。
这个**过程为:**读取总线电平,等待总线拉低完成,接着延迟30us越过出现数据0的时序(便于同时进行数据0或1的接收),然后读取总线电平,若为低说明此时DHT11发送的确实是数据"1",反之发送的是数据"0",最后若为数据1则继续等待总线拉高完成,反之则一位数据读取结束。
5、DHT11发送完40位数据后,会先拉低总线54us后自动释放总线,使总线空闲,默认拉高。
此时DHT11释放总线后,总线会处于空闲状态,此时需要等待DHT11内部重测温湿度数据并记录。故DHT11产生停止信号后主机不必恢复占据空闲的总线,影响DHT11的数据记录以及后续的通信。此时让总线空闲,自由时序即可。
最后,主机记录好40位数据,并进行校验,没有问题说明接受的数据无误,串口输出数据即可。
3.5 注意事项

四、参考代码(基于STM32)
最后,我们基于STM32的寄存器方式编写一下DHT11的驱动代码,实现串口打印温湿度数据。
4.1 DHT11驱动代码
1、dht111.h
cpp
/*
* @Descripttion: DHT11驱动程序(寄存器方式)
* @Author: JaRyon
* @version: v1.0
* @Date: 2025-10-10 21:56:32
*/
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"
#include "usart.h"
#include "Delay.h"
// 数据线状态
#define DHT11_SDA_HIGH() {GPIOA->BSRR |= GPIO_BSRR_BR5;} // 拉高
#define DHT11_SDA_LOW() {GPIOA->BRR |= GPIO_BRR_BR5;} // 拉低
// 读数据
#define DHT11_READ (GPIOA->IDR & GPIO_IDR_IDR5) // 读电平
// 应答与非应答
#define ACK 0
#define NACK 1
// 输入输出模式
typedef enum
{
INPUT_MODE = 1,
OUTPUT_MODE
}IOMode;
// 函数声明
// 配置初始化
void DHT11_Init(void);
// IO模式设置
void DHT11_SetIOMode(IOMode mode);
// 发送起始信号
void DHT11_Start(void);
// 等待DHT11响应
int8_t DHT11_Wait4Ack(void);
// 接收DHT11的一位数据
int8_t DHT11_ReadBit(void);
// 接收DHT11的一字节数据
int8_t DHT11_ReadByte(void);
// 读取DHT11发送的数据
// int8_t DHT11_GetHumTemp(int16_t *hunitidy, int16_t *temperature);
uint8_t DHT11_GetHumTemp(uint8_t *buffer);
#endif
2、dht11.c
cpp
/*
* @Descripttion: DHT11驱动程序(寄存器方式)
* @Author: JaRyon
* @version: v1.0
* @Date: 2025-10-10 21:56:32
*/
#include "dht11.h"
/**
* @brief DHT11初始化函数
* @return None
*/
void DHT11_Init(void)
{
// 开漏输出 PA5 mode-11 cnf-01
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL |= GPIO_CRL_MODE5;
GPIOA->CRL &= ~GPIO_CRL_CNF5_1;
GPIOA->CRL |= GPIO_CRL_CNF5_0;
DHT11_SDA_HIGH();
}
/**
* @brief 设置DHT11引脚模式
* @param mode: 输入模式或输出模式
* @return None
*/
void DHT11_SetIOMode(IOMode mode)
{
switch (mode)
{
case INPUT_MODE: // 浮空输入
GPIOA->CRL &= ~(GPIO_CRL_MODE5 | GPIO_CRL_CNF5_1);
GPIOA->CRL |= GPIO_CRL_CNF5_0;
break;
case OUTPUT_MODE: // 开漏输出
GPIOA->CRL |= GPIO_CRL_MODE5;
GPIOA->CRL &= ~GPIO_CRL_CNF5_1;
GPIOA->CRL |= GPIO_CRL_CNF5_0;
break;
default:
break;
}
}
/**
* @brief 发送起始信号
* @return None
*/
void DHT11_Start(void)
{
// 1. 主机占用总线
DHT11_SetIOMode(OUTPUT_MODE);
// 2. SDA拉低, 发出起始信号
DHT11_SDA_LOW();
Delay_ms(20);
// 3. 主机释放总线
DHT11_SDA_HIGH();
DHT11_SetIOMode(INPUT_MODE);
Delay_us(20);
}
/**
* @brief 等待DHT11响应
* @return ACK表示成功,NACK表示失败
* @attention 利用循环等待结束,避免延时超过或提前造成时序差错
*/
int8_t DHT11_Wait4Ack(void)
{
// 1. 出现应答信号
if (!DHT11_READ)
{
// 2. 等待DHT11拉低应答完成
while (!DHT11_READ);
// 3. 等待DHT11拉高完成,准备接收数据
while (DHT11_READ);
return ACK;
}
return NACK;
}
/**
* @brief 读取一个位的数据
* @return 读取到的位值(0或1)
* @attention 利用循环等待结束,避免延时超过或提前造成时序差错
*/
// 接收DHT11的一位数据
int8_t DHT11_ReadBit(void)
{
int8_t bit = 0x00;
// 1. 等待总线低电平结束
while (!DHT11_READ);
// 2. 延时后接收数据
Delay_us(28);
if (DHT11_READ)
{
bit = 1;
// 3. 等待总线高电平结束
while (DHT11_READ);
}
else
{
bit = 0;
}
return bit;
}
/**
* @brief 读取一个字节的数据
* @return 读取到的字节值
*/
int8_t DHT11_ReadByte(void)
{
int8_t byte = 0x00;
for (uint8_t i = 0; i < 8; i++)
{
byte <<= 1;
byte |= (DHT11_ReadBit() & 0x01);
}
return byte;
}
/**
* @brief 获取温湿度数据
* @param buffer: 存储数据的缓冲区
* @return 1表示成功,0表示失败
* @attention DHT11自动释放总线,不用手动干预,且逻辑非的判断可能影响时序
*/
uint8_t DHT11_GetHumTemp(uint8_t *buffer)
{
// 发送起始信号并等待响应
DHT11_Start();
if (DHT11_Wait4Ack() == NACK)
{
return NACK; // 响应失败
}
// 读取5个字节的数据
for (uint8_t i = 0; i < 5; i++)
{
buffer[i] = DHT11_ReadByte();
}
// 校验数据
return (buffer[0] + buffer[1] + buffer[2] + buffer[3] == buffer[4]) ? 1 : 0;
}
4.2 主函数代码
cpp
/*
* @Descripttion: 串口打印DHT11测量的温湿度数据(基于寄存器实现)
* @Author: JaRyon
* @version: v1.0
* @Date: 2025-10-10 21:56:32
*/
// DHT11对时序要求比较严格,需要严格按照指定时序接收数据
//时序模拟过程中尽可能减少无关指令
/* 引脚定义
DHT11:
VCC ---> 3.3/5V
DATA ---> PA5
GND ---> GND
CH340:
5V ---> 5V
GND ---> GND
TX ---> PA10
RX ---> PA9
*/
#include "stm32f10x.h"
#include "usart.h"
#include "dht11.h"
int main(void)
{
uint8_t DHT11_Data[5] = {0}; // 存储温湿度数据的缓冲区
uint8_t readRes; // 读取结果标志
USART_Init();
DHT11_Init();
while (1)
{
// 读取温湿度数据
readRes = DHT11_GetHumTemp(DHT11_Data);
if (readRes)
{
// 数据读取成功,打印结果
printf("Read Success!\r\n");
printf("---------------------\r\n");
printf("humidity: %d.%d %%RH \r\n", DHT11_Data[0], DHT11_Data[1]);
printf("temperature: %d.%d C \r\n", DHT11_Data[2], DHT11_Data[3]);
for (uint8_t i = 0; i < 5; i++)
{
printf("DHT11_Data[%d] = %d\n", i, *(DHT11_Data + i));
}
printf("CRC: 0x%02X \r\n", DHT11_Data[4]);
}
else
{
// 数据读取失败
printf("Check Connected!\r\n");
}
printf("---------------------\r\n");
// 每3秒读取一次
Delay_ms(3000);
}
}
4.3 测试效果

参考资料
DHT11 奥松-ASAIR_PDF_数据手册 | 电容式温湿度传感器模块
以上便是本次文章的所有内容,欢迎各位朋友在评论区讨论,本人也是一名初学小白,愿大家共同努力,一起进步吧!
鉴于笔者能力有限,难免出现一些纰漏和不足,望大家在评论区批评指正,谢谢!