dht11温湿度模块
author:onceday date:2022年4月9日
1.模块介绍
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。
引脚说明:
- VDD 供电3.3~5.5V DC。
- DATA 串行数据,单总线。
- NC 空脚。
- GND 接地,电源负极。
接线说明:
- 典型应用电路中建议连接线长度短于5m时用4.7K上拉电阻,大于5m时根据实际情况降低上拉电阻的阻值。
- 使用3.3V电压供电时连接线尽量短,接线过长会导致传感器供电不足,造成测量偏差。
- 每次读出的温湿度数值是上一次测量的结果,欲获取实时数据,需连续读取2次,但不建议连续多次读取传感器,每次读取传感器间隔大于2秒即可获得准确的数据。
- 电源部分如有波动,会影响到温度。如使用开关电源,温度就会跳动。
2.单总线串行双向通信
用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次传送40位数据,高位先出。
数据格式:
- 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位。注:其中湿度小数部分为0。
- “8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”=8bit校验位等于所得结果的末8位。
示例一:接收到的40位数据为:
0011 0101 | 0000 0000 | 0001 1000 | 0000 0100 | 0101 0001 |
湿度高8位 | 湿度低8位 | 温度高8位 | 温度低8位 | 校验位 |
计算:
00110101+00000000+00011000+00000100=01010001
接收数据正确:
湿度:00110101(整数)=35H=53%RH00000000(小数)=00H=0.0%RH=>53%RH+0.0%RH=53.0%RH
温度:00011000(整数)=18H=24℃00000100(小数)=04H=0.4℃=>24℃+0.4℃=24.4℃
3.数据通讯过程
用户主机(MCU)发送一次开始信号后,DHT11从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信采集。
3.1步骤1
DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平;此时DHT11的DATA引脚处于输入状态,时刻检测外部信号。
3.2步骤2
微处理器的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),然后微处理器的I/O设置为输入状态,由于上拉电阻,微处理器的I/O即DHT11的DATA数据线也随之变高,等待DHT11作出回答信号。发送信号如图4所示:
3.3步骤3
DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知外设准备接收数据,微处理器的I/O此时处于输入状态,检测到I/O有低电平(DHT11回应信号)后,等待87微秒的高电平后的数据接收,发送信号如图5所示:
3.4步骤4
由DHT11的DATA引脚输出40位数据,微处理器根据I/O电平的变化接收40位数据,位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。位数据“0”、“1”格式信号如图6所示:
3.5步骤5
==结束信号:==DHT11的DATA引脚输出40位数据后,继续输出低电平54微秒后转为输入状态,由于上拉电阻随之变为高电平。但DHT11内部重测环境温湿度数据,并记录数据,等待外部信号的到来。
3.6单总线信号特性
4.代码实例
4.1头文件定义
typedef struct __dhtt_data
{
u32 humidness;//湿度
double temperature;//温度
}_dhtt_data;
4.2管脚初始化
以stm32f103代码为例:
void dhtt_init(void)
{
//初始化io
//数据线B0
RCC->APB2ENR|=(1<<3);
GPIOB->CRL&=~(0x0000000F);
GPIOB->CRL|=0x00000008;//上下拉输入
GPIOB->ODR|=1;//上拉电阻
}
//输入状态
void dhtt_io_input(void)
{
GPIOB->CRL&=~(0x0000000F);
GPIOB->CRL|=0x00000008;//上下拉输入
GPIOB->ODR|=1;//上拉电阻
}
//输出状态
void dhtt_io_out(void)
{
GPIOB->CRL&=~(0x0000000F);
GPIOB->CRL|=0x00000003;//推挽输出
GPIOB->ODR&=~(1);//输出低
}
#define DHTT_IO (GPIOB->IDR&1)
4.3 数据通信
u8 dhtt_check_respond(void)
{
int count=0;
while(DHTT_IO)
{
//查询低电平的到来
//如果1ms内未到,则设备故障,直接退出,实际上最多20us就应该回应。
if(count++>72000)
return 0;
}
//检测到低电平,准备检测响应
count=0;
while(!DHTT_IO)
{
//查询下一个高电平
//如果1ms内未到,则设备故障,直接退出,实际上最多85us就应该回应。
if(count++>72000)
return 0;
}
//检测到高电平,准备检测数据的到来
count=0;
while(DHTT_IO)
{
//查询低电平的到来
//如果1ms内未到,则设备故障,直接退出,实际上最多20us就应该回应。
if(count++>72000)
return 0;
}
//数据响应正确
return 1;
}
u8 dhtt_check_data(u8* data)
{
u8 j=0,d=0;
int i,count;
_rtime rt;//设置时间架构体
u16 htime=0;//高电平时间
get_rtime(&rt);//获取当前时间
while(j<5)
{
for(i=0;i<8;i++)//四十个数据
{
//检测高电平的到来
count=0;
while(!DHTT_IO)
{
//查询下一个高电平
//如果1ms内未到,则设备故障,直接退出,实际上最多56us就应该回应。
if(count++>72000)
return 0;
}
get_rtime(&rt);//更新当前时间
count=0;
while(DHTT_IO)
{
//查询下一个低电平
//如果1ms内未到,则设备故障,直接退出,实际上最多74us就应该回应。
if(count++>72000)
return 0;
}
htime=get_dus(&rt);//计算高电平时间
//23-27us为0,68-74us为1,选47作为分界点
if(htime<47)
{
d = 0;
}
else
{
d = 1;
}
//低电平将持续52-56us
data[j] =(data[j]<<1)+d;
}
j++;
}
return 1;
}
4.4 校验和读取数据
u8 dhtt_data_sumcheck(u8* data)
{
u32 sum=data[0]+data[1]+data[2]+data[3];
if((sum&(0x000000ff))==data[4])
{
return 1;
}
else
{
return 0;
}
}
u8 dhtt_read(_dhtt_data* dhtt_data)
{
u8 d=0;
u8 data[5]={0};
//首先输出低信号20ms
dhtt_io_out();//输出状态
delay_ms(20);//延迟20ms
dhtt_io_input();
if(dhtt_check_respond())
{
if(!(dhtt_check_data(data)))
{
draw_string(5,40,"receive error");
return 0;
}
}
else
{
draw_string(5,40,"respond error");
return 0;
}
if(!(dhtt_data_sumcheck(data)))
{
draw_string(5,40,"sumcheck error");
return 0;
}
dhtt_data->humidness=data[0];
dhtt_data->temperature=(double)data[2];
d=data[3]&(0x7f);//去除最大的符号位
if(d>=100)
{
dhtt_data->temperature+=(double)d/1000;
}
else if(d>=10)
{
dhtt_data->temperature+=(double)d/100;
}
else
{
dhtt_data->temperature+=(double)d/10;
}
if(data[3]&(0x80))
{
dhtt_data->temperature=-dhtt_data->temperature;
}
return 1;
}