外设驱动库开发笔记15:DHT11温湿度传感器驱动

DS18B20一样DHT11也是采用单总线,但所不同的是DHT11可同时实现温度和湿度的检测。在我们的产品中经常使用它来检测环境的温湿度信息。这一篇我们将设计并封装DHT11的驱动程序,以方便重复使用。

1、功能概述

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。

1.1、硬件描述

传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选择。产品为4针单排引脚封装。

DHT11的供电电压为 35.5V。传感器上电后,要等待 1s 以越过不稳定状态在此期间无需发送任何指令。电源引脚(VDDGND)之间可增加一个100nF 的电容,用以去耦滤波。

1.2、通讯接口

DHT11传感器单总线通讯建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使用合适的上拉电阻。连线图如下:

DATA用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为零。一次完整的数据传输为40bit,高位在前。数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和。

其中,在数据传送正确时,校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据所得结果的末8位。

用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据。通讯过程如下图所示:

从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集。采集数据后转换到低速模式。

2、驱动设计与实现

我们已经了解了DHT11温湿度传感器的相关信息,接下来我们将设计并实现DHT11温湿度传感器的驱动程序。

2.1、对象定义

在使用一个对象之前我们需要获得这个对象。同样的我们想要操作DHT11温湿度传感器就需要先定义DHT11温湿度传感器的对象。

2.1.1、对象的抽象

我们要得到DHT11温湿度传感器对象,需要先分析其基本特性。一般来说,一个对象至少包含两方面的特性:属性与操作。接下来我们就来从这两个方面思考一下DHT11温湿度传感器的对象。

先来考虑属性,作为属性肯定是用于标识或记录对象特征的东西。我们来考虑DHT11温湿度传感器对象属性。DHT11温湿度传感器并没有标识设备区别的特性,只有温度和湿度信息可以表示当前的工作状态我们将其作为属性。

接着我们还需要考虑DHT11温湿度传感器对象的操作问题。我们知道DHT11温湿度传感器采用的是单总线。单总线就需要控制总线的输入输出方向,而且这对这条总线在不同的输入输出方向,我们需要读数据和写数据,而这些操作都依赖于硬件平台,所以我们将他们定义为DHT11温湿度传感器对象的操作。处于时序控制的需要,我们需要延时操作函数,而在不同的软硬件平台延时操作会有差异,我们也将其作为对象的操作。

根据上述我们对DHT11温湿度传感器的分析,我们可以定义DHT11温湿度传感器的对象类型如下:

/* 定义DHT11对象类型 */
typedef struct Dht11Object {float temperature;             //温度值float humidity;                         //湿度值uint8_t (*SetPinOutValue)(DhtPinValueType setValue);//设置DHT11引脚的输出值uint8_t (*ReadPinBit)(void);//读取引脚电平void (*SetPinDirection)(DHT11IOModeType mode);//设置引脚的输入输出方向void (*Delayms)(volatile uint32_t nTime);      /*实现ms延时操作*/void (*Delayus)(volatile uint32_t nTime);      /*实现us延时操作*/
}Dht11ObjectType;

2.1.2、对象初始化

我们知道,一个对象仅作声明是不能使用的,我们需要先对其进行初始化,所以这里我们来考虑DHT11温湿度传感器对象的初始化函数。一般来说,初始化函数需要处理几个方面的问题。一是检查输入参数是否合理;二是为对象的属性赋初值;三是对对象作必要的初始化配置。据此我们设计DHT11温湿度传感器对象的初始化函数如下:

