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

news2024/11/13 8:38:23
硬件开发板:STM32F407VET6
软件平台:cubemax+keil+VScode

1 DHT11工作原理

1.1 简介

DHT11温湿度传感器是一种数字式温湿度传感器,其工作原理基于集成了湿度感测元件和NTC温度感测元件的传感器模块。以下是DHT11温湿度传感器的工作原理:

  1. 湿度感测:DHT11传感器的湿度感测元件是一种具有高湿度灵敏度的电容式湿度传感器。它利用吸湿薄膜吸收环境中的水分,导致传感元件的电容值发生变化。当环境湿度增加时,吸湿薄膜吸收更多的水分,电容值增大;反之,当环境湿度减小时,电容值减小。通过测量电容值的变化,可以得知环境的湿度情况。

  2. 温度感测:DHT11传感器的温度感测元件是一颗NTC(Negative Temperature Coefficient)热敏电阻,其电阻值随温度的变化而变化。NTC热敏电阻的特性是随着温度升高电阻值减小,反之则增大。通过测量NTC热敏电阻的电阻值,可以推算出环境的温度情况。

  3. 信号处理:DHT11传感器内部集成了一个微控制器,用于采集湿度和温度感测元件的信号,并将其转换为数字信号输出。微控制器会对采集到的模拟信号进行A/D转换,并对其进行校准和处理,最终输出一个数字信号,表示环境的湿度和温度数值。

  4. 数字信号输出:DHT11传感器的输出是一串数字信号,其中包括湿度值和温度值。通常情况下,这些数字信号是通过单总线串行通信协议传输的,可以直接连接到微控制器或其他数字电路进行处理。

综上所述,DHT11温湿度传感器通过湿度感测元件和温度感测元件来实现对环境湿度和温度的检测,通过内部的信号处理和数字输出,将检测到的湿度和温度值以数字信号的形式输出,具有简单、精准、成本低廉等特点,在各种应用场景中得到了广泛的应用。
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
受到延时函数精度影响,观察时间戳发现略有误差

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2103528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【安全生产】叉车安全带报警器有哪些特点?

叉车安全带报警器是用于防止在叉车发生猛烈碰撞或紧急制动时&#xff0c;司机不与方向盘、挡风玻璃等发生二次碰撞或抛出车外&#xff0c;从而造成的严重伤害的一种叉车安全装置、配件。 很多司机在开叉车时经常有不系安全带的习惯&#xff0c;有很多不负责任的人会认为&#…

智能水培机

目录 一. 选型 1.1 Lichee RV Dock 1.1.1 芯片&#xff1a;D1-H 1.1.2 镜像选择&#xff1a;Tina Linux 二. QT上位机 2.1 选择ID 2.2 主界面刷新数据 2.2.1 设置定时器 2.2.3 定义查询数据库表qtnew的函数checkNew_data 2.2.2 定义槽函数 Refresh_data 2.3 主界面按…

讨论运维监控工具的普及程度

在讨论运维监控工具的普及程度时&#xff0c;加入PIGOSS BSM产品的分析是非常有意义的&#xff0c;因为PIGOSS BSM是一款在中国市场具有一定影响力的运维监控工具。 PIGOSS BSM运维监控工具是一款综合性的IT运维监控解决方案&#xff0c;它能够对多层次的IT资源进行监测&#x…

2024.09.04【读书笔记】|如何使用GATK ASEReadCounter工具进行ASE(等位基因特异性表达)分析

准备数据&#xff1a; 获取基因组序列&#xff08;FASTA格式&#xff09;和对应的基因组注释文件&#xff08;GTF或GFF格式&#xff09;。获取样本的BAM文件&#xff0c;确保这些文件已经过排序和索引。获取变异信息文件&#xff08;VCF格式&#xff09;&#xff0c;包含样本的…

运动耳机哪个牌子的好?精选5款值得入手的骨传导运动耳机分享!

在过去的两年里&#xff0c;骨传导耳机逐渐被大众的所熟知。可能毕竟长时间使用音量过大的传统入耳式耳机&#xff0c;多多少少会对我们的听力健康构成威胁。所以很多人就想找一款不伤耳朵的耳机。然后就了解到了骨传导耳机&#xff0c;所以就会延伸出这些问题——骨传导耳机好…

【效率工具】推荐五款电脑桌面软件,轻量好用!

电脑桌面软件可以帮助我们在电脑上创建分区&#xff0c;然后将文件、文件夹、应用程序等图标整理到对应的分区中&#xff0c;方便我们精准访问文件。不同的电脑桌面软件功能可能存在一些差异&#xff0c;本文分享几个常用的桌面整理工具&#xff0c;以及一些以及分享一些关于电…

EvoSuite使用总结

1.安装EvoSuite插件 以IDEA为例&#xff0c;在Plugins栏搜索EvoSuite后点击install&#xff0c;安装完成后重启IDEA 2.使用EvoSuite 选中文件右键选择Run EvoSuite 生成成功可以看到如下提示&#xff1a; 注意事项&#xff1a; 生成路径&#xff1a;src/test/java 使用juni…

【C++ 第十九章】异常

