资讯详情

《STM32》——一线协议之DHT11温湿度采样

文章目录

  • 一、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);
}

标签: 采样电阻上滤波电容拉低电压外接5k电阻到5vh8a传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台