【DHT11通信协议详解】单总线协议优化版

单总线概述

        1、单总线的介绍
       (1)、单总线也称为1—Wire bus,它是由美国DALLAS(达尔斯)公司推出的外围串行扩展总线。单总线系统中配置的各种器件,由DALLAS公司提供的专用芯片实现。
       (2)、每个芯片都有64位ROM,厂家对每一芯片都用激光烧写编码,其中存有16位十进制编码序列号,它是器件的地址编码,以确保它挂在总线上后可被唯一地确定。除了器件的地址编码外,芯片内还包含收发控制和电源存储电路。这些芯片的耗电量都很小(空闲时为几微瓦,工作时为几毫瓦),工作时从总线上馈送电能到大电容中就可以工作,故一般不需要另加电源。
      (3)、与其他的单片机系统的串行扩展(如IIC、SPI和MICROWIRE等)不同,它只有一条数据输入/输出线DQ,总线上的所有器件都要挂在DQ上,DQ信号线既传输时钟,又传输数据,而且数据传输是双向的,这种只使用一条信号线地串行扩展技术,称为单总线技术。
     (4)、单总线的数据传输速率一般为16.3Kbit/s,最大可达142 Kbit/s,通常情况下采用100Kbit/s以下的速率传输数据。
        2、单总线技术的优势
       (1)与其他的的串行扩展相比,单片机与外围扩展器件相连接所需要的I/O口线很少,这极大地简化了器件间的连接,进而提高了可靠性;

       (2)单总线接口器件体积更加小,占用的电路板空间小,这就极大程度地减少了电路板空间与成本。

        3、单总线通信的硬件结构

 

        单片机对每个单总线器件通过总线DQ进行寻址。因为单总线的端口为漏极开路构或三态门的端口,因此一般需要加上拉电阻Rp,上拉电阻的阻值通常5K~10KΩ。

单总线通信的工作原理

        顾名思义,单总线即只有一根数据线,系统中的数据交换、控制都由这根数据线完成。

        主机和从机之间的通信可通过3个步骤完成分别为初始化单总线器件、识别单总线 器件和与单总线器件交换数据。由于它们是主从结构只有主机呼叫从机时从机才能应答,因此主机访问单总线器件都必须严格遵循单总线命令序列即初始化、ROM 命令、功能命令。如果出现序列混乱1-wire器件将不响应主机(搜索ROM命令报警搜索命令除外)。

        表1所列为 ROM 命令的说明而功能命令则根据具体1-wire 器件所支持的功能来确定。

 

        2、单总线技术的通信协议

        所有的单总线器件都要遵循严格的通信协议以保证数据的完整性。1—Wire 协议定义了复位脉冲、 应答脉冲、写0、写1、读0和读1时序等几种信号类型。所有的单总线命令序列(初始化ROM 命令功能命令)都是由这些基本的信号类型组成的。

        在这些信号中除了应答脉冲是由从机发送以外,其它均由主机发出同步信号并且发送的所有命令和数据都是字节的低位在前。

        (1)、初始化时序

 

 

        初始化过程 = 主机发出的复位脉冲 + 从机发出的应答脉冲。

        主机通过拉低单总线480 ~ 960 us产生T X复位脉冲,然后由主机释放总线,进入RX接收模式。主机释放总线时,会产生低电平跳变为高电平的上升沿,单总线器件检测到上升沿之后,延时15 ~ 60 us,单总线器件拉低总线60 ~ 240 us来产生应答脉冲。主机接收到从机的应答脉冲说明单总线器件就绪,初始化过程完成,然后主机就可以开始对单总线器件进行 ROM 命令和功能命令操作。

       ( 2)、写“1”和写“0”时序

 

        写间隙有两种,包括写0的时间隙和写1的时间隙。

        主机要产生一个写1时间隙,就必须把数据线拉低,在写时间隙开始后的15 us内允许数据线拉高(即在0~15us内释放总线)。

        主机要产生一个写0时间隙,就必须把数据线拉低,在写时间隙开始后的60us内保持数据线拉低(即在0~60us内为低电平)。

        (3)、读时序

 

 

        单总线器件仅在主机发出读时序时才向主机传输数据所以当主机向单总线器件发出读数据命令1us后产生读时序以便单总线器件能传输数据。在主机发出读时序之后单总线器件才能在总线上发送“0”或“1”。

        若单总线器件发送“1”则总线保持高电平;

        若单总线器件发送“0”则总线保持低电平;

        由于单总线器件发送数据后可保持15μs有效时间,因此主机在读时序期间必须释放总线且须在 15μs 内采样总线状态以便接收从机发送的数据。

