基于STM32_DHT11单总线温湿度传感器驱动

基于STM32_DHT11单总线温湿度传感器驱动


文章目录

  • 基于STM32_DHT11单总线温湿度传感器驱动
  • 前言
  • 一、DHT11?
  • 二、原理
    • 1.时序
      • 1.主机复位信号和 DHT11 响应信号
      • 2.信号‘0’的表示
      • 3.信号‘1’的表示
      • 4.整个数据信号收发流程
    • 2.数据结构
  • 三、驱动
    • 1 .h文件:
    • 2 .c文件:


前言

趁热打铁,接上篇DS18B20的介绍再出一篇关于单总线传感器DHT11的介绍,相比之下,DHT11的时序和操作更简单易懂。


一、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 的上拉电阻。第三脚为空脚,此管脚悬空不用。

二、原理

1.时序

1.主机复位信号和 DHT11 响应信号

在这里插入图片描述
主机拉低信号维持18ms后释放总线(变为高电平),20-40us后,DHT11会将总线拉低维持40-50微秒再将总线拉高维持40-50微秒,主机在对应时间段内依次检测到低电平信号和高电平信号,表示有从机在位,否则从机不在位。

2.信号‘0’的表示

以12-14微秒的低电平作为始,随之而来的高电平信号维持26-28微秒后拉低,此时序表示信号 0
在这里插入图片描述

3.信号‘1’的表示

同样以12-14微秒的低电平作为始,随之而来的高电平信号维持116-118微秒后拉低,此时序表示信号 1
在这里插入图片描述
总结来讲就是看高电平时间维持的长短,可使用while循环等待电平信号是否为低,循环依次延时1us,计数器+1,如果跳出循环则判断计数器数值,小于30则为0,大于30且小于120则为1,大于120则为错误。

4.整个数据信号收发流程

在这里插入图片描述

2.数据结构

DHT11数字湿温度传感器采用单总线数据格式。即,单个数据引脚端口完成输入输出双向传输。其数据包由5Byte( 40Bit)组成。数据分小数部分和整数部分,具体格式在下面说明。
         一次完整的数据传输为40bit,高位先出。
         数据格式: 8bit湿度整数数据+8bit湿度小数数据
                +8bit温度整数数据+8bit温度小数数据
                +8bit校验和
         校验和数据为前四个字节相加。
传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。如果,某次从传感器中读取如下5Byte数据:
        在这里插入图片描述
由以上数据就可得到湿度和温度的值,计算方法:
        humi (湿度)= byte4 . byte3=45.0 (%RH)
        temp (温度)= byte2 . byte1=28.0 ( ℃ )
        jiaoyan(校验)= byte4+ byte3+ byte2+ byte1=73(=humi+temp)(校验正确)
注意: DHT11一次通讯时间最大3ms,主机连续采样间隔建议不小于100ms。

三、驱动

1 .h文件:

#ifndef __DHT11_H
#define __DHT11_H#include "stdio.h"	
#include "Config.h"  			//包含初始化GPIO,初始化时钟
#include "SysTick.h"/********************************************DHT11 devier********************************************/
#define DHT11_IS_READY      (1u)
#define DHT11_NOT_READY     (0u) #define DHT11_DQ_IN()       {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=0<<9*2;}//PG9 输入模式
#define DHT11_DQ_OUT()      {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=1<<9*2;}//PG9 输出模式#define DHT11_DQ_PORT       GPIOG
#define DHT11_DQ_PIN        GPIO_Pin_9#define DHT11_DQ_LOW        GPIO_ResetBits(DHT11_DQ_PORT,DHT11_DQ_PIN) 
#define DHT11_DQ_HIGH       GPIO_SetBits(DHT11_DQ_PORT,DHT11_DQ_PIN) #define DHT11_DQ_STATUS     GPIO_ReadInputDataBit(DHT11_DQ_PORT,DHT11_DQ_PIN)		//读取DQ状态#define DHT11_delay_us(a)   SysCtlDelayus(a)			      //延时函数us
#define DHT11_delay_ms(a)   SysCtlDelayus(a * 1000)			//延时函数ms#define DHT11_ACK_TIMEOUT           (uint8_t)100	        //等待DHT11响应信号延时
#define DHT11_BIT_START_TIMEOUT     (uint8_t)100	        //1bit起始信号延时时间
#define DHT11_BIT_STATUS_TIMEOUT    (uint8_t)130	        //表示 0 的延时时间typedef enum
{DHT11_1 = 0,DHT11_2,DHT11_3,DHT11_4,DHT11_Num_Counter
}DHT11_Num;typedef struct
{uint8_t DHT11_IndexNumber;float DHT11_Temp;float DHT11_Humi;
}DHT11_Data_Type;extern uint8_t DHT11_Init(void);
extern void DHT11_Reset(void);
extern uint8_t DHT11_GetTemp_Main(void);
extern float DHT11_Get_Temperature(uint8_t Index);
extern float DHT11_Get_Humidity(uint8_t Index);#endif
## 1.时序

