一、简介
DHT11概述(官方描述)
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为 4 针单排引脚封装。连接方便,特殊封装形式可根据用户需求而提供。
应用场景
常应用于暖通空调,汽车,湿度调节器,除湿器,测试与检测设备,家电,医疗等 。
开漏输出常用于总线通信。
二、通讯过程
串行接口(单项双线),用比特传输,DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分。
数据格式:8比特湿度整数数据+8比特湿度小数数据+8比特温度整数数据+8比特温度小数数据+8比特校验和。校验和是第二个字节到第六个字x
过程:用户MCU发送一次开始信号后(也就是VCC拉低变低电平,过一会在拉高电平,这是一个开始,对应图片的黑色路线区),DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号(也就是低电平转为高电平,对应图片的DHT响应输出那一块),然后送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据.。从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集。采集数据后转换到低速模式。
三、代码编写
初始化DHT11
void dht11_init(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //指定9号引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//配置为输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//速度越高,功耗就越高,但是响应速度也更快
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//不需要使能内部上下拉电阻
GPIO_Init(GPIOG, &GPIO_InitStructure);
//看时序图,初始电平状态为高电平
GPIO_SetBits(GPIOG,GPIO_Pin_9);
}
读数据
int32_t dht11_read(uint8_t *buf)
{
uint8_t *p = buf;
uint32_t t=0;
int32_t i,j;
uint8_t d=0;
uint8_t check_sum=0;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //指定9号引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//配置为输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//速度越高,功耗就越高,但是响应速度也更快
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//不需要使能内部上下拉电阻
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_ResetBits(GPIOG,GPIO_Pin_9);
delay_ms(20);
GPIO_SetBits(GPIOG,GPIO_Pin_9);
delay_us(30);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //指定9号引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//配置为输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//速度越高,功耗就越高,但是响应速度也更快
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//不需要使能内部上下拉电阻
GPIO_Init(GPIOG, &GPIO_InitStructure);
//等待低电平出现
t=0;
while(PGin(9))
{
delay_us(1);
t++;
if(t >=4000)
return -1;
}
//检测低电平的有效性
t=0;
while(PGin(9)==0)
{
delay_us(1);
t++;
//不能在80左右,离零界点太接近
if(t >=100)
return -2;
}
//检测高电平的有效性
t=0;
while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9))
{
delay_us(1);
t++;
//不能在80左右,离零界点太接近
if(t >=100)
return -3;
}
for(j=0; j<5; j++)
{
d=0;
for(i=7; i>=0; i--)
{
//成功判断一个数据0或数据1
//等待前置的50us电平持续完毕
t=0;
while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9)==0)
{
delay_us(1);
t++;
if(t >=100)
return -4;
}
//延时一会,延时多长时间才合适呢(30us~70us)
delay_us(40);
if(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9))
{
d|=1<<i;
//等待剩下的高电平持续完毕
t=0;
while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9))
{
delay_us(1);
t++;
if(t >=100)
return -5;
}
}
}
p[j]=d;
}
//通过校验和检测数据的有效性
check_sum = (p[0]+p[1]+p[2]+p[3])&0xFF;
if(check_sum !=p[4])
return -6;
return 0;
}