单总线器件的举例——DHT11

        1、DHT11的概述

        DHT11 是广州奥松有限公司生产的一款湿温度一体化的数字传感器。 该传感器包括一个电阻式测湿元件和一个 NTC 测温元件,并与一个高性能 8 位 单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集环境的湿度和温度。

        DHT11 与单片机之间能采用简单的单总线进行通信,仅仅需要一个 I/O口。传感器内部湿度和温度数据40Bit的数据一次性传给单片机,数据采用 校验和方式进行校验,有效的保证数据传输的准确性。DHT11 功耗很低,5V 电 源电压下,工作平均最大电流 0.5mA。

        性能指标和特性如下

        ●工作电压范围:3.5V-5.5V 

        ●工作电流 :平均 0.5mA

        ●湿度测量范围:20-90%RH 

        ●温度测量范围:0-50℃ 

        ●湿度分辨率 :1%RH 8 位 

        ●温度分辨率 :1℃ 8 位

        ●采样周期 :1S

        ●单总线结构

        ●与TTL兼容(5V)管脚排列如下:

 

 

        DHT11 数字湿温度传感器连接方法极为简单。

        第一脚接电源正,第四脚接电源地端,数据端为第二脚,可直接接主机(单片机)的 I/O 口。为提高稳定性,建议在数据端和电源正之间接一只 4.7K 的上拉电阻。第三脚为空脚,此管脚悬空不用

2、DHT11的数据结构

        DHT11数字湿温度传感器采用单总线数据格式,即单个数据引脚端口完成输入输出双向传输。

        其数据包由5Byte(40Bit)组成。数据分小数部分和整数部分,具 体格式在下面说明。 一次完整的数据传输为40bit,高位先出。

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

        校验和数据为前四个字节相加。 传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间 应该分开处理。如果,某次从传感器中读取如下5Byte数据:

 

 

        由以上数据就可得到湿度和温度的值,计算方法:

        (湿度)= byte4 . byte3=45.0 (%RH)

        (温度)= byte2 . byte1=28.0 ( ℃)

        (校验和)= byte4+ byte3+ byte2+ byte1=73

        如果校验和=湿度+温度,说明数据校验正确。

        注意:DHT11一次通讯时间最大3ms,主机连续采样间隔建议不小于100ms。

        3、DHT11的传输时序

        (1)DHT11 开始发送数据流程

 

        首先主机发送开始信号,即:拉低数据线,保持t1(至少18ms)时间,然后拉高数据线t2(20~40us)时间,然后读取DHT11的响应,正常的话,DHT11会拉低数据线,保持t3(40~50us)时间,作为响应信号,然后DHT11拉高数据线,保持t4(40~50us)时间后,开始输出数据

(2)主机复位信号和 DHT11 响应信号

 

        首先由主机拉低数据线至少18ms,紧接着拉高数据线20~40us,即主机发送的复位信号。在主机发送复位信号后,DHT11开始拉低数据线40~50us作为响应信号,DHT11再发送向主机发送响应信号后,紧接着拉高数据线40~50us,意味着DHT11可以开始传送数据了。

(3)DHT11输出数字‘0’ 和输出数字‘1’

 

 

 

        1.主机先把data线拉高(io设置为输入)。

        2.从机把data线拉低,主机读取data线电平,直到低电平结束(大约50us)

     3.从机拉高data线后,延迟40us左右(28~70us之间)主机再次读取data线电平,如果为低电平,则为“0”,如果为高电平,则为“1”。

     4.继续重复上述1,2步骤累计40次。

        4、DHT11的程序

        DHT11.h中的程序

#ifndef DHT11_H
#define DHT11_H


#include "stm32f10x.h"
#include "iobit.h"

