STM32 HAL DHT11驱动程序

发布于:2025-04-13 ⋅ 阅读:(25) ⋅ 点赞:(0)

DHT11驱动程序会占用TIM3定时器,进行高精度延时。程序共包含4个文件 

DHT11.c DHT11.h delay.c delay.h

DHT11.c

#include "stm32f1xx_hal.h"
#include "dht11.h"
#include "delay.h"  // 添加延时头文件
#define DHT_PORT  GPIOB
#define DHT_PIN  GPIO_PIN_10
//配置A9为输出模式
void DHT11_Output_Mode(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	__HAL_RCC_GPIOB_CLK_ENABLE();
	GPIO_InitStructure.Pin   = DHT_PIN; 	
	GPIO_InitStructure.Mode  = GPIO_MODE_OUTPUT_PP;	//推挽输出
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStructure.Pull  = GPIO_NOPULL;
	HAL_GPIO_Init(DHT_PORT, &GPIO_InitStructure);
}
//配置A9为输入模式
void DHT11_Input_Mode(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	__HAL_RCC_GPIOB_CLK_ENABLE();
	GPIO_InitStructure.Pin   = DHT_PIN; 	//9号引脚
	GPIO_InitStructure.Mode  = GPIO_MODE_INPUT;  //浮空输入
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStructure.Pull  = GPIO_NOPULL;
	HAL_GPIO_Init(DHT_PORT, &GPIO_InitStructure);
}
 
//A9输出电平0/1
void DHT11_DQ_OUT(uint8_t BitValue)
{
	HAL_GPIO_WritePin(DHT_PORT, DHT_PIN, (GPIO_PinState)BitValue);
}
 
//A9读取输入电平0/1
uint8_t DHT11_DQ_IN(void)
{
	return HAL_GPIO_ReadPin(DHT_PORT, DHT_PIN);
}
 
 
//DHT11复位信号
void DHT11_Reset(void)
{
	DHT11_Output_Mode();
	DHT11_DQ_OUT(0);//拉低DQ,复位信号的开始
	delay_ms(20);//拉低至少18ms
	DHT11_DQ_OUT(1);// 将DHT11的DQ引脚拉高,结束复位信号
	delay_us(25); //在拉高DQ之后,DHT11会开始其内部复位过程,拉高20-40us
}
 
//检测是否有DHT11存在,0存在,1不存在
uint8_t DHT11_Check(void)
{
	uint8_t retry = 0;//初始为0,用来重复计次
	DHT11_Input_Mode();//设置PA9为输入模式,接收DHT11信号
	// 等待DHT11拉低DQ引脚,这通常发生在复位信号之后的40-80微秒内
   
	while(DHT11_DQ_IN() && retry < 100)//DHT拉低40-80us
	{
		retry++;//每次循环计次加一
		delay_us(1);
	}
	
	//如果在计次100次内没有被拉低,返回1则认为DHT11没有响应,否则重置计次变量为0,
	//为下一次等待阶段做准备
	if(retry >= 100) return 1; 
	else 
	{
		retry = 0;
	}
		
	// 等待DHT11拉高DQ引脚,在拉低之后的40-80微秒内
    // 如果DQ在100次重试内没有被拉高,同样认为DHT11没有正确响应
	while(!DHT11_DQ_IN() && retry < 100)//DHT会再拉高40-80us
	{
		retry++;
		delay_us(1);
	}
	if(retry >= 100) return 1;
	return 0;
	
	
}
//检测DHT11是否响应,1无,0有
uint8_t DHT11_Init(void)
{
	DHT11_Output_Mode();//DHT11_Rst函数中也执行,但为了确保在复位之前引脚状态正确,再次设置
	DHT11_Reset();//重置DHT11
	return DHT11_Check();//检测是否DHT11响应
}
 
//读取一个位1/0
uint8_t DHT11_Read_Bit(void)
{
	uint8_t retry = 0;
	while(DHT11_DQ_IN() && retry < 100)//DHT会拉低40-80us
	{
		retry++;
		delay_us(1);
	}
	retry = 0;
	while(!DHT11_DQ_IN() && retry < 100)//DHT会拉低40-80us
	{
		retry++;
		delay_us(1);
	}
	// 根据DHT11的通信协议,拉高DQ引脚后会保持一段时间
    // 对于数据位1,DQ引脚会在50微秒内保持高电平;对于数据位0,DQ引脚会在30微秒内拉低
    // 取中间值等待40微秒
	delay_us(40);
	if(DHT11_DQ_IN()) return 1;
	else return 0;
}
//读取一个字节
uint8_t DHT11_ReadByte(void)
{
	uint8_t i,Dat = 0;
	for(i = 0; i < 8; i++)
	{
		Dat <<= 1;
		Dat |= DHT11_Read_Bit();//Dat某一位或运算上1必定为1,或上0位不变
	}
	return Dat;
}
//temp温度数据范围0-50度
//humi湿度数据范围20-90%
//指向存储温度数据的uint8_t变量的指针temp,
//指向存储湿度数据的uint8_t变量的指针humi
//返回值0表示读取成功,1读取失败
uint8_t DHT11_ReadData(uint8_t * temp,uint8_t *humi)
{
	uint8_t DHT11_Buff[5];//用来存读取DHT11得到的5个字节数据
	uint8_t i;
	
	DHT11_Reset();//复位DHT11
	
	if(DHT11_Check() == 0)//如果存在DHT11,读取温湿度数据
	{
		for(i = 0;i < 5;i++)
		{
			DHT11_Buff[i] = DHT11_ReadByte();
		}
		
		//验证数据的完整性,计算前4个字节的和与第5个字节校验和进行比较
		if(DHT11_Buff[0] + DHT11_Buff[1] + DHT11_Buff[2] + DHT11_Buff[3] ==         
         DHT11_Buff[4])
		{
			*temp = DHT11_Buff[2];//温度整数数据
			*humi = DHT11_Buff[0];//湿度整数数据
			//小数部分为0不用读取
		}
	}
	else
	{
		return 1;//读取失败
	}
	return 0;//存在DHT11
}

