首页 > 其他分享 >【STM32+HAL库】---- 驱动DHT11温湿度传感器

【STM32+HAL库】---- 驱动DHT11温湿度传感器

时间:2024-03-22 22:33:06浏览次数:16  
标签:CODE HAL 温湿度 ---- USER GPIO Data DHT11

硬件开发板:STM32F407VET6
软件平台:cubemax+keil+VScode

1 DHT11工作原理

1.1 简介

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件。该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。
image

1.2 接线

image

建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使用合适的上拉电阻
image

1.3 供电

DHT11的供电电压为 3-5.5V。传感器上电后,要等待 1s 以越过不稳定状态在此期间无需发送任何指令。电源引脚(VDD,GND)之间可增加一个100nF 的电容,用以去耦滤波

1.4 串行数据接口

DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,一次完整的数据传输为40bit,高位先出

数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和

数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据” 所得结果的末8位

1.5 时序与通信

image
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集, 用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集, 如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后转换到低速模式。

image

  • 总线空闲状态为高电平

  • 主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号

  • DHT11接收到主机的开始信号后, 等待主机开始信号结束,然后发送80us低电平响应信号

  • 主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号

  • 主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高

  • 总线为低电平,说明DHT11发送响应信号

  • DHT11发送响应信号后,再把总线拉高80us,准备发送数据(每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1)
    数字0信号表示方法:
    image
    数字1信号表示方法:
    image

  • 如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常

  • 当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态

2 cubemx配置

2.1 配置烧录环境

image

2.2 启用外部时钟

image

2.3 配置时钟树

image
注意这里的timer定时器时钟频率是84MHz

2.4 配置串口

打印调试输出
image

2.5 配置定时器

依赖定时器提供微秒延时函数(建议选择32位定时器,这样可以避免计数溢出,保证延时的精确性):上面提到系统分配给timer的频率为84MHz,所以将预分频系数配置为84-1,就可以得到1MHz的定时器频率,即1有1000000个脉冲,每个脉冲周期为1us,每计一次数就是1us
image

2.6 配置结束,导出工程

image

image

3 代码

3.1 printf重定向

打开keil魔术棒界面,使能微库
image
在usart.h中添加头文件和函数声明

#include "stdio.h"

int fputc(int ch,FILE *f);

在usart.c中添加重定向函数

//重定向printf
int fputc(int ch,FILE *f)
{
  uint8_t temp[1]={ch};
  HAL_UART_Transmit(&huart1,temp,1,2);
  return ch;
}

3.2 延时函数

#include "tim.h"

/**
 * ************************************************************************
 * @brief 基于32位定时器构造的微秒延时函数
 * 
 * @param[in] us  微秒值
 * @note 选择32位定时器,可防止计数值溢出,避免加大运算量
 * 
 * ************************************************************************
 */
void my_delay_us(uint32_t us)
{
    __HAL_TIM_SET_COUNTER(&htim5, 0);
    
    HAL_TIM_Base_Start(&htim5);
    
    while (__HAL_TIM_GET_COUNTER(&htim5) != us);
    
    HAL_TIM_Base_Stop(&htim5);
}
/**
 * ************************************************************************
 * @brief 基于32位定时器构造的毫秒延时函数
 * 
 * @param[in] ms  毫秒值
 * 
 * ************************************************************************
 */
void my_delay_ms(uint32_t ms)
{
    my_delay_us(ms * 1000);
}

3.3 DHT11驱动

My_DHT11.h

/**
 * ************************************************************************
 * 
 * @file My_DHT11.h
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#ifndef __MY_DHT11_H
#define __MY_DHT11_H

#include "stm32f4xx_hal.h"

#define DHT11_PORT			GPIOA
#define DHT11_PIN			GPIO_PIN_0

#define DHT11_PULL_1		HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET)
#define DHT11_PULL_0		HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET)

#define DHT11_ReadPin		HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN)

/**
 * ************************************************************************
 * @brief 存储传感器数据的结构体
 * 
 * 
 * ************************************************************************
 */
typedef struct
{
	uint8_t humi_int;			// 湿度的整数部分
	uint8_t humi_dec;	 		// 湿度的小数部分
	uint8_t temp_int;	 		// 温度的整数部分
	uint8_t temp_dec;	 		// 温度的小数部分
	uint8_t check_sum;	 		// 校验和

} DHT11_Data_TypeDef;