/*DHT11初始化操作*/
DHT11ErrorType InitializeDHT11(Dht11ObjectType *dht,                //需要初始化对象Dht11SetPinOutValueType setPinStatus,//设置总线输出值Dht11ReadPinBitType getPinStatus,    //读取总线输入值Dht11SetPinModeType mode,            //配置总线的输入输出模式Dht11DelayType delayms,              //毫秒延时Dht11DelayType delayus                //微秒延时)
{if((dht==NULL)||(setPinStatus==NULL)||(getPinStatus==NULL)||(mode==NULL)||(delayms==NULL)||(delayus==NULL)){return DHT11_InitError;}dht->SetPinOutValue=setPinStatus;dht->ReadPinBit=getPinStatus;dht->SetPinMode=mode;dht->Delayms=delayms;dht->Delayus=delayus;dht->humidity=0.0;dht->temperature=0.0;ResetDHT11(dht);return CheckDHT11Status(dht);
}

2.2、对象操作

我们已经完成了DHT11温湿度传感器对象类型的定义和对象初始化函数的设计。但我们的主要目标是获取对象的信息,接下来我们还要实现面向DHT11温湿度传感器的各类操作。

2.2.1、启动数据通讯

DHT11温湿度传感器上电后,总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号。主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。启动数据通讯的时序图如下:

/*复位DHT11,开始通讯*/
static void ResetDHT11(Dht11ObjectType *dht)
{dht->SetPinMode(DHT11_Out);                 //设置为输出方式dht->SetPinOutValue(DHT11_Reset);           //将引脚点位拉低dht->Delayms(20);                           //拉低至少18msdht->SetPinOutValue(DHT11_Set);             //拉高dht->Delayus(30);                           //主机拉高20至40us
}

DHT11传感器的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11 DATA引脚处于输出状态,输出80微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待80微秒的高电平后的数据接收。

/*等待DHT11的回应,返回1:未检测到DHT11的存在;返回0:存在*/
static DHT11ErrorType CheckDHT11Status(Dht11ObjectType *dht)
{uint8_t retry=0;dht->SetPinMode(DHT11_In);                          //设置为输入方式while(dht->ReadPinBit()&&(retry<100)){retry++;dht->Delayus(1);}if(retry>=100){return DHT11_None;}retry=0;while(!dht->ReadPinBit()&&(retry<100)){retry++;dht->Delayus(1);}if(retry>=100){return DHT11_None;}return DHT11_NoError; 
}

2.2.2、读取数据位

当主机变为输入模式后,检测到总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是“0”还是“1”。表示0”“1”的时序图如下所示:

/*从DHT11读取一个位,返回值:1/0*/
static uint8_t ReadBitFromDHT11(Dht11ObjectType *dht)               
{uint8_t retry=0;/*等待变为低电平*/while(dht->ReadPinBit()&&(retry<100)){retry++;dht->Delayus(1);}retry=0;/*等待变高电平*/while(!dht->ReadPinBit()&&(retry<100)){retry++;dht->Delayus(1);}dht->Delayus(40);               //延时判断此位是0还是1return dht->ReadPinBit();
}

当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。

3、驱动的使用

我们已经实现了DHT11温湿度传感器的驱动,接下来将以此驱动为基础设计了简单的测试应用。

3.1、声明并初始化对象

使用基于对象的操作我们需要先得到这个对象,所以我们先要使用前面定义的DHT11温湿度传感器对象类型声明一个DHT11温湿度传感器对象变量,具体操作格式如下:

Dht11ObjectType dht;

声明了这个对象变量并不能立即使用,我们还需要使用驱动中定义的初始化函数对这个变量进行初始化。这个初始化函数所需要的输入参数如下:

Dht11ObjectType *dht,需要初始化对象

Dht11SetPinOutValueType setPinStatus,设置总线输出值

Dht11ReadPinBitType getPinStatus,读取总线输入值

Dht11SetPinModeType mode,配置总线的输入输出模式

Dht11DelayType delayms,毫秒延时

Dht11DelayType delayus,微秒延时

对于这些参数,对象变量我们已经定义了。剩下的输入参数就是我们操作中需要的函数,这几个函数需要我们在应用中定义,并将函数指针作为参数。这几个函数的类型如下:

typedef uint8_t (*Dht11SetPinOutValueType)(DhtPinValueType setValue);//设置DHT11引脚的输出值
typedef uint8_t (*Dht11ReadPinBitType)(void);//读取引脚电平
typedef void (*Dht11SetPinModeType)(DHT11IOModeType mode);//设置引脚的输入输出方向
typedef void (*Dht11DelayType)(volatile uint32_t nTime);      /*实现ms延时操作*/

对于这几个函数我们根据样式定义就可以了,具体的操作可能与使用的硬件平台有关系。我们在STM32F4HAL库环境下使用,具体函数定义如下:

//设置DHT11引脚的输出值
uint8_t Dht11SetPinOutValue(DhtPinValueType setValue)
{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_11,(GPIO_PinState)setValue);
}//读取引脚电平
uint8_t Dht11ReadPinBit(void)
{return (uint8_t)HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11);
}//设置引脚的输入输出方向
void Dht11SetPinMode(DHT11IOModeType mode)
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin = GPIO_PIN_11;if(mode==DHT11_In){ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;}else{ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;} HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

对于延时函数我们可以采用各种方法实现。我们采用的STM32平台和HAL库则可以直接使用HAL_Delay()函数。微秒延时函数则使用我们自己定义的。于是我们可以调用初始化函数如下:

InitializeDHT11(&dhtDht11SetPinOutValueDht11ReadPinBitDht11SetPinModeHAL_DelayDelayus);

3.2、基于对象进行操作

我们定义了对象变量并使用初始化函数给其作了初始化。接着我们就来考虑操作这一对象获取我们想要的数据。我们在驱动中已经将获取数据并转换为转换值的比例值,接下来我们使用这一驱动开发我们的应用实例。

