学习ESP8266_13_DHT11读取温湿度

1、DHT11

DHT11是一个检测温湿度的模块,将温湿度传感器获取的信号传给内部8位的单片机,单片机进行处理,得到数字的温湿度数据。

DHT11与外部通信方式是单总线。

2、单总线通信过程

主机是ESP8266,从机是DHT11。

很容易理解的过程:

  • 由主机ESP8266发出起始信号
  • DHT11发现主机在呼唤,给出应答
  • DHT11发送温湿度的数据,以及结束信号

ESP8266:在么?
DHT11:我在。
DHT11:现在的温度是26℃,湿度是70%,完毕!

3、各个时序

空闲电平:单总线通常要求外接一个约 4.7kΩ 的上拉电阻,这样,当总线闲置时,其状态为高电平。

3.1、起始信号及应答

1)ESP8266输出低电平,且低电平保持时间18~30ms,典型值为20ms,程序中取25ms。
在这里插入图片描述

	DHT11_OUT(0);							//ESP8266输出低电平
	DHT11_delay_ms(25);						//范围18~30ms,典型值为20ms

2)ESP8266的IO设为输入,等待DHT11输出低电平的到来,最多等待100us,超时则认为通信失败。

	DHT11_IN();	
	
	while(GPIO_INPUT_GET(GPIO_ID_PIN(5))){	//等待低电平的到来
		retry++;
		os_delay_us(1);
		if(retry > 100)
			return START_ERR;				//等100us都没有低电平响应
	}

3)有低电平到来之后,计算低电平的时间,范围在78~88us,典型值是83us的低电平,故超过90us可认为低电平时间过长了。

在这里插入图片描述

	retry = 0;
	while((GPIO_INPUT_GET(GPIO_ID_PIN(5))) == 0){
		retry++;							//计算低电平的时间
		os_delay_us(1);
		if(retry > 90)
			return START_ERR;				//低电平响应时间过长
	}

4)能运行到这里,单总线上已经是高电平了,高电平持续范围80~92us,可取60us之后,再读取一次总线状态,确认是否仍然为高电平。

	os_delay_us(60);						//等待60us再检测是否为高电平,确认一次
	if(GPIO_INPUT_GET(GPIO_ID_PIN(5)) == 0)
		return START_ERR;
	else
		return DHT_OK;
}

3.2、发送温湿度数据

3.2.1、 数据格式

在这里插入图片描述

8bit检验位是前4字节数据的和校验

3.2.2、读取一位数据

位数据“0”的格式为: 54us(50~58us)的低电平和 23-27us的高电平;
位数据“1”的格式为: 54us(50~58us)的低电平加 68-74us的高电平。

1)首先要等待低电平的到来,超过50us认为读取出错。
2)有低电平了,要计时低电平的时间,根据手册超过58us认为出错,程序中稍稍延长,取62us.
3)此时进入高电平的阶段,如果是23-27us的高电平认为是0,如果是68~74us的高电平认为是1,所以要跳过0的高电平时间,但又处于1的高电平期间,检测47us时(27和68的中间值)的总线状态,为0则0,为1则1。

//读一位数据
u8   ICACHE_FLASH_ATTR DHT11_Read_Bit(void)
{
	u8 retry = 0;
	u8 data;

	while(GPIO_INPUT_GET(GPIO_ID_PIN(5))){	//等待低电平
		retry ++;
		os_delay_us(1);
		if(retry > 50)
			return BIT_ERR;			//出错
	}

	retry = 0;
	while(GPIO_INPUT_GET(GPIO_ID_PIN(5))==0){	//等待低电平结束
		retry ++;
		os_delay_us(1);
		if(retry > 62)
			return BIT_ERR;			//出错
	}

	os_delay_us(47);			// 跳过"0"的高电平时序,取27和68的中间值
	if(GPIO_INPUT_GET(GPIO_ID_PIN(5)))
		data = 1;
	else
		data = 0;

	return data;
}
3.2.3、读取一个字节

注意,数据在总线上传输是高位在前,也就是说先接收到的位是最高位。

//读DHT11传回来的一个字节
u8 ICACHE_FLASH_ATTR DHT11_Read_Byte(void)
{
	u8 i,data = 0;
	for(i=0;i<8;i++){
		data <<= 1;
		data |= DHT11_Read_Bit();		//高位在前
	}

	return data;
}
3.2.4、读取40位数据(5个字节)

循环5次读取字节就OK了,把数据放在数组里存着。

	for(i=0;i<5;i++)		//读取原始的5个字节
		DHT11_Data_Array[i] = DHT11_Read_Byte();

3.3、结束信号

DHT11会输出54us的低电平,然后释放总线(拉高)。

下面这一段代码就是等待低电平,并计算低电平的时间是否过长。

	while(GPIO_INPUT_GET(GPIO_ID_PIN(5))){	//等待低电平到来
		retry++;
		os_delay_us(1);
		if(retry > 50)
			return END_ERR;					//低电平响应时间过长
	}

	//计数低电平的时间
	retry = 0;
	while(GPIO_INPUT_GET(GPIO_ID_PIN(5)) == 0){
		retry++;
		os_delay_us(1);
		if(retry > 60)
			return END_ERR;					//低电平时间过长
	}

4、处理及串口打印

4.1、校验

和校验,就是把前4个字节加起来,看看是不是第5个字节的内容。

	if(DHT11_Data_Array[4] != DHT11_Data_Array[0]+DHT11_Data_Array[1]+DHT11_Data_Array[2]+DHT11_Data_Array[3])
		return CHECK_ERR;					//返回校验错误

4.2、温度为负的情况

当温度为负时,温度小数部分的最高位会置1,所以可以据此来判断温度的正负并修正零下时的温度数据。

DHT11_Data_Array[5]用来存放温度的正负,温度为正为0,温度为负为1.
DHT11_Data_Array[3]是温度的小数部分,温度为负时把最高位去除。

	if(DHT11_Data_Array[3] & 0x80){			//温度为负
		DHT11_Data_Array[3] = DHT11_Data_Array[3] & 0x7F;
		DHT11_Data_Array[5] = 1;
	}else{
		DHT11_Data_Array[5] = 0;
	}

4.3、串口打印温湿度

	//打印湿度
	os_printf("Humi:%d.%dRH\r\n",DHT11_Data_Array[0],DHT11_Data_Array[1]);
	//打印温度
	os_printf("Temp:%d.%d℃\r\n",DHT11_Data_Array[2],DHT11_Data_Array[3]);
  • 0
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值