STM32-HAL库驱动DHT11温湿度传感器 --2024.9.28

目录

一、教程简介

二、驱动原理讲解

        (一)通信4步骤

        (二)传感器数据解析

三、CubeMX生成底层代码

        (一)基础配置

        (二)配置DHT11的驱动引脚

        (三)配置串口

四、Keil中编写代码

        (一)dht11.c 代码

        (二)dht11.h 代码

        (三)main.c 中调用

五、效果展示


一、教程简介

        DHT11是单片机开发常用的一个温湿度传感器,采用单总线通信,优点是单片机和传感器的连接只需要一根数据线,缺点则是对通信时序的要求较高。

        本教程用通俗易懂的语言和详细的操作过程截图,为开发者清除DHT11这只拦路虎,本教程还提供可以快速使用DHT11的驱动代码,只要跟着本教程操作,都可以正确读取到温湿度信息。

二、驱动原理讲解

        DHT11采用的是单总线的通信方式,系统中数据的交换、控制均由单总线完成。(注意:DHT11的数据引脚需要一个4.7K的上拉电阻,若使用的传感器是不带PCB的那种,请自己外加上拉电阻)。

   (一)通信4步骤

        步骤一:

        DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平;此时DHT11的DATA引脚处于输入状态,时刻检测外部信号。

        步骤二:

        微处理器的I/0设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),然后微处理器的I/0设置为输入状态,由于上拉电阻,微处理器的I/0即DHT11的DATA数据线也随之变高,等待DHT11作出回答信号。发送信号如下图所示:

        步骤三:

        DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知外设准备接收数据,微处理器的I/0此时处于输入状态,检测到I/0有低电平(DHT11回应信号)后,等待87微秒的高电平后的数据接收,发送信号如图5所示:

         步骤四:

         由DHT11的DATA引脚输出40位数据,微处理器根据I/0电平的变化接收40位数据,位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。位数据“0”、“1”格式信号如图6所示:

        结束信号     

        DHT11的DATA引脚输出40位数据后,继续输出低电平54微秒后转为输入状态,由于上拉电阻随之变为高电平。但DHT11内部重测环境温湿度数据,并记录数据,等待外部信号的到来。

   (二)传感器数据解析

        传感器发送的40位数据分为5个部分,分别是:湿度高8位、湿度低8位、温度高8位、温度低8位、校验位。下面举例分析:

        示例一:接收到的40位数据为

0011 01010000 00000001 10000000 01000101 0001
湿度高8位湿度低8位温度高8位温度低8位校验位

        计算:                                                                                                                                        

        00110101 + 00000000 + 00011000 + 00000100 = 01010001                                                   

        校验正确,接收数据正确。                                                                                                        

        湿度:00110101(整数) = 0x35 = 53%   ,湿度小数为0。                                                         

                   所以湿度为: 53%                                                                                                          

        温度:00011000(整数) = 0x18 = 24 度  ,00000100(小数) = 0x04 = 0.4度                              

                   所以温度为:24 + 0.4 = 24.4 摄氏度                                                                              

三、CubeMX生成底层代码

(一)基础配置

        1、配置Debug

        2、配置外部高速晶振

        3、 配置时钟

(二)配置DHT11的驱动引脚

        将任意一个引脚配置为:输出模式、内部上拉、高速模式、重命名为DHT11

(三)配置串口

(四)生成工程文件

四、Keil中编写代码

(一)dht11.c 代码