.c文件:

#ifndef __DHT11_H
#define __DHT11_H#include "stdio.h"	
#include "Config.h"  			//包含初始化GPIO,初始化时钟
#include "SysTick.h"/********************************************DHT11 devier********************************************/
#define DHT11_IS_READY      (1u)
#define DHT11_NOT_READY     (0u) #define DHT11_DQ_IN()       {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=0<<9*2;}//PG9 输入模式
#define DHT11_DQ_OUT()      {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=1<<9*2;}//PG9 输出模式#define DHT11_DQ_PORT       GPIOG
#define DHT11_DQ_PIN        GPIO_Pin_9#define DHT11_DQ_LOW        GPIO_ResetBits(DHT11_DQ_PORT,DHT11_DQ_PIN) 
#define DHT11_DQ_HIGH       GPIO_SetBits(DHT11_DQ_PORT,DHT11_DQ_PIN) #define DHT11_DQ_STATUS     GPIO_ReadInputDataBit(DHT11_DQ_PORT,DHT11_DQ_PIN)		//读取DQ状态#define DHT11_delay_us(a)   SysCtlDelayus(a)			      //延时函数us
#define DHT11_delay_ms(a)   SysCtlDelayus(a * 1000)			//延时函数ms#define DHT11_ACK_TIMEOUT           (uint8_t)100	        //等待DHT11响应信号延时
#define DHT11_BIT_START_TIMEOUT     (uint8_t)100	        //1bit起始信号延时时间
#define DHT11_BIT_STATUS_TIMEOUT    (uint8_t)130	        //表示 0 的延时时间typedef enum
{DHT11_1 = 0,DHT11_2,DHT11_3,DHT11_4,DHT11_Num_Counter
}DHT11_Num;typedef struct
{uint8_t DHT11_IndexNumber;float DHT11_Temp;float DHT11_Humi;
}DHT11_Data_Type;extern uint8_t DHT11_Init(void);
extern void DHT11_Reset(void);
extern uint8_t DHT11_GetTemp_Main(void);
extern float DHT11_Get_Temperature(uint8_t Index);
extern float DHT11_Get_Humidity(uint8_t Index);#endif

2 .c文件:

 #include "DHT11.h"//#define DHT11_MORE_THAN_ONE DHT11_Data_Type DHT11_Temp[DHT11_Num_Counter] = {{DHT11_1,0.0,0.0},{DHT11_2,0.0,0.0},{DHT11_3,0.0,0.0},{DHT11_4,0.0,0.0}   };static uint8_t DHT11_Read_Bit(void);