1.C语言传统的处理错误的方式 传统的错误处理机制&#xff1a; 终止程序&#xff0c;如 assert&#xff0c;缺陷&#xff1a;用户难以接受。如发生内存错误、除 0 错误时就会终止程序。 返回错误码&#xff0c;缺陷&#xff1a;需要程序员自己去查找对应的错误。如系统的很多库…

趣解网络安全专业术语(保密性、暴露)零基础入门到精通,收藏这一篇就够了

保密性confidentiality 使信息不泄露给未授权的个人、实体、进程&#xff0c;或不被其利用的特性。 想象一下&#xff0c;你有一个神秘的盒子&#xff0c;里面装满了你最珍贵的秘密。这个盒子有一个特殊的锁&#xff0c;只有你和你最亲密的朋友能打开它。这个锁特别聪明&#…

新一代交互模式:LUICUIVUI

随着技术的发展&#xff0c;特别是人工智能和机器学习的进步&#xff0c;交互方式也在不断演变。以下是一些新概念&#xff0c;它们描述了当下和未来可能的交互方式&#xff1a; Conversational UI (CUI)&#xff1a; 以对话为基础的用户界面&#xff0c;用户通过自然语言与系统…

Moveit2 Move Group C++ 接口

系列文章目录 留空 文章目录 系列文章目录前言一、完整代码二、编写步骤三、代码分析1. 引入必要的头文件2. 初始化和配置 ROS2 环境3. 设置 MoveIt 规划组和场景4. 可视化5. 获取基本信息6. 开始演示7. 规划姿态目标8. 可视化计划路径9. 移动到姿势目标10. 规划关节空间目标1…

OpenAI发布GPT-4o mini,3.5从此退出历史舞台?

随着OpenAI在2024年7月18日正式发布GPT-4o Mini&#xff0c;无疑在科技界引发了一场新的风暴。这一创新不仅标志着GPT-3.5模型正式退出历史舞台&#xff0c;更预示着人工智能在自然语言处理领域迈入了一个全新的时代。 之前速度最快的模型一直是GPT3.5&#xff0c;随着后来的GP…

数据结构——开篇

一、数据结构&#xff08;内存中&#xff09; 1、定义 用来保存一种或多种特定关系的数据的集合&#xff08;组织和存储数据&#xff09;。 程序 数据结构算法 2、特定关系 &#xff08;1&#xff09;逻辑结构 数据元素与元素之间的关系。 分类&#xff1a;①集合&…

电脑找不到x3daudio1_7.dll怎么解决?5种方法科学修复x3daudio1_7.dll

如果在使用电脑过程中遇到“找不到x3daudio1_7.dll”的错误&#xff0c;这通常意味着您的系统缺少一个关键组件&#xff0c;它是与 Microsoft DirectX 相关的一个文件&#xff0c;主要用于处理高级音频功能&#xff0c;尤其是在游戏和其他多媒体应用程序中。其实这个问题通常可…

传统CV算法——基于Opencv的多目标追踪算法

基于 OpenCV 的跟踪算法有多种&#xff0c;每种算法都有其特定的应用场景和优缺点。以下是一些常见的基于 OpenCV 的目标跟踪算法&#xff1a; 1. BOOSTING 跟踪器 描述&#xff1a;基于 AdaBoost 算法的跟踪器。它是一种早期的跟踪算法&#xff0c;使用的是基于弱分类器的强…

归并、计数排序(画图详解)

归并排序&#xff1a; 基本思想&#xff1a;先递归再回归&#xff0c;在回归的时候进行归并排序 归并排序&#xff1a; 适用于两个有序数组&#xff0c;合并成一个数组的时候&#xff0c;也就是先要递归&#xff0c;递归到最后就相当于一个元素&#xff0c;一个元素就是有序的。…

Unity数据持久化 之 二进制存储法

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​​ 前置知识&#xff1a;1 Byte 8 bit &#xff0c;所以0000 00001 就是一个字节&#xff0c; 该串数字转为十进制代表1…

通过cmd命令的方式转码MP4为webp动图。附带命令解释。

zihao 通过cmd命令的方式转码MP4为webp动图&#xff1a; 均衡大小和z效果的配置&#xff08;直接拷贝后需要改下路径&#xff09;&#xff1a; ffmpeg -i E:\steam\222.mp4 -vcodec libwebp -filter:v fpsfps24 -lossless 0 -compression_level 5 -q:v 35 -loop 1 -preset def…

深入浅出Promise,循序渐进掌握JavaScript异步编程

一. Promise基本用法 Promise 是 JavaScript 中处理异步操作的一种方式。它是一个对象&#xff0c;代表了一个异步操作的最终完成或失败的结果。 Promise 有三种状态&#xff1a; pending &#xff08;进行中&#xff09;、 fulfilled &#xff08;已成功&#xff09; 和 rej…

如何在SQL Server中恢复多个数据库?

一次性恢复多个 SQL数据库吗可以吗&#xff1f; "是的&#xff0c;可以一次性恢复多个 SQL 数据库。通常情况下&#xff0c;只要备份文件的名称与相应的数据库匹配&#xff0c;且没有附加的日期或时间信息&#xff0c;就可以通过有效的 T-SQL 脚本来完成恢复。如果你希望…