#include "dht11.h"
/** DHT11引脚:输入/输出模式配置函数 * Mode = 0/INPUT  时 输入模式  * Mode = 1/OUTPUT 时 输出模式  */
void DHT11_PIN_Mode(int Mode)
{	if(Mode)   {GPIO_InitTypeDef GPIO_InitStruct = {0};							// 定义GPIO_InitTypeDef结构体 GPIO_InitStruct.Pin = DHT11_Pin;                    // 引脚选择GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;         // 引脚模式:输出模式GPIO_InitStruct.Pull = GPIO_NOPULL;                 // 配置内部上拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;       // 引脚速率:高速HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);}else{GPIO_InitTypeDef GPIO_InitStruct = {0};						// 定义GPIO_InitTypeDef结构体 GPIO_InitStruct.Pin = DHT11_Pin;				    				// 引脚选择GPIO_InitStruct.Mode = GPIO_MODE_INPUT;							// 引脚模式:输入模式GPIO_InitStruct.Pull = GPIO_NOPULL;									// 配置内部上拉HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);}
}  /**DHT11起始函数*根据DHT11时序图,主机要要发送起始信号,需要将总线电平拉低(18~30ms)*/
void DHT11_Start(void)
{DHT11_PIN_Mode(OUTPUT);DHT11_IO_SET;    				// 先让总线处于高电平状态HAL_Delay(1);DHT11_IO_RESET;  				// 拉低总线20ms,表示主机发送起始信号HAL_Delay(20);DHT11_IO_SET;    				// 将总线拉高等待传感器响应DHT11_Delay_us(30);
}/*** DHT11响应检测函数* 返回1:未检测到DHT11的存在* 返回0:存在出现由高到低的变化即可*/
uint8_t DHT11_Check(void)
{uint8_t retry = 0;DHT11_PIN_Mode(INPUT);              //将引脚切换为输入模式while(!DHT11_IO_Read && retry<100)  //单片机发送起始信号后,DHT11会将总线拉低83微妙{retry++;DHT11_Delay_us(1);}if(retry >= 100)return 1;else retry = 0;while(DHT11_IO_Read && retry<100)  //DHT11拉低后会再次拉高87微妙{retry++;DHT11_Delay_us(1);}if(retry >= 100) return 1;return 0;
}/*** 从DHT11读取一个位* 返回值:1/0*/
uint8_t DHT11_Read_Bit(void)
{DHT11_PIN_Mode(INPUT);while(!DHT11_IO_Read);DHT11_Delay_us(40);if(DHT11_IO_Read){while(DHT11_IO_Read);return 1;}else{return 0;}
}/***  读取一个字节数据 1byte / 8bit*  返回值是一个字节的数据*/
uint8_t DHT11_Read_Byte(void)
{uint8_t i,buf = 0;                             //  暂时存储数据for(i=0; i<8 ;i++){buf <<= 1;                                 if(DHT11_Read_Bit())                        //  1byte -> 8bit{buf |= 1;                              //  0000 0001}}return buf;
}/*** 读取温湿度传感器数据 5byte / 40bit* 使用方法:创建两个float变量,将变量地址传入函数* 注意:两次使用该函数的间隔需要大于2秒,否则会导致数据测量不准确*/
uint8_t data[5] = {0};uint8_t DHT11_READ_DATA(float *temp, float *humi)
{uint8_t i;DHT11_Start();                                 //  主机发送启动信号if(!DHT11_Check())                             //  如果DHT11应答     {  for(i=0; i<5; i++){                        data[i] = DHT11_Read_Byte();             //  读取 5byte}if(data[0] + data[1] + data[2] + data[3] == data[4]){*humi = data[0] + 0.1*data[1];*temp = data[2] + 0.1*data[3];return 1;                                //  数据校验通过}else return 0;                              //  数据校验失败}else return 2;                                 //  如果DHT11不应答
}/*** 微妙延时函数* 全系列通用,只需要将宏定义CPU_FREQUENCY_MHZ根据时钟主频修改即可。* 系统滴答定时器是HAL库初始化的,且必须有HAL库初始化。*/
#define CPU_FREQUENCY_MHZ   (int)(HAL_RCC_GetHCLKFreq()/1000000)		// 自动获取STM32时钟主频void DHT11_Delay_us(__IO uint32_t delay)  
{int last, curr, val;int temp;while (delay != 0){temp = delay > 900 ? 900 : delay;last = SysTick->VAL;curr = last - CPU_FREQUENCY_MHZ * temp;if (curr >= 0){do{val = SysTick->VAL;}while ((val < last) && (val >= curr));}else{curr += CPU_FREQUENCY_MHZ * 1000;do{val = SysTick->VAL;}while ((val <= last) || (val > curr));}delay -= temp;}
}

(二)dht11.h 代码

#include "main.h"#ifndef __DHT11_H_
#define __DHT11_H_
/**** 如果未用CubeMX配置引脚,可以将下面代码的注释取消,并替换后面的GPIOB以及GPIO_PIN_1 * 例如: 使用了PA5引脚,则应将 GPIOB 替换成 GPIOA ,将 GPIO_PIN_1 替换成 GPIO_PIN_5*
***/// #define DHT11_GPIO_Port GPIOB
// #define DHT11_Pin       GPIO_PIN_1#define DHT11_IO_Read   HAL_GPIO_ReadPin(DHT11_GPIO_Port,DHT11_Pin)                   //读DHT11引脚电平
#define DHT11_IO_SET    HAL_GPIO_WritePin(DHT11_GPIO_Port,DHT11_Pin,GPIO_PIN_SET)     //DHT11引脚置高电平
#define DHT11_IO_RESET  HAL_GPIO_WritePin(DHT11_GPIO_Port,DHT11_Pin,GPIO_PIN_RESET)   //DHT11引脚置低电平#define INPUT 0   //引脚输入模式
#define OUTPUT 1  //引脚输出模式void DHT11_Delay_us(__IO uint32_t delay);           // 微妙级延时函数
void DHT11_PIN_Mode(int Mode);  										// 引脚模式配置函数
void DHT11_Start(void);         										// 起始信号发送函数
uint8_t DHT11_Check(void);      										// DHT11应答检测函数
uint8_t DHT11_Read_Bit(void);   										// 读取一个数据位(bit),8 bit = 1 byte
uint8_t DHT11_Read_Byte(void);  										// 读取一个字节的数据
uint8_t DHT11_READ_DATA(float *temp, float *humi);  // 温湿度数据读取函数#endif

 (三)main.c 中调用

       注意: 在main.c中需要包含dht11.h、stdio.h两个头文件,声明两个浮点变量和一个串口发送缓冲数组。使用的时候不需要初始化,直接放while里面循环读取就可,但必须要加上延时。        

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "dht11.h"
#include "stdio.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
float Humi,Temp;
char  DHT11_TX[40];
/* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
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_USART1_UART_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_Delay(2000);DHT11_READ_DATA(&Temp,&Humi);sprintf(DHT11_TX,"温度:%0.1f 度	湿度:%0.1f %%\r\n",Temp,Humi);HAL_UART_Transmit(&huart1,(uint8_t*)DHT11_TX,40,200);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

五、效果展示

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

@Transactional声明式事务回调编程

文章目录 1. 理论阐述2. 代码实现2.1. 问题代码2.2. 改进方案 本文参考&#xff1a; 事务回调编程 大事务问题 1. 理论阐述 最近在学习数据库事务的过程中&#xff0c;了解到了大事务的危害&#xff1a; 并发情况下&#xff0c;数据库连接资源容易耗尽锁定数据较多&#xff0…

用java做一个简易版球球大作战

该界面模拟了一个简单的“吃球”游戏&#xff0c;一开始多个球在屏幕上移动&#xff0c;并检查每个大球是否可以吃掉其他小球&#xff0c;且更新状态&#xff0c;删除已经被吃掉的小球。通过图形绘制和逻辑处理实现了游戏的基本功能。 主界面World.java package gzeu.test.da…

边缘自适应粒子滤波(Edge-Adaptive Particle Filter)的MATLAB函数示例,以及相应的讲解

目录 讲解 初始化 预测步骤 观测模拟 权重更新 重采样 状态估计 总结 下面是一个简单的边缘自适应粒子滤波&#xff08;&#xff09;的函数示例&#xff0c;以及相应的讲解。 程序源代码&#xff1a; function X_est edgeAdaptiveParticleFilter(numParticles, numS…

RabbitMQ(学习前言)

目录 学习MQ之前有必要先去温故下微服务知识体系&#xff0c;以加深本章节的理解 一、微服务间的通讯方式 1. 基本介绍 2. 同步通讯 2.1. 什么是同步通讯 2.2. 同步通讯存在的问题 问题一&#xff1a;耦合度高 问题二&#xff1a;性能和吞吐能力下降 问题三&#xff1a…

在线Xpath匹配定位测试工具

具体请前往&#xff1a;在线Xpath-匹配-定位-调试/测试工具

一文看懂计算机中的大小端(Endianess)

文章目录 前言一、什么是大小端二、如何判断大小端三、大小端的转换3.1 使用标准库函数3.2 手动实现大小端转换 前言 本文主要探讨计算机中大小端的相关概念以及如何进行大小端的判断和转换等。 一、什么是大小端 大小端&#xff08;Endianess&#xff09;是指计算机系统在存…

【AI学习笔记】基于Unity+DeepSeek开发的一些BUG记录解决方案

【AI学习笔记】基于UnityDeepSeek开发的一些BUG记录&解决方案 背景前摇&#xff1a;&#xff08;省流可不看&#xff09; Unity是大学学的&#xff0c;AI是研究生学的&#xff0c;DeepSeek是第一份实习偷师的&#xff0c;三合一的梦是最近开始做的&#xff0c;BUG是今天遇…

【数据结构】什么是哈希表(散列表)?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;哈希表的概念 &#x1f4cc;哈希函数的构造方法 &#x1f38f;直接定址法 &#x1f38f;除留余数法 &#x1f38f;平方取中法 &#x1f38f;折叠法 &#x…

Bolt.new:终极自动化编程工具

兄弟们&#xff0c;终极写代码工具来了—— Bolt.new&#xff01;全方位的编程支持&#xff1a; StackBlitz 推出了 Bolt․new&#xff0c;这是一款结合了 AI 与 WebContainers 技术的强大开发平台&#xff0c;允许用户快速搭建并开发各种类型的全栈应用。 它的主要特点是无需…

前端reactvue3——实现滚动到底加载数据

文章目录 ⭐前言⭐react 实现滚动加载⭐vue3 实现滚动加载⭐总结⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享 前端react&vue3——实现滚动加载&#xff08;到底部加载&#xff09; scrollTop 属性 一个双精度浮点值&#xff0c;表示元素当前从原点垂直…

安全运营中心 (SOC) 团队对其安全工具感到失望

Vectra AI 表示&#xff0c;安全运营中心 (SOC) 从业人员认为&#xff0c;由于太多孤立的工具和缺乏准确的攻击信号&#xff0c;他们在检测和确定真实威胁的优先级方面正在失败。 人们对供应商的不信任感日益加深&#xff0c;认为供应商的工具在发现真正的攻击方面起的阻碍作用…

ctfshow-web入门(信息收集,持续更新中。。)

写在之前:近期打了个比赛,备受打击,入手了vip账号进修,加油! 文章目录 ctfshow-web1查看源代码ctfshow-web2burp抓包ctfshow-web3burp抓包ctfshow-web4访问robots.txtctfshow-web5dirscarch扫描PHPS文件泄露ctfshow-web6dirscarch扫描ctfshow-web7dirscarch扫描ctfshow-w…

【STM32开发之寄存器版】(六)-通用定时器中断

一、前言 STM32定时器分类 STM32103ZET6具备8个定时器TIMx(x 1,2,...,8)。其中&#xff0c;TIM1和TIM8为高级定时器&#xff0c;TIM2-TIM6为通用定时器&#xff0c;TIM6和TIM7为基本定时器&#xff0c;本文将以TIM3通用定时器为例&#xff0c;分析STM32定时器工作的底层寄存器…

You must konw JS!!(超详细的javascript套餐,适合计算机专业有基础的,包含常见前端开发面试题)

1.起源 JavaScript 起源于 1995 年&#xff0c;当时它主要是为了满足网页交互的需求而被创建。它最初的设计目的是为了让网页开发者能够在网页中添加一些简单的交互效果和动态内容。在那个时期&#xff0c;网页大多是静态的&#xff0c;而 JavaScript 的出现为网页带来了新的活…

jmeter学习(7)beanshell

beanshell preprocessor 发送请求前执行 beanshell postprocessor 发送请求前执行 获取请求相关信息 String body sampler.getArguments().getArgument(0).getValue(); String url sampler.getPath(); 获取响应报文 String responseprev.getResponseDataAsString(); 获…

CMake 教程跟做与翻译

目录 STEP 1: 入门与理解 cmake_minimum_required设置CMake版本的最小值 project声明工程属性 add_executable添加可执行文件 使用CMake构建工程 根据自己的构建工具自行构建 Reference STEP 1: 入门与理解 我们起手的&#xff0c;最基本的 CMake 项目是从单个源代码文件…

【Blender Python】1.概述和基础使用

概述 众所周知&#xff0c;Blender是一款开源免费的3D建模软件&#xff08;当然不限于3D建模&#xff09;。在Blender中&#xff0c;可以使用其内置的Python解释器执行Python代码&#xff0c;用于程序化的生成网格以及其他内容。你可以基于此创建Blender插件。 这个系列就是快…

Electron桌面应用打包现有的vue项目

1 环境准备 Node&#xff1a;v16.20.2&#xff08;本地vue项目nodejs版本&#xff09;Electron&#xff1a;22.3.7vue&#xff1a;2 版本管理 2 Vue项目准备 更新相关依赖npm install --registry https://registry.npmmirror.com/npm run dev 3、引入Electorn 安装指定版…

算法剖析:双指针

文章目录 双指针算法一、 移动零1. 题目2. 算法思想3. 代码实现 二、 复写零1. 题目2. 算法思想3. 代码实现 三、 快乐数1. 题目2. 算法思想3. 代码实现 四、 盛水最多的容器1. 题目2. 算法思想3. 代码实现 五、有效三角形的个数1. 题目2. 算法思想3. 代码实现 六、 和为 s 的两…

UART驱动学习三(TTY驱动部分源码解析)

目录 全局框架图一、tty_io.c 分析1. 关键数据结构和定义2. 文件操作结构体3. 初始化和注册4. 读写操作5. 挂起和恢复6. 信号处理7. 设备类8. 控制台通知9. 辅助函数10. 代码功能11. 带有注释的部分tty_io.c源码 二、tty_ldisc.c 分析1. 关键数据结构和定义2. 行规程操作函数3.…