/*获取数据值*/
void GetMeasureDataFromDHT11(void)
{float temperature;             //温度值float humidity;                         //湿度值GetProcessValueFromDHT11(&dht);temperature=dht.temperature;humidity=dht.humidity;
}

4、应用总结

我们已经实现了DHT11温湿度传感器的驱动,并在此基础上设计了简单的验证应用。经过测试,利用驱动我们成功的读取了温湿度数据。

根据数据手册的要求,DHT11温湿度传感器上电后要等待1S以越过不稳定状态在此期间不能发送任何指令。

单总线数据传输时,会改变总线的输入输出方向。在我们的应用中,我们修改了对应GPIO引脚的输入输出模式。事实上如果我们在STM32中使用时,我们可将该引脚配置为开漏输出模式,加上总线的上拉电阻,可以在不修改GPIO的输入输出模式的情况下实现读写。

源码下载:https://github.com/foxclever/ExPeriphDriver

欢迎关注:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499347.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外设驱动库开发笔记16:MS5536C压力变送器驱动

压力检测也是经常会遇到的需求&#xff0c;比如环境压力或者低压气体等都会用到压力检测。这类检测压力都比较低&#xff0c;一般不会超过大气压&#xff0c;有时甚至是负压。这一篇我们要讨论的MS5536C就属于这类器件。接下来我们将设计并实现MS5536C的驱动。 1、功能概述 M…

外设驱动库开发笔记17:MS5803压力变送器驱动

很多时候我们需要检测被控对象的绝对压力&#xff0c;而且在我们的多款产品中也有这样的需求。当然检测绝对压力的传感器有很多&#xff0c;我们经常使用MS5803来实现压力检测。本篇中我们将设计并实现MS5803系列压力传感器的驱动。 1、功能概述 MS5803系列产品包含压阻传感器…

通讯接口应用笔记1:RS485通讯上下拉电阻的选择

RS485是一种常见的通讯接口方式&#xff0c;在我们的实际产品中也是多次使用。但我们平常并不会去过多考虑某一实现的细节问题&#xff0c;不过最近我们遇到了一个因如上下拉电阻的选择问题而造成的通讯故障&#xff0c;所以在这一片中我们来讨论一下RS485总线上下拉电阻的选择…

外设驱动库开发笔记18:MS5837压力变送器驱动

绝对压力的检测是常见的需求。在我们的系统中也常常会遇到。而MS5837压力传感器也是我们进场会采用的方案。在这篇里我们将讨论并实现MS5837压力传感器的驱动。 1、功能概述 MS5837压力传感器是一种可用于电路板上&#xff0c;适用于检测10-1200mbar压力范围的传感器&#xf…

外设驱动库开发笔记19:BMP280压力温度传感器驱动

压力和温度监测在嵌入式系统开发中是非常常见的需求&#xff0c;特别是对环境大气压力和温度的检测需求就更常见了。我们一般都会选择一些封装较小操作比较方便的压力传感器。BMP280就是满足这一要求的器件。在这一篇中我们将设计并实现BMP280的驱动。 1、功能概述 BMP280是一…

一个简单的空气质量数据监测站项目

大气质量数据监测站用于测试空气质量监测及数据采集&#xff0c;实现野外或者室内空气质量的检测。并通过网络将数据上传到OneNet​显示。​ 1、项目概述 本项目是一个定制项目&#xff0c;要求采集大气的压力、温度、湿度、PM25、位置等数据并上传到指定的后台服务器。但有时…

一个基于STM32实现的多组分气体分析仪项目

本篇将简要的总结一下一个基于STM32F412ZG实现的多组分气体分析仪的项目。简要描述该项目的软硬件设计及其验证。 一、项目概述 多组分气体分析仪是我公司近期研发的三个主要产品之一。采用模块化设计&#xff0c;可增减配置&#xff0c;可分析混合气体中的氧气、氢气、甲烷、…

外设驱动库开发笔记20:BME280压力湿度温度传感器驱动

嵌入式产品开发中&#xff0c;我们常常会有检测环境温度、压力、湿度的需求。如果有一个集成有这3个传感器的元件&#xff0c;无疑将是很方便的。博世的BME280就能实现这一要求。在这一篇中我们将讨论BME280的驱动设计与实现。 1、功能概述 BME280是一款专为移动应用而开发的…

外设驱动库开发笔记21:BME680环境传感器驱动

环境传感器是一类我们很常用的传感器。它可以方便我们获取压力、温度、湿度以及空气质量等数据。在这一篇中&#xff0c;我们将分析BME680环境传感器的功能&#xff0c;并设计和实现BME680环境传感器的驱动。 1、功能概述 BME680是一款专为移动应用和可穿戴设备开发的集成环境…

外设驱动库开发笔记22:ADXL345三轴数字加速度计驱动