uint8_t DHT11_ReadData(DHT11_Data_TypeDef* DHT11_Data);

#endif

My_DHT11.c

/**
 * ************************************************************************
 * 
 * @file My_DHT11.c
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#include "My_DHT11.h"
#include "My_Delay.h"

/**
 * ************************************************************************
 * @brief 将DHT11配置为推挽输出模式
 * ************************************************************************
 */
static void DHT11_PP_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.Pin = DHT11_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;	
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

/**
 * ************************************************************************
 * @brief 将DHT11配置为上拉输入模式
 * ************************************************************************
 */
static void DHT11_UP_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.Pin = DHT11_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;	//上拉
	HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

/**
 * ************************************************************************
 * @brief 读取字节
 * @return temp
 * ************************************************************************
 */
uint8_t DHT11_ReadByte(void)
{
	uint8_t i, temp = 0;

	for (i = 0; i < 8; i++)
	{
		while (DHT11_ReadPin == 0);		// 等待低电平结束
		
		my_delay_us(40);			//	延时 40 微秒
		
		if (DHT11_ReadPin == 1)
		{
			while (DHT11_ReadPin == 1);	// 等待高电平结束
			
			temp |= (uint8_t)(0X01 << (7 - i));			// 先发送高位
		}
		else
		{
			temp &= (uint8_t)~(0X01 << (7 - i));
		}
	}
	return temp;
}

/**
 * ************************************************************************
 * @brief 读取一次数据
 * @param[in] DHT11_Data  定义的结构体变量
 * @return 0或1(数据校验是否成功)
 * @note 它首先向DHT11发送启动信号,然后等待DHT11的应答。如果DHT11正确应答,
 * 		 则继续读取湿度整数、湿度小数、温度整数、温度小数和校验和数据,
 * 		 并计算校验和以进行数据校验
 * ************************************************************************
 */
uint8_t DHT11_ReadData(DHT11_Data_TypeDef *DHT11_Data)
{
	DHT11_PP_OUT();			// 主机输出,主机拉低
	DHT11_PULL_0;	
	my_delay_ms(18);				// 延时 18 ms
	
	DHT11_PULL_1;					// 主机拉高,延时 30 us
	my_delay_us(30);	

	DHT11_UP_IN();				// 主机输入,获取 DHT11 数据
	
	if (DHT11_ReadPin == 0)				// 收到从机应答
	{
		while (DHT11_ReadPin == 0);		// 等待从机应答的低电平结束
		
		while (DHT11_ReadPin == 1);		// 等待从机应答的高电平结束
		
		/*开始接收数据*/   
		DHT11_Data->humi_int  = DHT11_ReadByte();
		DHT11_Data->humi_dec = DHT11_ReadByte();
		DHT11_Data->temp_int  = DHT11_ReadByte();
		DHT11_Data->temp_dec = DHT11_ReadByte();
		DHT11_Data->check_sum = DHT11_ReadByte();
		
		DHT11_PP_OUT();		// 读取结束,主机拉高
		DHT11_PULL_1;	
		
		// 数据校验
		if (DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_dec + DHT11_Data->temp_int + DHT11_Data->temp_dec)	
		{
			return 1;
		}		
		else
		{
			return 0;
		}
	}
	else		// 未收到从机应答
	{
		return 0;
	}
}

3.4 功能测试

main.c

#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "My_DHT11.h"
#include "My_Delay.h"	//延时函数文件
/* USER CODE END Includes */

