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

2023-10-18 04:01

本文主要是介绍基于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

这篇关于基于STM32_DHT11单总线温湿度传感器驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/230054

相关文章

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu

驱动(RK3588S)第七课时:单节点设备树

目录 需求一、设备树的概念1、设备树的后缀名:2、设备树的语法格式3、设备树的属性(重要)4、设备树格式举例 二、设备树所用函数1、如何在内核层种获取设备树节点:2、从设备树上获取 gpio 口的属性3、获取节点上的属性只针对于字符串属性的4、函数读取 np 结点中的 propname 属性的值,并将读取到的 u32 类型的值保存在 out_value 指向的内存中,函数的返回值表示读取到的

驱动安装注册表指令

HKCR: HKEY_CLASSES_ROOT HKCU: HKEY_CURRENT_USER HKLM: HKEY_LOCAL_MACHINE HKU: HEKY_USER HER: 相对根键

UMDF驱动安装

VS2013 + WDF8.1,UMDF驱动选择User Mode Driver,不要选User Mode Driver 2.0,否则Win7安装有问题,如图 另外,在驱动安装时不要忘记WUDFUpdate_<主版本号><次版本号>.dll文件,具体文件名在INF中查找。此文件可在WDF的安装目录中找到。注意:在WDF的安装目录中会有3个WUDFUpdate_xxx.dll文件,x86,x6