static uint8_t DHT11_Read_Byte(void);
static uint8_t DHT11_Check(void);/************************************************************************************
*@fuction	:DHT11_Init
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
extern uint8_t DHT11_Init(void)
{DHT11_Reset();if(DHT11_Check() == DHT11_IS_READY){return DHT11_IS_READY;}
}/************************************************************************************
*@fuction	:DHT11_Reset
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
void DHT11_Reset(void)
{//DHT11 复位时序:DQ输出模式 DQ = 0(20us), DQ = 1(30us.DHT11_DQ_OUT();DHT11_DQ_LOW;DHT11_delay_ms(20);DHT11_DQ_HIGH;DHT11_delay_us(30);
}/************************************************************************************
*@fuction	:DHT11_Check
*@brief		:
*@param		:--
*@return	:1-device ok/0-device error
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
uint8_t DHT11_Check(void)
{uint8_t wait_time = 0;uint8_t Ready_Dev = 0;//DQ输入模式DHT11_DQ_IN();//等待DQ脚被DHT11拉低while((DHT11_DQ_STATUS) && (wait_time < DHT11_ACK_TIMEOUT)){wait_time++;DHT11_delay_us(1);};if(wait_time >= DHT11_ACK_TIMEOUT){//如果等待时间超时,则退出等待return (uint8_t)DHT11_NOT_READY;}else{wait_time = 0;while((!DHT11_DQ_STATUS) && (wait_time < DHT11_ACK_TIMEOUT)){wait_time++;DHT11_delay_us(1);};if(wait_time >= DHT11_ACK_TIMEOUT){//如果等待时间超时,则退出等待return (uint8_t)DHT11_NOT_READY;}else{//如果未超时,则说明设备存在return (uint8_t)DHT11_IS_READY;              }}
}/************************************************************************************
*@fuction	:DHT11_Read_Bit
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
static uint8_t DHT11_Read_Bit(void) 			 //read one bit
{uint8_t wait_time = 0;uint8_t Bit_Status = 0;DHT11_DQ_IN();//等待DQ脚被DHT11拉低while((DHT11_DQ_STATUS) && (wait_time < 100)){wait_time++;DHT11_delay_us(1);}if(wait_time >= 100){//如果等待时间超时,则出现错误,退出等待Bit_Status = 0xFF;}else{wait_time = 0;//等待DQ脚被DHT11抬高while((!DHT11_DQ_STATUS) && (wait_time < DHT11_BIT_START_TIMEOUT)){wait_time++;DHT11_delay_us(1);}if(wait_time >= DHT11_BIT_START_TIMEOUT){//如果等待时间超时,则退出等待Bit_Status = 0xFF;}else{//如果未超时,则说明1bit起始信号正常,wait_time = 0;//进入高电平时长判断while((DHT11_DQ_STATUS) && (wait_time < DHT11_BIT_STATUS_TIMEOUT)){wait_time++;DHT11_delay_us(1);}//如果高电平保持时间小于50us则为0,大于50us则为1if(wait_time <= 50){                 Bit_Status = 0;}else if((50 < wait_time) && (wait_time <= 150)){Bit_Status = 1;              }else{Bit_Status = 0xFF;}}}return Bit_Status;
}
/************************************************************************************
*@fuction	:DHT11_Read_Byte
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
static uint8_t DHT11_Read_Byte(void)
{uint8_t i = 0 ,Bit_Status = 0,aByte = 0;//DQ为输入模式DHT11_DQ_IN();for (i = 0; i < 8; i++){//高位先出Bit_Status = DHT11_Read_Bit();aByte = (aByte << 1) | Bit_Status;}return aByte;
}/************************************************************************************
*@fuction	:DHT11_CheckSumFun
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
uint8_t DHT11_CheckSumFun(uint8_t* MsgArr, uint8_t Lengh){uint8_t CheckSum = 0;uint8_t i = 0;if((MsgArr == NULL_Ptr) && (Lengh == NULL)){return CheckSum;}for(i = 0; i < Lengh; i++){CheckSum = (CheckSum + MsgArr[i]) % 256;}return CheckSum;}/************************************************************************************
*@fuction	:SplicingFloat
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
float SpliceFloat(uint8_t Integer, uint8_t Decimal)
{float Temp = Integer;if(Decimal & 0x80) {Temp = -1 - Temp;}Temp += (Decimal & 0x0f) * 0.1;return Temp;
}/************************************************************************************
*@fuction	:DHT11_GetTemp_Main
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
extern uint8_t DHT11_GetTemp_Main(void)
{uint8_t i = 0,temp[5];DHT11_Reset();if(DHT11_Check() == DHT11_IS_READY){for(i = 0;i < 5;i++){temp[i] = DHT11_Read_Byte();}if(DHT11_CheckSumFun(temp,4) == temp[4]){DHT11_Temp[0].DHT11_Humi = SpliceFloat(temp[0],temp[1]);DHT11_Temp[0].DHT11_Temp = SpliceFloat(temp[2],temp[3]);return E_OK;}}
}/************************************************************************************
*@fuction	:DHT11_Get_Temp
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
extern float DHT11_Get_Temperature(uint8_t Index)
{return DHT11_Temp[Index].DHT11_Temp;
}/************************************************************************************
*@fuction	:DHT11_Get_Temp
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-12-04
************************************************************************************/
extern float DHT11_Get_Humidity(uint8_t Index)
{return DHT11_Temp[Index].DHT11_Humi;
}

