相比于DS18B20只能测温度,DHT11能测温度之外还能测湿度,但是DHT11的精度和测量范围都要低于DS18B20 |
DHT11简介
DHT11是一款价格便宜,易于使用的温度湿度测量二合一传感器。它具有超小体积、极低功耗的特点。它使用单总线与单片机进行双向的串行数据传输,信号传输距离可达20米以上,适用于对精度和实时性要求不高的温湿度测量场合。
DHT11封装与引脚说明
DHT11一共有4个引脚,但是只用到3个,其中一个要悬空处理。
DHT11使用单总线通信协议,使用时要将DATA线接电阻上拉,这个电阻一般取值5K左右。
DHT11工作原理
一次完整的通信过程:单片机发送一次复位信号后,DHT11从低功耗模式转换到高速模式,等待主机复位结束后,DHT11拉低总线80us发送应答(ACK)信号,并拉高总线准备传输数据。拉高总线80us之后DHT11开始按照数据格式发送数据,当所有数据都发送完之后,DHT11 拉低总线 50us,表示数据传输完毕,随后总线由上拉电阻拉高进入空闲状态。
数据格式
DHT11一共5Byte数据,前2Byte为湿度的整数/小数数据,后1Byte为温度的整数/小数数据,最后1Byte为校验和,是前4Byte数据和的低八位,数据以 高位在前 方式传输。由于 DHT11的分辨率只能精确到个位,所以小数部分是数据全为0。
工作时序
- 首先单片机 拉低总线18ms以上,向DHT11发出起始信号,然后再 拉高总线20~40us 表示信号结束。
- DHT11检测到起始信号后,拉低总线80us 发出应答信号,告诉主机数据已经准备好了,然后 DHT11 拉高总线80us,之后开始传输数据。
- 每位数据的传输都由一次 50us的低电平 作为开始。与DS18B20不同,DHT11用 高电平的持续时间 表示数据是’0’还是’1’。高电平持续26~28us表示逻辑0,持续70us表示逻辑1。
- 最后1bit数据传输完毕之后,DHT11拉低总线50us表示传输结束,之后释放总线,由上拉电阻将总线上拉至高电平(空闲状态)
注意事项
- DHT11上电后,要等待1秒以越过不稳定状态,在此期间不能发送任何指令。
- DHT11属于低速传感器,两次通信请求之间的间隔时间不能太短,一般不低于1秒。
分辨0和1的方法
由于 0 的高电平持续时间为 26-28us
1 的高电平持续时间为 70us
所以可以取高电平开始后 40us 的电平状态来确定数据是0还是1。如果是低电平,说明数据是0,因为0的高电平不能持续40us;如果是高电平,说明数据是1,因为1的高电平持续70us,此时高电平还未结束。
40us而不是30us的原因是:信号不是精准的26~28us长度,有可能略大一些,也有可能略小一些,所以最好取得稍大一点。但是也不能取太长,否则会错过下一次开始信号。取40-50us都是不错的选择。
自己写的驱动程序(C51)
/**********************************************************************************
* 程序名: TM1638驱动程序
* 作者: DaveoCKII
* 日期: 2020.3.4
* 版本: STC12C5A60S2 (延时函数时钟标准:11.0592MHZ)
**********************************************************************************/
#ifndef _DHT11_H_
#define _DHT11_H_
#include <STC12C5A60S3.H> // 自己修改过的STC12C5A60S2的头文件,为了区分原头文件改名S3
//------------------------------------定义列表------------------------------------//
sbit DATA = P3^2; // 单总线口定义
unsigned char temp,humi; // 温度,湿度
//------------------------------------函数列表------------------------------------//
unsigned char DHT11_Init(void); // DHT11初始化函数
unsigned char DHT11_Read(void); // DHT11读数据函数
unsigned char DHT11_Temp(void); // DHT11读温度函数
void delay40us(void); // 40us延时
void delay20ms(void); // 20ms延时
void delay1us(void); // 1us延时
void delay1s(void); // 1s延时
//------------------------------------函数内容------------------------------------//
unsigned char DHT11_Init(void)
{
unsigned char cnt=0;
DATA=1; // 总线初始化
delay40us();
DATA=0; // 拉低总线20ms
delay20ms();
DATA=1;
delay40us(); // 等待DHT11响应
while(!DATA){ // 检测低电平
cnt++;
delay1us();
}
if(cnt>100||cnt<40) {
return 0; // 初始化失败
}
cnt=0;
while(DATA){ // 检测高电平
cnt++;
delay1us();
}
if(cnt>100||cnt<40) {
return 0; // 初始化失败
}
return 1; // 初始化成功
}
unsigned char DHT11_Read(void)
{
unsigned char dat,i;
for(i=0; i<8; i++)
{
while(DATA); // 等待高电平结束 (数据信号)
while(!DATA); // 等待低电平结束 (起始信号)
delay40us(); // 40us延时
dat<<=1; // 数据格式:高位在前
if(DATA)
dat|=0x01;
}
return dat;
}
unsigned char DHT11_Temp(void)
{
unsigned char succ;
unsigned char buf[5]; // 数据暂存
EA=0; // 关中断防打扰
succ=DHT11_Init(); // DHT11初始化
if(!succ){
EA=1;
return 0; // 初始化失败
}
for(succ=0; succ<5; succ++) // 读取5Byte数据
buf[succ]=DHT11_Read();
if(buf[0]+buf[1]+buf[2]+buf[3]==buf[4]) { // 验证结果
humi = buf[0]; // 保存湿度值
temp = buf[2]; // 保存温度值
EA=1;
return 1; // 读取成功
}
else
EA=1;
return 0; // 读取失败
}
void delay40us(void) {
unsigned char a,b;
for(b=43;b>0;b--)
for(a=1;a>0;a--);
}
void delay20ms(void) {
unsigned char a,b,c;
for(c=14;c>0;c--)
for(b=168;b>0;b--)
for(a=22;a>0;a--);
}
void delay1s(void) {
unsigned char a,b,c;
for(c=217;c>0;c--)
for(b=171;b>0;b--)
for(a=73;a>0;a--);
}
void delay1us(void) {
}
//--------------------------------------------------------------------------------//
#endif
DaveoCKII |