当前位置:文档之家› DHT11自定义总线通信协议实例详解(附详细示波器实测波形图)

DHT11自定义总线通信协议实例详解(附详细示波器实测波形图)

DHT11详解

有的时候,外围器件与MCU之间的通信并不是常见通用的通信方式,而是厂家自定义的一种通信格式。所以,最重要的应该是掌握根据时序图编写驱动程序的能力,本文通过对一种利用厂家自定义的通信格式和MCU之间通信的详细讲解,以期让读者掌握这种能力。在本文就以DHT11数字温湿度传感器为例来讲解。

一、DHT11与MCU的通信协议

首先需要得到DHT11的Datasheet,然后根据Datasheet编写程序。DHT11的Datasheet前面部分是该传感器的介绍和一些接口及其相关性能参数的说明,这部分读者可以自己去看,我们关注的是改手册的第4部分:串行接口(单线双向)。接下来详细讲解这一部分。

DHT11的DATA引脚用于微处理器与DHT11之间的通讯和同步,采用单总线的数据格式,一次通信时间为4ms左右。先来看一下MCU发送开始信号和DHT11响应信号这部分的时序图:

图1 开始信号和响应信号时序图

从图1可以看出,总线空闲的时候为高电平(图1第1段的前面所示),MCU 把总线拉低至少18ms(图1第1段),然后拉高总线(图1第2段)等待DHT11响应。DHT11接收到MCU的开始信号后,等待MCU开始信号结束,然后发送80us 低电平响应信号(图1第3段),然后DHT11拉高总线80us(图1第4段)准备输出数据。图1第5段和图1第6段分别是数据1和数据0的格式。

根据图1编写的MCU开始信号如下:

#define DHT_IO PORTA_PA0

void DHT11_init(void)

{

DHT_IO=1;

DDRA_DDRA0=0xFF; //总线空闲高电平

DHT_IO = 0; //总线拉低

DDRA_DDRA0 = 0xFF; //设置为输出

Dlyms(18); //主机至少拉低18ms

DHT_IO = 1; //释放总线

delay_us(19); //主机拉高20~40us

DDRA_DDRA0 = 0x00; //设置为输入,等待DHT11响应

}

实测的MCU发出开始信号的波形如下:

图二 MCU发出开始信号

从图2可以看出,MCU把总线拉低18.2ms(图2中两光标之间的部分,对应于图1的第1部分),满足Datasheet中规定的数值。红框中的包括DHT11的响应信号和输出的40bit数据。接下来将红框中的波形放大进行详细的分析。先来看下Datasheet中对MCU发出的开始信号和DHT11的响应信号的详细说明,如图3所示:

图3 MCU开始信号和DHT11响应信号时序图

实测的波形为:

图4 MCU发出开始信号和DHT11响应信号实测波形

图4中下方的数字2、3、4是和图一中的数字一一对应的,上方的时间是实

测的时间,和图三中的时间进行比较可以发现,图四中的数据并不是完全和Datasheet上的一致,实践表明,误差是允许的。

开始信号和响应信号结束后就是数据的传输,从DHT11的Datasheet上可以看出其对数据0和数据1的定义如下:

图5 数据0格式

图6 数据1格式

总线为低电平说明DHT11发送响应信号,DHT11发送响应信号后再把总线拉高80us准备发送数据,没一bit数据都是以50us低电平时序开始,紧跟着的高电平的长短决定了数据是0还是1,格式如图5和图6,实测的如图7和图8。

图7 数据0格式图8 数据1格式从实测的2张波形图可以看出,跟Datasheet数据还是存在一定的误差的,但这个不影响正常的通信。

有了以上的知识就可以编写函数从DHT11中读取温湿度数据了。一次完整的数据传输为40bit,高位先出。

数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit

温度小数数据+8bit校验和。数据传输正确是校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”所得结果的末8位。先传输高位。当前小数部分用于以后扩展,现读出为0。

根据以上的说明编写的从DHT11读取数据的函数如下:

unsigned char get_DHT11_value(void)

{

(1)unsigned int bit;

unsigned char p=0,time_count=0;

temperature=0x0000;

humidity=0x0000;

bit=0x8000;

DHT_IO = 0; //总线拉低

DDRA_DDRA0 = 0xFF; //设置为输出

Dlyms(18); //主机至少拉低18ms

DHT_IO = 1; //释放总线

delay_us(19); //主机拉高20~40us

DDRA_DDRA0 = 0x00; //设置为输入,等待DHT11响应

delay_us(30);

//无应答信号,退出

if(DHT_IO!=0) return 0;

//等待电平变高,设置200us超时控制

time_count=0;

while(DHT_IO==0)

{

delay_us(10);

if(++time_count==20) return 0;

}

//等待电平变低,设置150us超时控制

time_count=0;

while(DHT_IO==1)

{

delay_us(10);

if(++time_count==15) return 0;

}

PORTA_PA1=~PORTA_PA1; //调试语句

(2)//数据开始

while(p!=2)

{

//低电平宽度50us

//等待电平变高,设置100us超时控制

(3)time_count=0;

while(DHT_IO==0)

{

delay_us(10);

相关主题