移动设备的广泛应用增加对移动过程中各种参数的检测需求。ADXL345三轴数字加速度计可以用来检测加速度、进而测量倾斜角度等。在这一篇中&#xff0c;我们将讨论ADXL345三轴数字加速度计驱动程序的设计与实现。 1、功能概述 ADXL345是一款小而薄的超低功耗3轴加速度计&#x…

外设驱动库开发笔记23:AT24Cxx外部存储器驱动

在我们的应用开发过程中&#xff0c;经常会使用到外部的EEPROM外部存储器来保存一些参数和配置数据等。而比较常用的就是AT24Cxx系列产品&#xff0c;这一节我们来开发用于操作AT24Cxx系列产品的驱动。 1、功能概述 AT24Cxx系列EEPROM包括从1Kbit到2Mbit的各种容量。AT24Cxx系…

外设驱动库开发笔记24:FM24xxx系列FRAM存储器驱动

虽然说使用EEPROM保存参数很有效&#xff0c;但操作及使用次数均有一下限制。当我们的一些参数需要不定时修改或存储时&#xff0c;使用FRAM就更为方便一点。这一节我们就来设计并实现FM24xxx系列FRAM的驱动。 1、功能概述 我们首先说一下铁电随机存取存储器&#xff0c;F-RA…

外设驱动库开发笔记25:FM25xxx FRAM存储器驱动

在我们的项目中&#xff0c;时常会有参数或数据需要保存。铁电存储器的优良性能和操作方便常常被我们选用。FM25xxx FRAM存储器就是我们经常使用到的一系列铁电存储器&#xff0c;这一篇我们将讨论FM25xxx FRAM存储器的驱动设计、实现及使用。 1、功能概述 FM25xxx FRAM存储器…

步进电机驱动技术1:基于TMC2660的步进电机驱动

步进电机的应用非常广泛&#xff0c;在各种设备中经常会遇到&#xff0c;而步进电机的驱动则是使用步进电机必不可少的部分&#xff0c;可以有多种方式来实现步进电机的驱动&#xff0c;在这里我们来考虑一下基于TMC2660驱动芯片的步进电机驱动。 1、功能概述 TMC2660是德国T…

外设驱动库开发笔记26:nRF24L01无线通讯驱动

现在无线在我们的生活中无处不在。而我们开发的物联网产品也大量使用无线通讯。在这一篇文章中&#xff0c;我们将讨论nRF24L01无线通讯模块驱动程序的开发与实现。 1、功能概述 nRF24L01是一款工作在2.4~2.5GHz世界通用ISM 频段的单片无线收发器芯片无线收发器包括&#xff…

外设驱动库开发笔记27:ESP8266无线通讯驱动

我们的物联网产品所使用的平台都支持无线通讯&#xff0c;而且无线通讯本身更的成本较低&#xff0c;受到大家的欢迎。在本篇文章中&#xff0c;我们将详细讨论并实现ESP8266无线通讯模块的驱动。 1、功能概述 ESP8266是由乐鑫公司出品的一款物联网芯片&#xff0c;因为价格较…

外设驱动库开发笔记28:W5500以太网控制器

以太网通讯是一种被广泛使用的数据通讯方式。在嵌入式应用中也经常使用&#xff0c;但协议栈的实现并不是一件容易的事。不过有些以太网控制器就带有协议栈&#xff0c;如W5500。在本篇中我们将讨论如何设计并实现W5500以太网控制器的驱动。 1、功能概述 W5500是WIZnet开发的…

外设驱动库开发笔记29:DS17887实时时钟驱动

一些时候&#xff0c;在我们的嵌入式产品中需要记录时间&#xff0c;所以我们就需要获取时钟&#xff0c;当然实现的方式多种多样&#xff0c;有的MCU本身就有这一功能&#xff0c;不过精度较低。当我们的应用要求较高时就需要使用专门的实时时钟芯片&#xff0c;如DS17887。在…

外设驱动库开发笔记30:宇电AI-BUS通讯驱动

嵌入式系统通常都会与外部设备进行通讯&#xff0c;这就涉及到通讯协议的问题。这些通讯协议有的是标准协议有的厂家自定义的协议&#xff0c;如宇电的AI-BUS。在本篇中&#xff0c;我们将讨论AI-BUS的驱动&#xff0c;以便于与宇电设备的通讯。 1、功能概述 宇电的设备使用基…

步进电机驱动技术3:基于ULN2003的步进电机驱动

在我们的项目中&#xff0c;经常使用到低电压小功率的步进电机&#xff0c;此类步进电机若采用驱动器控制不断成本高也过于复杂&#xff0c;我们可以直接使用场效应管或者达林顿管来实现对其的驱动。在本篇中&#xff0c;我们就来讨论一下基于ULN2003A达林顿管实现对步进电机的…