前言
本篇文章将带大家学习使用DHT11湿温度模块,使用这个模块可以获取当前的温度和湿度数据。DHT11可以用于智能家居,蔬菜大棚等项目当中适用范围广。
一、DHT11模块介绍
DHT11 是一种数字式温湿度传感器,由杜邦公司推出。它可以测量环境中的温度和湿度,并将测量结果以数字形式传输给微控制器或其他电子设备,适用于通过数字信号读取环境温湿度的应用场景。
DHT11 传感器使用单总线数据交换协议,可以通过一个 I/O 引脚进行控制和数据传输。它的测量精度为±2℃(在 0℃~50℃ 温度范围内)和±5%RH(在 20%~80%RH 湿度范围内),在低功耗和成本方面也表现优异。DHT11 传感器适用于许多应用场景,比如室内恒温恒湿、气象站、温室农业以及测量仓库、办公室等场所的温湿度等。
使用 DHT11 传感器的过程中需要注意一些事项。首先,DHT11 传感器测量时间较长,一般需要 1~2 秒左右才能完成一次温湿度测量。另外,传感器的电源电压范围必须在 3V~5V 之间,而且传感器的输出信号是串行数字信号,需要使用微控制器或其他数字电路进行采集和解析。因此,在接入 DHT11 传感器之前,需要对其进行一些电路设计和通信协议的处理才能正常使用。
二、DHT11引脚连接及cubemx配置
VCC----5V
GND----GND
S------信号引脚(接一个GPIO)
cubemx配置:
这里只需要配置一个定时器当作us级延时定时器来使用。GPIO的初始工作放到代码中实现。
配置一个串口来打印温度湿度数据:
三、DHT11时序分析
DHT11只需要通过一根数据闲就可以实现和单片机的通信:
根据时序图我们可以知道驱动DHT11首先需要发送一个起始信号,发送完毕后等待应答信号。
起始信号:引脚发送至少18ms低电平,然后再发送20-40us的高电平。
应答信号:低电平持续80us,高电平持续80us。
接收数据:
当等待到应答信号后就可以开始接受DHT11的数据了。
通过观察可以得知数据1和数据0起始部分都是50us的低电平,数据0高电平时间为26-28us之间,数据高电平时间为70us。我们主要就是根据高电平时间来区分到底是数据0还是数据1。
数据0:
数据1:
通过手册我们可以知道数据由小数部分和整数部分组成。完整的数据传输是40位,并且传感器首先发送更高的数据位。
这 40 位二进制数的组成如下:
8 位湿度整数数据位。
8 位湿度小数数据位。
8 位温度整数数据位。
8 位温度小数数据位。
8 位校验和数据位。
四、DHT11代码编写
有了上面时序图的分析我们就可以开始编写代码部分了。
代码部分需要注意的就是在发送完起始信号后对应数据线的GPIO要配置为输入模式,等待DHT11传输过来的应答信号和数据。在每次发送开始信号的时候都需要重新将数据引脚配置为输出引脚。
dht11.h
#ifndef _DH11_H_ #define _DH11_H_ #include"main.h" #define u8 unsigned char #define u16 unsigned short #define u32 unsigned int //DATA IO的定义 #define DATA_SET() HAL_GPIO_WritePin(DATA_GPIO_Port, DATA_Pin, GPIO_PIN_SET) #define DATA_RESET() HAL_GPIO_WritePin(DATA_GPIO_Port, DATA_Pin, GPIO_PIN_RESET) #define DATA_READ() HAL_GPIO_ReadPin(DATA_GPIO_Port,DATA_Pin) typedef struct { u8 Data[5];//数据存放数组 u8 index; u8 temp;//温度 u8 humidity;//湿度 }DH11_DATA; extern DH11_DATA DH11_data;//DH11属性封装 void DH11_Task(void);//后台轮询调用 #define DATA_Pin GPIO_PIN_7 #define DATA_GPIO_Port GPIOA #endif
dht11.c
#include "dht11.h" extern TIM_HandleTypeDef htim1; static void DATA_OUTPUT(u8 flg);//DATA输出 static u8 DATA_INPUT(void);//DATA输入 static u8 DH11_Read_Byte(void);//DH11读信号 u8 DH11_Read(void);//读取DH11温度和湿度 static void Test(void);//测试程序 DH11_DATA DH11_data; void Delay_us(uint16_t us) { //微秒延时 uint16_t differ = 0xffff-us-5; __HAL_TIM_SET_COUNTER(&htim1,differ); //设定TIM1计数器起始值 HAL_TIM_Base_Start(&htim1); //启动定时器 while(differ < 0xffff-5){ //判断 differ = __HAL_TIM_GET_COUNTER(&htim1); //查询计数器的计数值 } HAL_TIM_Base_Stop(&htim1); } void DATA_OUTPUT(u8 flg) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = DATA_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DATA_GPIO_Port, &GPIO_InitStruct); if(flg==0) { DATA_RESET(); } else { DATA_SET(); } } u8 DATA_INPUT(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; u8 flg=0; GPIO_InitStruct.Pin = DATA_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(DATA_GPIO_Port, &GPIO_InitStruct); if(DATA_READ()==GPIO_PIN_RESET) { flg=0; } else { flg=1; } return flg; } u8 DH11_Read_Byte(void) { u8 ReadDat=0; u8 temp=0; u8 retry=0; u8 i=0; for(i=0;i<8;i++) { while(DATA_READ()==0&&retry<100)//等待直到DHT11输出高电平 { Delay_us(1); retry++; } retry=0; Delay_us(40); if(DATA_READ()==1) { temp=1; } else { temp=0; } while(DATA_READ()==1&&retry<100)//等待直到DHT11输出低电平,表示退出。本轮1bit信号接收完毕。 { Delay_us(1); retry++; } retry=0; ReadDat<<=1; ReadDat|=temp; } return ReadDat; } u8 DH11_Read(void) { u8 retry=0; u8 i=0; DATA_OUTPUT(0);//设置为输出模式MCU向DH11发送信号 HAL_Delay(18); DATA_SET(); Delay_us(20); DATA_INPUT();//设置为输入模式DH11向MCU发送信号 Delay_us(20); if(DATA_READ()==0) { while(DATA_READ()==0&&retry<100) { Delay_us(1); retry=0; } retry=0; while(DATA_READ()==1&&retry<100) { Delay_us(1); retry++; } retry=0; for(i=0;i<5;i++)//Data[0]湿度, Data[2]温度。Data[1]和Data[3]分别为0和2的小数位。Data[4]用于校验。 { DH11_data.Data[i]=DH11_Read_Byte(); } Delay_us(50); } u32 sum=DH11_data.Data[0]+DH11_data.Data[1]+DH11_data.Data[2]+DH11_data.Data[3];//校验 if((sum)==DH11_data.Data[4]) { DH11_data.humidity=DH11_data.Data[0];//获取湿度 DH11_data.temp=DH11_data.Data[2];//获取温度 return 1; } else { return 0; } } void Test(void) { if(DH11_Read()) { DH11_data.index++; if(DH11_data.index>=128) { DH11_data.index=0; } } } void DH11_Task(void) { Test(); }
main函数测试代码:
这里需要注意的就是DHT11的数据读取不要太快了,因为DHT11数据转换也是需要一定时间的。
DH11_Task(); printf("Temp is %d\r\n", DH11_data.temp); printf("Hum is %d\r\n", DH11_data.humidity); HAL_Delay(3000);
总结
本篇文章就介绍到这里,大家可以自己尝试进行DHT11的驱动程序编写。
源码将放到公众号中:回复数字8即可得到源码。