前言:
DHT11是我们学习单片机中比较常见传感器,它将测量温湿度的功能结合到了一起,使我们可以精确地器件周围的温度和湿度,在一些比赛项目中,我们也能经常看到它的身影。不止在比赛项目中,这个器件的使用范围可谓是十分广泛:暖通空调、除湿器、农业、冷链仓储,自动控制、数据记录器、气象站、家电等等。因此学会使用这个器件,我们也能在很多项目用上,收益很高。
DHT11介绍:
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器电容式感湿元件和NTC测温元件。
DHT产品实物图(图片来源于网络)
DHT11接线:
DHT典型电路应用
产品手册建议连接线长度短于5m时用4.7K上拉电阻,大于5m时根据实际情况降 低上拉电阻的阻值。另外使用3.3V电压供电时连接线尽量短,接线过长会导致传感器供电不足,造成测量偏差。
鉴于很多市面上的一些产品通常把这电路部分和传感器本身集成为一个模块(如实物图右1),上拉电阻通常是不需要使用者外接的,直接将DATA与单片机连接即可,十分方便。
引脚1 | VCC |
引脚2 | IO口 |
引脚3 | NC(悬空) |
引脚4 | GND |
DHT11通信说明:
1.通信协议
DHT11温湿度模块采用半双工的简化单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。单总线通常要求外接一个约 4.7kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。
DHT11传感器与控制的通讯采用单总线数据格式,一次传送40位数据, 高位先出。
数据格式: 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位。
数据校核:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据 = 8bit校验位
如果不满足上述等式,则数据无效,舍弃。
2.时序步骤分析 
DHT11与控制器数据通信传输格式
步骤一:DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平; 此时DHT11的DATA引脚处于输入状态,时刻检测外部信号。
步骤二:控制器的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),然后控制器的I/O设置为输入状态,由于上拉电阻,控制器的I/O即DHT11的 DATA数据线也随之变高,等待DHT11作出回答信号。
步骤三:DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知外设准备接收数据,控制器的I/O此时处于输入状态,检测到I/O有低电平(DHT11回应信号) 后,等待87微秒的高电平后的数据接收。
步骤四:由DHT11的DATA引脚输出40位数据,控制器根据I/O电平的变化接收40位数据,位数据 “0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低 电平加68-74微秒的高电平。
步骤五(结束信号):DHT11的DATA引脚输出40位数据后,继续输出低电平54微秒后转为输入状态,由于上拉电阻随之变为高电平。但DHT11内部重测环境温湿度数据,并记录数据,等待外部信号的到来。
3.时序细节补充
单总线特性信号补充
产品手册提到:为保证传感器的准确通讯,用户在读取信号时,请严格按照时序图和上表给定参数读取数据。
DHT11参考代码
下面是作者自己根据产品手册敲的代码,设置了超时机制,工程仅供参考,若有错误随时指出,非常感谢!
#include "stm32f10x.h" // Device header
#include "Delay.h"
uint8_t DHTData[5] = {0,0,0,0,0}; //数据容器,外部使用时记得声明
/*
函数:初始化IO口为推挽输出,用于主机发送读取指令
参数:无
返回值:无
*/
void DHT11_Out_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
/*
函数:初始化IO口为浮空输入,用于DHT11传输数据和响应读取信号
参数:无
返回值:无
*/
void DHT11_In_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
/*
函数:初始化DHT11,DHT11温湿度模块上电需要后需要1s的启动时间
参数:无
返回值:无
*/
void DHT11_Init()
{
DHT11_Out_Init();
Delay_ms(1000);
}
/*
函数:读取DHT11一个字节的数据
参数:无
返回值:读取到的数据
*/
uint8_t DHT11_ReadByte()
{
uint8_t Data = 0;
uint8_t i = 0;
for(i = 0;i<8;i++)
{
uint8_t tmp = 0;//定义临时变量存放Data里面的每一位
uint8_t timeOut_Count = 0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1 && timeOut_Count < 100)
{
Delay_us(1);
timeOut_Count++;
}
timeOut_Count = 0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 0 && timeOut_Count < 100)
{
Delay_us(1);
timeOut_Count++;
}
timeOut_Count = 0;
Delay_us(30);//延时30us - 表示0的区间在26-28us,如果延时超过28s还没有跳变为低电平,说明表示的是1
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1)
tmp = 1;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1 && timeOut_Count < 100)//等待1剩余的时间
{
Delay_us(1);
timeOut_Count++;
}
Data <<= 1;
Data |= tmp;
}
return Data;
}
/*
函数:读取DHT11温湿度模块一轮的数据
参数:无
返回值:1 --- 读取成功
0 --- 读取失败
*/
uint8_t DHT11_ReadData()
{
uint8_t i = 0;
uint8_t timeOut_Count = 0;
DHT11_Out_Init();//主机掌控总线控制权
GPIO_SetBits(GPIOA,GPIO_Pin_9);
Delay_us(30);
GPIO_ResetBits(GPIOA,GPIO_Pin_9);//主机向从机发送读取的请求
Delay_ms(20);//拉低至少18ms但不能超过30ms
GPIO_SetBits(GPIOA,GPIO_Pin_9);//主机拉高总线,准备等待从机回应
Delay_us(30);
DHT11_In_Init();//主机让出总线控制权
GPIO_SetBits(GPIOA,GPIO_Pin_9);
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1 && timeOut_Count < 100)
{
Delay_us(1);
timeOut_Count++;
}//等待从机响应信号
timeOut_Count = 0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 0 && timeOut_Count < 100)
{
Delay_us(1);
timeOut_Count++;
}//等待从机准备输出信号
timeOut_Count = 0;
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1)
{
for(i = 0;i < 5;i++)
{
DHTData[i] = DHT11_ReadByte();//读取5份数据
}
}
GPIO_ResetBits(GPIOA,GPIO_Pin_9);
Delay_us(55);
GPIO_SetBits(GPIOA,GPIO_Pin_9);
if(DHTData[0] + DHTData[1] + DHTData[2] + DHTData[3] == DHTData[4])
return 1;
else
return 0;
}
参考资料
产品手册说明书:链接:https://pan.baidu.com/s/1qKnJ2ZQrAPPIt6mEjrSv9Q
提取码:wpiv