DHT11.h

#ifndef  __DHT11_H__
#define	 __DHT11_H__
#include<stdint.h>
#include "delay.h"

// DHT11初始化函数,检测传感器是否存在
// 返回0表示存在,返回1表示不存在
uint8_t DHT11_Init(void);

// 配置DHT11数据引脚为输入模式
// 用于读取DHT11发送的数据
void DHT11_Input_Mode(void);

// 配置DHT11数据引脚为输出模式
// 用于向DHT11发送命令信号
void DHT11_Output_Mode(void);

// 控制DHT11数据引脚输出高低电平
// 参数BitValue: 0表示输出低电平,1表示输出高电平
void DHT11_DQ_OUT(uint8_t BitValue);

// 读取DHT11数据引脚的电平状态
// 返回值: 0表示低电平,1表示高电平
uint8_t DHT11_DQ_IN(void);

// 发送复位信号给DHT11
// 拉低数据线至少18ms,然后拉高20-40us,启动DHT11
void DHT11_Reset(void);

// 检测DHT11是否响应复位信号
// 返回0表示DHT11响应正常,返回1表示无响应
uint8_t DHT11_Check(void);

// 从DHT11读取一个位的数据
// 返回值: 读取到的位值(0或1)
uint8_t DHT11_Read_Bit(void);

// 从DHT11读取一个字节的数据
// 返回值: 读取到的字节值
uint8_t DHT11_ReadByte(void);

// 读取DHT11的温湿度数据
// 参数temp: 指向存储温度数据的变量的指针(范围0-50℃)
// 参数humi: 指向存储湿度数据的变量的指针(范围20-90%)
// 返回值: 0表示读取成功,1表示读取失败
uint8_t DHT11_ReadData(uint8_t *temp, uint8_t *humi);

#endif

 delay.c

#include "delay.h"
#include "stm32f1xx_hal.h"

TIM_HandleTypeDef htim3;

/**
  * @brief  初始化定时器3用于延时
  * @param  无
  * @retval 无
  */
void Delay_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  
  /* 使能TIM3时钟 */
  __HAL_RCC_TIM3_CLK_ENABLE();
  
  /* 基础配置 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 72-1;  // 72MHz / 72 = 1MHz,即计数频率为1MHz,计数周期为1us
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 0xFFFF;  // 最大计数值
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  
  /* 启动定时器 */
  HAL_TIM_Base_Start(&htim3);
}

/**
  * @brief  微秒级延时
  * @param  nus: 延时的微秒数,范围:0~65535
  * @retval 无
  */
void delay_us(uint16_t nus)
{
  uint16_t differ;
  uint16_t ticks = nus;
  uint16_t start = __HAL_TIM_GET_COUNTER(&htim3);
  
  while(1)
  {
    uint16_t now = __HAL_TIM_GET_COUNTER(&htim3);
    
    if(now < start)
      differ = now + 65536 - start;  // 处理计数器溢出
    else
      differ = now - start;
    
    if(differ >= ticks)
      break;
  }
}

/**
  * @brief  毫秒级延时
  * @param  nms: 延时的毫秒数
  * @retval 无
  */
void delay_ms(uint16_t nms)
{
  uint32_t i;
  for(i = 0; i < nms; i++)
  {
    delay_us(1000);  // 1ms = 1000us
  }
}

delay.h

#ifndef __DELAY_H
#define __DELAY_H

#include "stm32f1xx_hal.h"

void Delay_Init(void);
void delay_us(uint16_t nus);
void delay_ms(uint16_t nms);

#endif /* __DELAY_H */


使用步骤:

1、在主函数文件添加包含

#include "dht11.h"
#include "delay.h"

2、初始化dht11和定时器延时,注意要先初始化    Delay_Init();

	Delay_Init();
	DHT11_Init();

3、通过函数读取问湿度值

uint8_t temp,humidity ;
DHT11_ReadData(&temp,&humidity);

代码结束

ai编程提示词

DHT11使用以下函数获取温度和湿度。
//temp温度数据范围0-50度
//humi湿度数据范围20-90%
//指向存储温度数据的uint8_t变量的指针temp,
//指向存储湿度数据的uint8_t变量的指针humi
//返回值0表示读取成功,1读取失败
uint8_t DHT11_ReadData(uint8_t * temp,uint8_t *humi)