DHT11程序分析和测试

本篇文章对于DHT11进行测试,并且提供程序思路

先看一下DHT11的数据

 目前DHT11读出的湿度小数和温度小数都为0(和DHT11的版本有关),它采用单总线协议,但是和DS18B20的不同在于,它没有复杂的控制字节,以及设备编码,还有就是诸如eeprom和温度上下限等特殊存储功能,相比之下操作更简单一些。并且可以一次读出湿度和温度,比较方便。

 下面看一下具体时序操作

 首先主机要拉低总线至少18ms,并且主机可以马上拉高总线,等待DHT的响应信号,在响应信号后,它会有一段准备时间(DHT拉高总线),然后再拉低总线开始传送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1.格式见下面图示。

这个其实也比较好解决,可以在传送数据的时候等待高电平的到来,到来后等待60us(这个时间不是随意的,不能超过76-78,也就是50us+(26或28)),这个时候如果再去读取,电平为低的话,则为0,电平为高的话,则为1,然后再等待高电平过去。这个思想很好,可以好好想一下。下面提供程序思路

#include "stc15f2k60s2.h"
#include "DHT11.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define TIMEMAX 2000
sbit DQ = P1^0;
void Delay19ms()		//@11.0592MHz
{
	unsigned char i, j, k;
 
	_nop_();
	_nop_();
	_nop_();
	i = 1;
	j = 205;
	k = 97;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void Delay60us()		//@11.0592MHz
{
	unsigned char i, j;
 
	i = 1;
	j = 162;
	do
	{
		while (--j);
	} while (--i);
}
//数据传输
uchar Read_Dat()
{
 uchar i; uchar Dat;
 for( i = 0 ; i < 8 ; i++ )
 {
	uint timeout = TIMEMAX;
  while( !DQ && timeout-- ); //等待低电平信号过去
	if(timeout == 0)
	return 0;
	timeout = TIMEMAX;
  //延时60us并且去读取数据,如果是0的话,现在已经是越过了高电平并且50us的低电平已经过了约30us了
  //而如果是1,现在还是高电平。
  Delay60us();
  Dat <<= 1;
  if( DQ )
  {
   Dat |= 1;
  }
  //如果数据是0的话,就直接跳过了,去执行while( !DQ )来等待剩余的越20us低电平过去,并且进行下一次传送
  //如果数据是1的话,就等待高电平过去,然后执行while( !DQ )来等待50us的低电平过去,并且进行下一次传送
  while( DQ && timeout--); 
	if(timeout == 0)
	return 0;
 }
 return( Dat );
}
 

 
/*响应信号是DHT11拉低总线    准备信号是DHT11拉高总线*/
uint Read_DHT11()
{
 uint Dat;
 uchar SD_z , SD_x , WD_z , WD_x , JY; //分别为湿度整数,湿度小数,温度整数,温度小数 , 校验值
 uint timeout = TIMEMAX;
 DQ = 1;
 _nop_();
 DQ = 0;          //拉低总线至少18ms
 Delay19ms();
 DQ = 1;          
 while( DQ && timeout--);    // 主机拉高总线,并且等待DHT11响应信号
 if(timeout == 0)
	 return 0;
 timeout = TIMEMAX;
 while( !DQ && timeout-- );   //响应信号到来后,等待响应信号结束,(也即为等待准备信号 )
 if(timeout == 0)
	 return 0;
 timeout = TIMEMAX;
 while( DQ && timeout--);    //准备信号到来后,等待准备信号结束,并开始数据传输
 if(timeout == 0)
	 return 0;
 SD_z = Read_Dat();
 SD_x = Read_Dat();
 WD_z = Read_Dat();
 WD_x = Read_Dat();
 JY = Read_Dat();
 //校验
  if( JY == ( SD_z + SD_x + WD_z + WD_x )  )
  Dat = ( ( uint )SD_z << 8 )| WD_z ;
  else
  Dat = 0;
 return( Dat );
}

这个程序其实是不好的,因为没有加超时退出,即如果条件没有达到,会卡死程序,一般调好了,不会出现这个问题,所以,要想更完美点,就加上超时退出就行了。

下面是串口收到的数据

注意,在读取单总线这种对信号严格要求的信号来说,读取的时候,最好将中断关闭!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一WILLPOWER一

你的鼓励是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值