文章目录
- 一、DHT11传感器介绍
-
- 1.1DHT11简介
- 1.2DHT11工作原理
- 1.3DHT11通信时序
-
- 数据总时序
- 主机发送起始信号
- 从机响应信号
- 表示高低电平
- 数据传输
- 二、DHT实现11温湿度采样
-
- 2.1接口说明:
- 2.2编写DHT11源文件
一、DHT11传感器介绍
1.1DHT11简介
DHT11温湿度传感器是一种具有校准数字信号输出的温湿度传感器,包括电阻湿度传感器元件和一个NTC感温元件,并与高性能8位单片机连接。如下图所示,内置上拉电阻,使用时无需连接上拉电阻。
1.2DHT11工作原理
DHT用单总线通信11次。单总线只有一条数据线,即上图out引脚,主机对DHT单总线完成11数据交换和控制。单总线通常要求外接一个约5.1k当总线闲置时,欧姆的上拉电阻处于高电平状态。由于它们是主从结构,只有在主机呼叫时才能响应,因此主机访问设备必须严格遵循单总线序列。如果序列混乱,设备将不响应主机。原理图如下:注意NC引脚不接出来。DHT11的电源电压为3~5.5V。传感器上电后,等待1s在此期间,无需发送任何指令,以越过不稳定状态。电源引脚(VDD,GND)可以增加1000nF用于去耦滤波的电容器。
1.3DHT11通信时序
数据总时序
STM32单片机发送开始信号后,DHT11从低功耗模式到告知模式,主机开始信号结束后,DHT11发送响应信号,发送5个字节的采样数据,然后完成采集任务。
主机发送起始信号
DHT11的out(data)引脚连接单片机GPIO引脚,总线空闲状态高电平,主机GPIO把总线拉低(>=18ms),以保证DHT11可以检测到起始信号,并继续等待20~40us,切换到输入模式,等待和读取DHT11响应。
从机响应信号
DHT11收到主机的开始信号后,等待主机发送开始信号到最后,然后向主机发送80us低电平响应信号,然后DHT11然后拉高总线800us,告诉主机准备发送数据。
表示高低电平
我们需要知道的是,主机和从机通信最基本的单位是位置(bit),0和1,8个位为一字节,一个字节可以表示一个字符。如何表示数字0和1?在这里,每一个bit数据都以50us低电平间隙开始,高电平长度决定数据位为0或1,格式见下图。如果主机读取响应信号为高电平,则表示DHT检查线路是否正常,无响应。当最后一bit数据传输后,DHT11拉低总线50us,然后总线从上拉电阻拉高到空闲状态。
数字0信号表示方法:50us低电平 26~28us高电平 数字1信号表示方法:50us低电平 70us高电平
数据传输
DHT11传输数据时,一次传输4字节温湿度值数据和1字节数据验证。数据格式为:1B湿度数据 1B湿度小数据 1B温度整数据 1B温度小数据 1B验证。但目前小数温湿度尚未使用。 一次性完整的数据传输为40bit,高位先出:MSB,即大端字节序,高位数存在于低地址。 当数据传输正确时,验证和数据等于1B湿度数据 1B湿度小数据 1B温度整数据 1B温度小数据结果最后8位。
二、DHT实现11温湿度采样
2.1接口说明:
DHT11传感器的工作电压范围为3~5.5V,因此接3.3V和5V除此之外,都可以DHT11的I/O口接到单片机的一个GPIO管脚上(我在这里的时候PA5) 。没有内置的上拉电阻DHT当连接线长度小于20米时,建议使用11传感器k当上拉电阻大于20米时,应根据实际情况使用适当的上拉电阻。注:如果传感器上有引脚S,表示信号引脚。 硬件连接如下 插入图片描述
2.2编写DHT11源文件
创建DHT11温湿度传感器驱动源文件dht11.c dht11.c文件
/* * dht11.c * * Created on: 2022年6月17日 * Author: 28980 */ #include "dht11.h" /*用于存储引脚组和引脚号的结构体*/ typedef struct w1_gpio_S {
GPIO_TypeDef *group; uint16_t pin; }w1_gpio_t; /*结构体变量*/ static w1_gpio_t W1Dat = {
.group = GPIOA,//组别A .pin = GPIO_PIN_5,//引脚5,即PA5 }; //定义宏将引脚设置为特定的输入模式。至于为什么它没有被包装成函数,这是因为调用函数过程中的变量和其他数据需要进出栈,这消耗了很多 #define W1DQ_Input() \ {
\ GPIO_InitTypeDef GPIO_InitStruct = {
0};\ GPIO_InitStruct.Pin = W1Dat.pin;\ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;\ GPIO_InitStruct.Pull = GPIO_PULLUP;\ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\ HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct);\ }
//定义宏,将引脚设置为特定的输出模式
#define W1DQ_Output() \ {
\ GPIO_InitTypeDef GPIO_InitStruct = {
0};\ GPIO_InitStruct.Pin = W1Dat.pin;\ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;\ GPIO_InitStruct.Pull = GPIO_NOPULL;\ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\ HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct);\ }
/*运用了三目运算符,如果x为1,则HAL_GPIO_WritePin的第三个参数level为GPIO_PIN_SET(1) ,否则为GPIO_PIN_RESET(0),*/
#define W1DQ_Write(x) HAL_GPIO_WritePin(W1Dat.group, W1Dat.pin,\ (x==1)?GPIO_PIN_SET : GPIO_PIN_RESET)
/*用于读取引脚的电平*/
#define W1DQ_Read() HAL_GPIO_ReadPin(W1Dat.group, W1Dat.pin)
/*向主机发送起始信号*/
static void DHT11_StartSignal(void)
{
W1DQ_Output();//设置引脚为输出模式
W1DQ_Write(0);//输出20ms低电平
HAL_Delay(20);
W1DQ_Write(1);//输出30us高电平
delay_us(30);
W1DQ_Input();//设置引脚为输入模式
}
/*主机检测从机应答信号*/
uint8_t DHT11_RespondSignal(void)
{
uint8_t retry = 0;//用于判断是否超市
/*读取引脚状态,如果是高电平,则说明从机DHT11还没有发送低电平信号给主机,将一直循环,直到retry==100*/
while(W1DQ_Read() && retry < 100)
{
retry++;
delay_us(1);
}
/*retry>=100时,说明从机DHT11没有响应主机*/
if(retry >= 100)
{
printf("The host receives no response signal!\r\n");
return 1;
}
retry = 0;
while(!W1DQ_Read() && retry < 100)
{
retry++;
delay_us(1);
}
if(retry >= 100)
{
printf("DHT11 has not received a start signal!\r\n");
return 1;
}
return 0;
}
/*读取一个位的数据,即为高电平或低电平*/
uint8_t DHT11_ReadBit(void)
{
uint8_t retry = 0;
/*如果是低电平,则跳过这个while循环*/
while(W1DQ_Read() && (retry < 100))
{
retry++;
delay_us(1);
}
retry = 0;
while( !W1DQ_Read() && retry < 100)
{
retry++;
delay_us(1);
}
delay_us(40);
if(W1DQ_Read())
{
return 1;
}
else
{
return 0;
}
}
/*读取一个字节的数据*/
uint8_t DHT11_ReadByte(void)
{
uint8_t i, dat;
dat = 0;
for(i=0; i<8; i++)
{
dat <<=1;//大端字节序,每循环一次左移一位,将最新的一位数据放到最右一位
dat |= DHT11_ReadBit();
}
return dat;
}
/*一次采样*/
int DHT11_SampleData(float *temperature, float *humidity)
{
uint8_t humi_H8bit;
uint8_t humi_L8bit;
uint8_t temp_H8bit;
uint8_t temp_L8bit;
uint8_t check_sum;
if(!temperature || !humidity)
return -1;
DHT11_StartSignal();
if(0 != DHT11_RespondSignal())
return -2;
humi_H8bit = DHT11_ReadByte();//湿度整数
humi_L8bit = DHT11_ReadByte();//湿度小数
temp_H8bit = DHT11_ReadByte();//温度整数
temp_L8bit = DHT11_ReadByte();//温度小数
check_sum = DHT11_ReadByte();//校验和
if((humi_H8bit + humi_L8bit + temp_H8bit + temp_L8bit) != check_sum)
return -3;
*humidity = (humi_H8bit*1000 + humi_L8bit)/1000;//湿度,整数+小数(保留三位小数)
*temperature = (temp_H8bit*1000 + temp_L8bit)/1000;
return 0;
}
dht11.h文件
/* * dht11.h * * Created on: 2022年6月17日 * Author: 28980 */
#ifndef INC_DHT11_H_
#define INC_DHT11_H_
#include "main.h"
extern int DHT11_SampleData(float *temperature, float *humidity);
#endif /* INC_DHT11_H_ */
main.h文件需要在main()里面添加的代码
while(1)
{
int flag = DHT11_SampleData(&temperature, &humidity);
if( flag < 0 )
{
printf("ERROR: DHT11 Sample Data failure:%d\r\n", flag);
}
else
{
printf("DHT11 Sample Temperature: %.3f Relative Humidity: %.3f\r\n", temperature,humidity);
}
HAL_Delay(3000);
}