注意:

1.硬件电路中DQ脚外部会加上拉电阻,主机释放总线会被上拉电阻自动上拉,但为保险器件我们将主机释放中线写为主动上拉为高电平
2. .h文件中对延时函数DS18B20_delay_us(a)的定义,关于 SysCtlDelayus(a)实际是ARM汇编的一种延时函数的写法,参见另一篇关于延时函数的博客(汇编延时)https://blog.csdn.net/Yin_w/article/details/130036593?spm=1001.2014.3001.5501

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

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

相关文章

如何正确的关闭Redis服务器

Redis官方原生版本是在Linux平台上开发和测试的&#xff0c;但是大多数初学者都是使用Windows系统来学习如何开发的。因此&#xff0c;官方提供了一个叫做“Microsoft Open Tech Redis”的项目&#xff0c;该项目专门为Windows平台提供了一个官方支持的Redis版本&#xff0c;但…

智慧公厕:打破传统,解决城市痛点@中期科技

近年来&#xff0c;随着城市化进程的加速推进&#xff0c;智慧公厕成为人民生活质量提升的重要组成部分。作为一个富有创新和科技感的解决方案&#xff0c;智慧公厕不仅满足了人们对公共环境的要求&#xff0c;还提供了一系列便利的服务&#xff0c;让人们的生活更加舒适、便捷…

最新在线IDE流行度最新排名(每月更新)

2023年10月在线IDE流行度最新排名 TOP 在线IDE排名是通过分析在线ide名称在谷歌上被搜索的频率而创建的 在线IDE被搜索的次数越多&#xff0c;人们就会认为它越受欢迎。原始数据来自谷歌Trends 如果您相信集体智慧&#xff0c;那么TOP ODE索引可以帮助您决定在软件开发项目中…

Nginx解析漏洞

常见的解析漏洞&#xff1a; IIS 5.x/6.0解析漏洞 IIS 7.0/IIS 7.5/ Nginx <0.8.3畸形解析漏洞 Nginx <8.03 空字节代码执行漏洞 Apache解析漏洞 Nginx文件解析漏洞 对于任意文件名&#xff0c;例如:cd.jpg在后面添加/x.php后&#xff0c;即可将文件作为php解析。 原理…

Flink中的时间和窗口

Flink中的时间和窗口 在传统的批处理系统中&#xff0c;我们可以等到一批数据全部都到齐了之后&#xff0c;对其做相关的计算&#xff1b;但是在实时处理系统中&#xff0c;数据是源源不断的&#xff0c;正常情况下&#xff0c;我们就得来一条处理一条。那么&#xff0c;我们应…

函数栈帧的创建与销毁(保姆级讲解)

局部变量是怎么创建的? 在为main函数开辟栈帧空间时&#xff0c;在一定范围内初始化成0CCCCC&#xff0c;再把里面0CCCC的一些开辟空间给局部变量使用。 为什么局部变量的值是随机值? 因为我们在为main函数开辟栈帧空间时&#xff0c;会将一定范围内空间初始成0CCCCCC里面…

Avalonia使一个弹窗弹到指定位置

1.项目下载地址&#xff1a;https://gitee.com/confusedkitten/avalonia-demo 2.UI库Semi.Avalonia&#xff0c;项目地址 https://github.com/irihitech/Semi.Avalonia 3.样式预览 4.PositionControl.axaml <UserControl xmlns"https://github.com/avaloniaui&quo…

华为数通方向HCIP-DataCom H12-831题库(单选题:201-220)

第201题 如图所示,路由器所有的接口开启OSPF,链路的Cost值如图中标识。若在R2的OSPF进程中通过命令import-route direct type 1引入直连路由,则R1到达10.0.2.2 /32的Cost值是以下哪一选项? A、150 B、151 C、200 D、201 答案:C 解析: Loopback0的cost值默认为0,R1-R2的…