/*******************************************************************************
STM32的CRL控制着每个IO端口(A~G)的低8位的模式。
每个IO端口的位占用CRL的4个位,高两位为CNF,低两位为MODE。
*******************************************************************************
//IO方向设置
//IO方向设置	CRH的作用和CRL完全一样,CRL控制的是低8位输出口,CRH控制的是高8位输出口
#define      DHT11_IO_IN()       {GPIOB->CRL&=0XFFFFFFF0;GPIOB->CRL|=8<<0;}	
//GPIOB->CRL&=0XFFFFFFF0:控制IO口    GPIOB->CRL|=8<<0:设置IO口为输入
#define		 DHT11_IO_OUT() 	 {GPIOB->CRL&=0XFFFFFFF0;GPIOB->CRL|=3<<0;}	
//GPIOB->CRL&=0XFFFFFFF0:控制IO口    GPIOB->CRL|=3<<0:设置IO口为输出

IO操作函数											   
#define	DHT11_DQ_OUT PBout(0) 	    //数据端口	PB0
#define	DHT11_DQ_IN  PBin(0)  		//数据端口	PB0


unsigned char DHT11_Init(void);						//初始化DHT11
unsigned char DHT11_Read_Data(u8 *humiH,u8 *humiL,u8 *tempH,u8 *tempL);  	
//读取温湿度
unsigned char DHT11_Read_Byte(void);				//读出一个字节
unsigned char DHT11_Read_Bit(void);					//读出一个位
unsigned char DHT11_Check(void);					//检测是否存在DHT11
void DHT11_Reset(void);								//复位DHT11   
void DHT11_Show_Data(void);


#endif

DHT11.c中的程序 

#include "dht11.h"
#include "delay.h"
#include "string.h"
#include "stdio.h"

/*******************************************************************************
* 函数名         : DHT11_Reset()
* 函数功能		 : 复位DHT11	
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void DHT11_Reset(void)	   
{                 
	
	DHT11_IO_OUT(); 								//SET OUTPUT
    DHT11_DQ_OUT=0; 								//拉低DQ
    delay_ms(20);    								//拉低至少18ms
    DHT11_DQ_OUT=1; 								//DQ=1 
	delay_us(30);     								//主机拉高20~40us
	
}

/*******************************************************************************
* 函数名         : DHT11_Check()
* 函数功能		 : 等待DHT11的回应	
* 输入           : 无
* 输出         	 : 返回1:未检测到DHT11的存在 返回0:检测到DHT11的存在
*******************************************************************************/
unsigned char DHT11_Check(void) 	   
{   
	
	unsigned char retry=0;
	DHT11_IO_IN();									//SET INPUT	 
    while (DHT11_DQ_IN&&retry<100)					//DHT11会拉低40~80us
	{
		retry++;
		delay_us(1);
	}	 
	if(retry>=100)
		return 1;
	else 
		retry=0;
    while (!DHT11_DQ_IN&&retry<100)					//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		delay_us(1);
	}
	if(retry>=100)
		return 1;	    
	return 0;
	
}

/*******************************************************************************
* 函数名         : DHT11_Read_Bit()
* 函数功能		 : 从DHT11读取一个位	
* 输入           : 无
* 输出         	 : 返回值:1/0
*******************************************************************************/
unsigned char DHT11_Read_Bit(void) 			 
{
	
 	unsigned char retry=0;
	while(DHT11_DQ_IN&&retry<100)					//等待变为低电平
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(!DHT11_DQ_IN&&retry<100)					//等待变高电平
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);									//等待40us
	if(DHT11_DQ_IN)
		return 1;
	else 
		return 0;	
	
}


/*******************************************************************************
* 函数名         : DHT11_Read_Byte()
* 函数功能		 : 从DHT11读取一个字节	
* 输入           : 无
* 输出         	 : 返回值:读到的数据
*******************************************************************************/
unsigned char DHT11_Read_Byte(void)    
{        
    unsigned char i,data;
    data=0;
	for (i=0;i<8;i++) 
	{
   		data<<=1; 
	    data|=DHT11_Read_Bit();
	}						    
    return data;
}


/*******************************************************************************
* 函数名         : DHT11_Read_Data()
* 函数功能		 : 从DHT11读取一次数据
* 输入           : 无
* 输出         	 : 返回值:0,正常;1,读取失败			
tempL:温度值低位    tempH:温度值高位	humiL:湿度值低位	humiH:湿度值低位
*******************************************************************************/
unsigned char DHT11_Read_Data(u8 *humiH,u8 *humiL,u8 *tempH,u8 *tempL)    
{    
    
 	unsigned char buf[5];
	unsigned char i;
	DHT11_Reset();
	if(DHT11_Check()==0)						//是否检测到DHT11的存在
	{
		for(i=0;i<5;i++)							//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();//将读取到的数据存储到buf[]这个数组里
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humiH=buf[0];			
			*humiL=buf[1];			
			*tempH=buf[2];
			*tempL=buf[3];
		}
	}
	else 
		return 1;									//1,读取失败
	return 0;										//0,正常
    
}


/*******************************************************************************
* 函数名         : DHT11_Read_Data()
* 函数功能		 : 初始化DHT11的IO口 DQ 同时检测DHT11的存在
* 输入           : 无
* 输出         	 : 返回1:不存在	返回0:存在
*******************************************************************************/   	 
unsigned char DHT11_Init(void)
{	 
 	GPIO_InitTypeDef  GPIO_InitStructure;					 //定义GPIO结构体
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PB端口时钟
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;				 //PB0端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //GPIO的速度
 	GPIO_Init(GPIOB, &GPIO_InitStructure);				 	 //初始化IO口
 	GPIO_SetBits(GPIOB,GPIO_Pin_0);						 	 //PB0 输出高
			    
	DHT11_Reset();  										 //复位DHT11
	return 
		DHT11_Check();										 //等待DHT11的回应
}



物联沃分享整理
物联沃-IOTWORD物联网 » 【DHT11通信协议详解】单总线协议优化版

发表评论