【通信协议】单总线协议详解——以DHT11为例

2023-10-26

单总线概述

        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的回应
}



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【通信协议】单总线协议详解——以DHT11为例 的相关文章

  • Ubuntu双系统启动时卡死解决办法

    ubuntu双系统启动时卡死解决办法 在ubuntu16 04和18 04测试无误 问题描述 在安装完ubuntu双系统后 第一次启动ubuntu系统时 卡死在启动界面 或者黑屏 这大概都是由于显卡驱动的原因 具体不在这里阐述 通过以下方法
  • flink-cdc 实现oracle 实时同步到kudu

    其实网上也有很多相关话题的代码实现 但是发现有很多坑 在 腾讯官方文档中 有介绍 但是屏蔽了很多细节 我做了以下四点修改才能正常运行 1 前置条件 保证oracle中相关表开启了归档日志和补充日志 因为flink cdc基于debezium
  • IOS 多线程初探(二) - Operation Object

    上次简单介绍了使用NSThread来创建线程的方法 今天简单介绍使用Operation Object来创建线程 Operation Object简介 将要执行的任务 即函数 封装成操作对象NSOperation 并将对象放置到NSOpera

随机推荐

  • [C++STL] 严格弱序(less函数、小于号重载)

    前言 严格弱序 stick weak ordering 在以下场景会涉及到 对一个容器进行排序时 如使用std sort 使用有序关联容器时 如使用std set std map 使用std less时 重载 lt 操作符 小于 其中 st
  • Vue 中使用 v-for 展示不同的图片

    1 示例前提 展示一个数组对象数据 数组对象中没有图片字段 图片字段在本地保存 根据不同的id 下标 展示不同的图片 示例代码 template 中的代码
  • 数字图像处理扭曲效果——挤压效果

    挤压效果 挤压效果是将图像向内挤压 产生收缩变形 挤压效果的实现可以看成是数学极坐标的一种体现 将当前像素点 图像正中心点和过中心点的水平线这三要素画出一个极坐标 然后根据用户指定的挤压度 在当前点与中心点所连的直线上映射出一个像素点 最后
  • VulnHub-Tr0II

    一 信息收集 将靶机部署好之后改成NAT模式 扫描本网段发现目标ip 进一步探测ip 通过进一步的探测发现目标开启了21 22 80三个端口 先去80端口看一眼web服务 一张图没其它内容 扫一下目录看看 挨个访问也没有啥特殊的地方 考虑一
  • PropertyDescriptor获取非标准java bean属性的getter和setter时候的一个问题

    1 import java beans IntrospectionException 2 import java beans PropertyDescriptor 3 import java lang reflect InvocationT
  • 显著性水平对应的临界值_统计学问题 常有的显著性水平a 所对应的Z值是哪些...

    展开全部 z a 2 指的是标准正态分布的双侧临界值 z a 当然就是单侧临界值 a 阿尔法 指62616964757a686964616fe4b893e5b19e31333431356638的是显著水平 一般是0 05 0 01等 而95
  • Java 动态代理,invoke() 自动调用原理,invoke() 参数

    Java 动态代理 invoke 自动调用原理 invoke 参数 本文介绍了静态代理和动态代理的概念 并且用代码 注释 图示和源码的方式来分析动态代理原理和invoke 自动调用原理 学习动态代理 先从静态代理入手 静态代理 假如现在我们
  • 每日一练——Python字典格式读取文件

    现有一个user csv文件 内容如下 name username email 杨洋 yangy yangy sina com 贾子豪 jiazh jiazh 126 com 于飞 yuf yuf 163 com 田宇辰 tianych t
  • HttpGet和HttpPost请求

    HttpPost请求 public static void main String args throws IOException String url null 请求地址 Map
  • 分类预测

    作者简介 热爱科研的Matlab仿真开发者 修心和技术同步精进 matlab项目合作可私信 个人主页 Matlab科研工作室 个人信条 格物致知 内容介绍 极限学习机 作为一种新兴的机器学习方法 已经成为了一个热门的研究方向 随机确定单隐含
  • [机器学习与scikit-learn-23]:算法-聚类-KMeans算法的工作原理

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 目录 第1章 KMeans概述 1 1 什么是簇与质心 1 2 质心的计算过程 第2章 聚合指标 2 1 距离和度量方法 2 2 聚合的意义
  • window.open()打开新页面,并往新页面插入内容

    定义和用法 open 方法用于打开一个新的浏览器窗口或查找一个已命名的窗口 语法 window open URL name specs replace 参数说明参考https www runoob com jsref met win ope
  • 使用Spring的JAVA Mail支持简化邮件发送

    闲来无事 翻看 Spring in Action 发现Spring集成了对JAVA Mail的支持 有点小激动的看了一遍 嗯 话说真的简单了很多 Spring的邮件发送的核心是MailSender接口 在Spring3 0中提供了一个实现类
  • 前端学习之初识HTML以及块级元素和行内元素的区别(1)

    目录 一 什么是HTML HTML是HyperType Markup Language 超文本标记语言 HTML的特点 Html标签注意规范 建议镜面嵌套 不建议交叉嵌套 二 块级元素和行内元素 块级元素 行内元素 一 什么是HTML HT
  • 贪心(1)田忌赛马

    目录 一 贪心算法 1 贪心选择性质 2 最优子结构性质 二 田忌赛马 三 OJ实战 CSU 1722 Race 力扣 870 优势洗牌 HDU 1338 Game Prediction HDU 1052 POJ 2287 UVA 1344
  • 神经网络之LN(Layer Normalization)

    上一篇博客提到了BN不适用于RNN等动态网络以及batchsize较小的时候 而LN可以 这篇博客就对LN做一个简单的介绍 深度网络中的数据维度一般是 N C H W 或者 N H W C 格式 N是batch size H W是featu
  • Redis主从复制及其实现原理

    Redis主从复制及其实现原理 首先 简单介绍一下什么是Redis主从复制 假如我们服务中用到了Redis 并且只有一台Redis服务器 如果某个时刻该Redis服务挂了 那么会导致整个服务的Redis不可用 在此期间 大量的请求将会直接打
  • Activiti7工作流+SpringBoot

    文章目录 一 Activiti相关概念 1 Activiti介绍 2 核心类 2 1 ProcessEngine 2 2 服务 Service 类 2 2 1 TaskService 2 2 2 RepositoryService 2 2
  • Objective-C学习笔记---构造函数和析构函数

    简单的讲 构造函数就是在创建一个对象的时候起到初始化的作用 对这个对象里的一些成员变量进行初始化 析构函数就是在对象被删除进行一些清理工作 也就是专门的扫尾工作 下面用代码来进行具体说明 一 构造函数 在OC中凡是已init开头的函数我们都
  • 【通信协议】单总线协议详解——以DHT11为例

    单总线概述 1 单总线的介绍 1 单总线也称为1 Wire bus 它是由美国DALLAS 达尔斯 公司推出的外围串行扩展总线 单总线系统中配置的各种器件 由DALLAS公司提供的专用芯片实现 2 每个芯片都有64位ROM 厂家对每一芯片都