AI 律助 Alpha GPT 线上实操发布会,重磅发布!

数字化时代,随着人工智能的迅猛发展,各行各业都在积极探索通过智能化工具实现工作效率翻升的可能性。“ ChatGPT 类产品”是未来办公应用软件发展的重要趋势之一,但如何将 ChatGPT 真正应用于法律人的工作,赋能效率提升?法律行业同样面临着新的挑战和机遇。 破局的关键是实现技…

DevExpress Reporting中文教程 - 如何在macOS等系统中生成导出报表文档

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表。 在本文中&#xff0c;我们将讨论如何在.NET MA…

基于Java的二手车交易管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

访问控制列表ACL讲解——想偷偷访问数据,我ACL可不同意

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 梦想从未散场&#xff0c;传奇永不落幕&#xff0c;博主会持续更新优质网络知识、Python知识、Linux知识以及各种小技巧&#xff0c;愿你我共同在CSDN进步 目录 一、ACL的基本概念 1. ACL是什么 2. 为什么需…

从零开始学习 Java:简单易懂的入门指南之线程同步(三十五)

线程同步 1.线程同步1.1卖票【应用】1.2卖票案例的问题1.3同步代码块解决数据安全问题【应用】1.4同步方法解决数据安全问题【应用】1.5Lock锁【应用】1.6死锁 2.生产者消费者2.1生产者和消费者模式概述【应用】2.2生产者和消费者案例【应用】2.3生产者和消费者案例优化【应用】…

C++程序加速方法

C程序加速方法 1. 将反复使用的数据存放在全局变量里面2. 使用多线程3. 用a和a&#xff0c;a–,--a4. 减少除法运算5. 尽量减少值传递&#xff0c;多用引用来传递参数。6. 循环引发的讨论1&#xff08;循环内定义&#xff0c;还是循环外定义对象&#xff09;7. 循环引发的讨论2…

出游热潮再起,IPIDEA代理IP帮你应对旅游数据采集的挑战

随着互联网的快速发展&#xff0c;旅游行业也随之迅速发展。在线旅游预订已经成为人们出行前的必要步骤&#xff0c;然而&#xff0c;旅游信息的采集却是一项具有挑战性的任务。为了从酒店和航空公司网站、在线旅行社和其他类似来源收集数据&#xff0c;企业需要克服许多障碍。…

valarray 包含对象成员的类(cpp14章)

C代码重用 1.公有继承可以实现 2.包含、私有继承、保护继承用于实现has-a关系&#xff0c;即新的类将包含另一个类的对象。 &#xff08;使用这样类成员&#xff1a;本身是另外一个类对象称为包含 &#xff08;组合或层次化&#xff09;。&#xff09; 3.函数模板、类模…

GoLang连接mysql数据库

跟着文档走GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly. 1.使用命令拉取 go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite2.开始使用 package mainimport ("fmt""github.com/gin-gonic/gin"&…

虚幻阴影整理

虚拟阴影贴图&#xff08;VSM&#xff09;是一种全新的阴影贴图方法&#xff0c;可以提供稳定的高分辨率阴影。通过与虚幻引擎5的Nanite虚拟几何体、Lumen全局光照和反射以及世界分区功能结合使用&#xff0c;它能够实现电影级的品质效果&#xff0c;为大型开放场景提供光照。 …

mysql case when 不命中缓存

case when 在sql 中非常方便数据不同维度统计&#xff0c;但是也会出现mysql 索引不命中问题&#xff0c;当多个case 出现时&#xff0c;需要提取出来到where里面优化 优化后 SELECT date(RecordTime) AS date, count( DISTINCT CASE WHEN Param 1 …

Java之TCP和UDP进行网络编程

目录 一.网络编程 1.1网络编程的作用 1.2网络编程的基本概念 1.3网络编程的实现 二.UDP网络编程 2.1UDP数据报套的初步了解 2.2Java数据报套接字通信模型 2.3Java编程实现UDP通信 三.TCP网络编程 3.1TCP流套接字api 3.2TCP通信代码实现 3.2.1短连接实现代码 3.…