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

news2024/9/29 10:51:10

目录

一、教程简介

二、驱动原理讲解

        (一)通信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.coloradmin.cn/o/2176475.html

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

相关文章

基于webComponents的纯原生前端框架

我本人的个人开发web前端前框架xui&#xff0c;正在开发中&#xff0c;业已完成50%的核心开发工作&#xff0c;并且在开发过程中逐渐完善. 目前框架未采用任何和市面上框架模式&#xff0c;没有打包过程&#xff0c;实现真实的开箱即用。 当然在开发过程中也会发现没有打包工…

二阶低通滤波器Simulink仿真测试

1、如何将S域传递函数转为Z域传递函数 传递函数如何转化为差分方程_非差分方程转成差分方程-CSDN博客文章浏览阅读4.1k次,点赞4次,收藏50次。本文介绍了如何将传递函数转化为差分方程,主要适用于PLC和嵌入式系统。通过MATLAB的系统辨识工具箱获取传递函数,并探讨了离散化方…

通义灵码【最佳编程实践】说明

通义灵码是JetBrains或VSCode集成开发环境&#xff08;IDE&#xff09;中嵌入的一款智能开发助手工具&#xff0c;旨在通过人工智能技术简化软件开发过程&#xff0c;提升开发效率。本文将介绍在开发过程中如何深度体验多种辅助功能。其主要功能包括&#xff1a;通用大模型问答…

AdaptIoT——制造业中使用因果关系的自我标签系统

0.概述 论文地址&#xff1a;https://arxiv.org/abs/2404.05976 在许多制造应用中&#xff0c;机器学习&#xff08;ML&#xff09;已被证明可以提高生产率。针对制造业应用提出了一些软件和工业物联网&#xff08;IIoT&#xff09;系统&#xff0c;以接收这些 ML 应用。最近&…

2-仙灵之谜(安装钱包及添加网络)

2-仙灵之谜&#xff08;安装钱包及添加网络&#xff09; 前言&#xff08;该游戏仅供娱乐&#xff09;正文 前言&#xff08;该游戏仅供娱乐&#xff09; 新部署的相关链接如下 游戏访问地址&#xff1a;   http://8.130.162.58/ RPC网络&#xff1a;   网络名称 &#xf…

目前最好用的爬虫软件是那个?

作为一名数据工程师&#xff0c;三天两头要采集数据&#xff0c;用过十几种爬虫软件&#xff0c;也用过Python爬虫库&#xff0c;还是建议新手使用现成的软件比较方便。 这里推荐3款不错的自动化爬虫工具&#xff0c;八爪鱼、亮数据、Web Scraper 1. 八爪鱼爬虫 八爪鱼爬虫是一…

尚硅谷vue3+TypeScript笔记大全

源码及视频&#xff1a;通过百度网盘分享的文件&#xff1a;尚硅谷vue3 链接&#xff1a;https://pan.baidu.com/s/19zVM5Xsr1UP7tZ4D0mhVqA?pwdgmta 提取码&#xff1a;gmta 1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piec…

演示:基于WPF的DrawingVisual开发的频谱图和律动图

一、目的&#xff1a;基于WPF的DrawingVisual开发的频谱图和律动图 二、效果演示 波形图 极坐标 律动图极坐标图 律动图柱状图 Dock布局组合效果 三、环境 VS2022,Net7,Win10&#xff0c;NVIDIA RTX A2000 四、主要功能 支持设置起始频率&#xff0c;终止频率&#xff0c;中心…

我把「国产Sora」接入了「小爱」,邀你免费体验

前段时间&#xff0c;搞了个微信 AI 小助理-小爱(AI)&#xff0c;爸妈玩的不亦乐乎。 零风险&#xff01;零费用&#xff01;我把AI接入微信群&#xff0c;爸妈玩嗨了&#xff0c;附教程&#xff08;下&#xff09; 不仅可以智能问答&#xff0c;文生图的能力也接了进来&…

HTML+CSS 水滴登录页