DHT11_Data_TypeDef DHT11_Data;  //定义结构体变量

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM6_Init();
  MX_USART1_UART_Init();
  MX_TIM5_Init();
  /* USER CODE BEGIN 2 */
  printf("code start ok\n");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	my_delay_ms(2000);
	if (DHT11_ReadData(&DHT11_Data))
    {
      printf("湿度:%d RH ,温度:%d ℃ \n", DHT11_Data.humi_int, DHT11_Data.temp_int);
    }
    else
    {
      printf("Read DHT11 ERROR!\n");
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

串口打印

image
受到延时函数精度影响,观察时间戳发现略有误差

标签:CODE,HAL,温湿度,----,USER,GPIO,Data,DHT11
From: https://www.cnblogs.com/zxr-blog/p/18088206

相关文章

  • 给计算机专业学生的建议
     如果条件允许,推荐尝试考研。虽然研究生学历的价值在一定程度上有所下降,但计算机专业研究生的发展前景通常优于本科生。如果决定考研,应尽力提高自己的学校等级。比赛成绩对于求职帮助有限,除非是含金量高的比赛,通常会被名校的学生获取。建议可以参加一些比赛以拓宽视野,但不应......
  • 解读“CFMS中国闪存市场峰会”存储技术看点-2
    根据Yole机构分析数据显示,CXL在2024年开始爬坡,在2025年将会大规模上量,也就是代表着CXL的时代从2025年开始正式到来。服务器目前正面临着内存性能挑战,而CXL部署提供了短期和长期的解决方案。从CXL1.1开始,AI云服务器可以从内存扩展中受益,而CXL3.0有可能为GPU、DPU、FPGA和AS......
  • C语言预编译#pragma宏的作用
    在嵌入式编程中,#pragma指令具有非常重要的作用,因为它允许开发者在不同的编译器之间传达特定的编译指令。由于嵌入式编程通常与硬件紧密相关,且资源有限,这些指令可以帮助开发者更有效地利用可用资源,优化程序,以及处理特定的硬件约束。以下是#pragma在嵌入式编程中的一些常见应用......
  • 搞不清++操作符前置后置的区别?看这篇博客就够了!
    前言:--操作符与++操作符属性可类比理解,懂++就懂--。一、++操作符简介    ++操作符是一种单目操作符,意味着其操作数只有一个,那么由于++操作符位于操作数的位置不同,分为前置++(例:++a)和后置++(例:a++)。++操作符有自增属性,++后会使得自身数值改变,数值+1。二、前置++与后置+......
  • if、switch语句构成的选择结构详解
    前言:C语言是结构化的程序设计语言,这里的结构指的是顺序结构、选择结构、循环结构,C语言是能够实现这三种结构的,其实我们如果仔细分析,我们日常所见的事情都可以拆分为这三种结构或者这三种结构的组合,下文将讲述C语言中选择结构相关语句语法。一、if语句if语句分为单if语句、if......
  • 深入了解与全面解析华为认证(HCIA/HCIP/HCIE)
    一、网络行业技术认证网络行业对于技术评定一般分为两种,一种是企业认证,一种是国家认证企业认证属于技术认证,在国内的互联网企业都会承认,用于评定一个人的技术等级或者企业招投标的资质。网络行业认证最好的有三种,又分别有三种不同等级及多种方向,分别为:华为、思科、H3C(华三......
  • 深入了解与全面解析华为认证(HCIA/HCIP/HCIE)
    一、网络行业技术认证网络行业对于技术评定一般分为两种,一种是企业认证,一种是国家认证企业认证属于技术认证,在国内的互联网企业都会承认,用于评定一个人的技术等级或者企业招投标的资质。网络行业认证最好的有三种,又分别有三种不同等级及多种方向,分别为:华为、思科、H3C(华三......
  • 传感器与雷达和射频数据的区别是什么?
    传感器数据与雷达和射频数据的区别是什么?传感器数据是什么?传感器数据的应用领域传感器数据的未来发展方向雷达和传感器的区别?射频技术和传感器的异同比较?毫米波雷达与其它传感器产品有什么区别?传感器数据是什么?是指由传感器收集并输出的数据,包括物理量的数值和数......
  • 基于SpringBoot的后勤管理系统【附源码】
    后勤管理系统开发说明开发语言:Java框架:ssmJDK版本:JDK1.8服务器:tomcat7数据库:mysql5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:Maven3.3.9摘 要21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次......
  • CF1948G MST with Matching 题解
    洛谷题面CF题面题目要求一个最小值加上一个最大值的最小值,不好直接做,考虑转化。发现树是二分图,而由柯尼希定理可知二分图的最大匹配等于其最小点覆盖。这样就把求\(\min(\min_{\text{生成树}}+\max_{匹配})\)转化为了\(\min(\min_{生成树}+\min_{覆盖})\)。直接\(\math......