文章目录 一、效果演示二、Code1.HTML2.CSS 三、实现思路拆分 一、效果演示 实现了一个水滴登录页的效果。页面包含一个水滴形状的登录框和两个按钮&#xff0c;登录框包括用户名、密码和登录按钮&#xff0c;按钮分别为忘记密码和注册。整个页面的设计非常有创意&#xff0c;采…

每日一练 2024.9.29(1)

目录 解题思路与代码实现 一、问题分析 二、解题策略 伪代码&#xff1a; 三、代码实现 四、代码解析 五、解题过程总结 六、运行过程示例 示例 1&#xff1a; 示例 2&#xff1a; 七、对比分析 八、改进建议 九、总结 解题思路与代码实现 这道题目要求我们模拟买…

如何解决调试dev-出++5.11不成功问题

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

【CKA】二、节点管理-设置节点不可用

2、节点管理-设置节点不可用 1. 考题内容&#xff1a; 2. 答题思路&#xff1a; 先设置节点不可用&#xff0c;然后驱逐节点上的pod 这道题就两条命令&#xff0c;直接背熟就行。 也可以查看帮助 kubectl cordon -h kubectl drain -h 参数详情&#xff1a; –delete-empty…

一个家越来越有钱,是因为女人身上有这3个好习惯!

在一个家庭中&#xff0c;女人往往扮演着举足轻重的角色。 她们不仅是家庭的支柱&#xff0c;也是家庭和谐与繁荣的重要因素。 正所谓“家和万事兴”&#xff0c;一个家庭是否能够兴旺发达&#xff0c;与家中女人的习惯和态度息息相关。 实际上&#xff0c;一个家越来越有钱…

ubuntu20.04安装CUDA与cudnn

这里写目录标题 一、NVIDIA显卡驱动安装二、安装CUDA官网找对应版本下载安装文件安装配置环境变量 三、安装cuDNN选择版本另一种下载方式 四、cuDNN与CUDA关系CUDAcuDNN的依赖关系与CPU的交互开发编程角度图示 总结 一、NVIDIA显卡驱动安装 我这里之前就装好了 使用命令 nvid…

DCDC电源设计工具(软件)(二)—— DC/DC Designer(MPS)

目录 一、简介 二、主页介绍 1、芯片选择 &#xff08;1&#xff09;在数据库中选择芯片 &#xff08;2&#xff09;通过下拉列表/具体型号选择芯片 2、编辑参数 &#xff08;1&#xff09;输入主要规格 &#xff08;2&#xff09;输入可选规格 &#xff08;3&…

基于Arduino的自弹尤克里里机器人

需要项目源码资料的可以私信我 基于Arduino的自弹尤克里里机器人 一、简介二、材料清单三、工具四、实现过程步骤1&#xff1a;实物图步骤2&#xff1a;3D打印部件步骤3&#xff1a;组装上半部分步骤4&#xff1a;组装下半部分步骤5&#xff1a;安装导轨步骤6&#xff1a;设置…

人工打电话的操作步骤指南

如果有一套外呼系统&#xff0c;那么在功能上有哪些具体如何操作 在进行人工电话沟通时 一套清晰、高效的操作流程对于实现沟通目标至关重要 以下是详细的人工打电话操作步骤 涵盖从准备到后续跟进的全过程 如果有一套外呼系统&#xff0c;那么在功能上有哪些具体如何操作 …

CST仿真分析:圆柱形谐振腔的模式分析

波导谐振器一般可以由波导两端短路形成&#xff0c;矩形和圆柱形谐振腔比较常见。矩形谐振腔模式的表示&#xff0c;是从波导的TEmn和TMmn变成了TEmnp和TMmnp&#xff0c;p是沿z方向的周期。之所以我们这里分析圆柱形&#xff0c;一是三个下角标更不容易理解&#xff08;TEnip和…

组合优化与凸优化 学习笔记5 对偶拉格朗日函数

有的时候约束条件有点难搞&#xff0c;我们可以把它放到目标函数里面。 记得之前凸函数的时候的结论吗&#xff1f;一大堆函数&#xff0c;每一段都取最大的&#xff0c;最后会得到一个凸函数。同理&#xff0c;每一段都取最小的&#xff0c;得到的是一个凹函数。就这样&#x…