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

打印 上一主题 下一主题

主题 656|帖子 656|积分 1968

目次
一、教程简介
二、驱动原理讲解
        (一)通信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 代码

  1. #include "dht11.h"
  2. /*
  3. * DHT11引脚:输入/输出模式配置函数
  4. * Mode = 0/INPUT  时 输入模式  
  5. * Mode = 1/OUTPUT 时 输出模式  
  6. */
  7. void DHT11_PIN_Mode(int Mode)
  8. {       
  9.    if(Mode)   
  10.    {
  11.                 GPIO_InitTypeDef GPIO_InitStruct = {0};                                                        // 定义GPIO_InitTypeDef结构体
  12.                 GPIO_InitStruct.Pin = DHT11_Pin;                    // 引脚选择
  13.                 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;         // 引脚模式:输出模式
  14.                 GPIO_InitStruct.Pull = GPIO_NOPULL;                 // 配置内部上拉
  15.                 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;       // 引脚速率:高速
  16.                 HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);
  17.    }
  18.    else
  19.    {
  20.             GPIO_InitTypeDef GPIO_InitStruct = {0};                                                // 定义GPIO_InitTypeDef结构体
  21.                 GPIO_InitStruct.Pin = DHT11_Pin;                                                                    // 引脚选择
  22.                 GPIO_InitStruct.Mode = GPIO_MODE_INPUT;                                                        // 引脚模式:输入模式
  23.                 GPIO_InitStruct.Pull = GPIO_NOPULL;                                                                        // 配置内部上拉
  24.                 HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);
  25.    }
  26. }  
  27. /*
  28. *DHT11起始函数
  29. *根据DHT11时序图,主机要要发送起始信号,需要将总线电平拉低(18~30ms)
  30. */
  31. void DHT11_Start(void)
  32. {
  33.         DHT11_PIN_Mode(OUTPUT);
  34.         DHT11_IO_SET;                                    // 先让总线处于高电平状态
  35.         HAL_Delay(1);
  36.         DHT11_IO_RESET;                                  // 拉低总线20ms,表示主机发送起始信号
  37.         HAL_Delay(20);
  38.         DHT11_IO_SET;                                    // 将总线拉高等待传感器响应
  39.         DHT11_Delay_us(30);
  40. }
  41. /**
  42.   * DHT11响应检测函数
  43.   * 返回1:未检测到DHT11的存在
  44.   * 返回0:存在出现由高到低的变化即可
  45.   */
  46. uint8_t DHT11_Check(void)
  47. {
  48.         uint8_t retry = 0;
  49.         DHT11_PIN_Mode(INPUT);              //将引脚切换为输入模式
  50.         while(!DHT11_IO_Read && retry<100)  //单片机发送起始信号后,DHT11会将总线拉低83微妙
  51.         {
  52.                 retry++;
  53.                 DHT11_Delay_us(1);
  54.         }
  55.         if(retry >= 100)return 1;
  56.         else retry = 0;
  57.        
  58.         while(DHT11_IO_Read && retry<100)  //DHT11拉低后会再次拉高87微妙
  59.         {
  60.                 retry++;
  61.                 DHT11_Delay_us(1);
  62.         }
  63.         if(retry >= 100) return 1;
  64.         return 0;
  65. }
  66. /**
  67.   * 从DHT11读取一个位
  68.   * 返回值:1/0
  69.   */
  70. uint8_t DHT11_Read_Bit(void)
  71. {
  72.         DHT11_PIN_Mode(INPUT);
  73.         while(!DHT11_IO_Read);
  74.         DHT11_Delay_us(40);
  75.         if(DHT11_IO_Read)
  76.         {
  77.                 while(DHT11_IO_Read);
  78.                 return 1;
  79.         }
  80.         else
  81.         {
  82.                 return 0;
  83.         }
  84. }
  85. /**
  86.   *  读取一个字节数据 1byte / 8bit
  87.   *  返回值是一个字节的数据
  88.   */
  89. uint8_t DHT11_Read_Byte(void)
  90. {
  91.     uint8_t i,buf = 0;                             //  暂时存储数据
  92.    
  93.     for(i=0; i<8 ;i++)
  94.     {
  95.         buf <<= 1;                                 
  96.         if(DHT11_Read_Bit())                        //  1byte -> 8bit
  97.         {
  98.             buf |= 1;                              //  0000 0001
  99.         }
  100.     }
  101.     return buf;
  102. }
  103. /**
  104.   * 读取温湿度传感器数据 5byte / 40bit
  105.   * 使用方法:创建两个float变量,将变量地址传入函数
  106.   * 注意:两次使用该函数的间隔需要大于2秒,否则会导致数据测量不准确
  107.   */
  108. uint8_t data[5] = {0};
  109. uint8_t DHT11_READ_DATA(float *temp, float *humi)
  110. {
  111.    uint8_t i;
  112.    DHT11_Start();                                 //  主机发送启动信号
  113.    
  114.    if(!DHT11_Check())                             //  如果DHT11应答     
  115.    {  
  116.       for(i=0; i<5; i++)
  117.       {                        
  118.          data[i] = DHT11_Read_Byte();             //  读取 5byte
  119.       }
  120.       if(data[0] + data[1] + data[2] + data[3] == data[4])
  121.       {
  122.                                  *humi = data[0] + 0.1*data[1];
  123.                                  *temp = data[2] + 0.1*data[3];
  124.          return 1;                                //  数据校验通过
  125.       }
  126.       else return 0;                              //  数据校验失败
  127.    }
  128.    else return 2;                                 //  如果DHT11不应答
  129. }
  130. /**
  131.   * 微妙延时函数
  132.   * 全系列通用,只需要将宏定义CPU_FREQUENCY_MHZ根据时钟主频修改即可。
  133.   * 系统滴答定时器是HAL库初始化的,且必须有HAL库初始化。
  134.   */
  135. #define CPU_FREQUENCY_MHZ   (int)(HAL_RCC_GetHCLKFreq()/1000000)                // 自动获取STM32时钟主频
  136.        
  137. void DHT11_Delay_us(__IO uint32_t delay)  
  138. {
  139.     int last, curr, val;
  140.     int temp;
  141.     while (delay != 0)
  142.     {
  143.         temp = delay > 900 ? 900 : delay;
  144.         last = SysTick->VAL;
  145.         curr = last - CPU_FREQUENCY_MHZ * temp;
  146.         if (curr >= 0)
  147.         {
  148.             do
  149.             {
  150.                 val = SysTick->VAL;
  151.             }
  152.             while ((val < last) && (val >= curr));
  153.         }
  154.         else
  155.         {
  156.             curr += CPU_FREQUENCY_MHZ * 1000;
  157.             do
  158.             {
  159.                 val = SysTick->VAL;
  160.             }
  161.             while ((val <= last) || (val > curr));
  162.         }
  163.         delay -= temp;
  164.     }
  165. }
复制代码
(二)dht11.h 代码

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

       注意: 在main.c中需要包含dht11.h、stdio.h两个头文件,声明两个浮点变量和一个串口发送缓冲数组。利用的时间不需要初始化,直接放while里面循环读取就可,但必须要加上延时。        
  1. /* USER CODE END Header */
  2. /* Includes ------------------------------------------------------------------*/
  3. #include "main.h"
  4. #include "usart.h"
  5. #include "gpio.h"
  6. /* Private includes ----------------------------------------------------------*/
  7. /* USER CODE BEGIN Includes */
  8. #include "dht11.h"
  9. #include "stdio.h"
  10. /* USER CODE END Includes */
  11. /* Private typedef -----------------------------------------------------------*/
  12. /* USER CODE BEGIN PTD */
  13. float Humi,Temp;
  14. char  DHT11_TX[40];
  15. /* USER CODE END PTD */
  16. /* Private define ------------------------------------------------------------*/
  17. /* USER CODE BEGIN PD */
  18. /* USER CODE END PD */
  19. /* Private macro -------------------------------------------------------------*/
  20. /* USER CODE BEGIN PM */
  21. /* USER CODE END PM */
  22. /* Private variables ---------------------------------------------------------*/
  23. /* USER CODE BEGIN PV */
  24. /* USER CODE END PV */
  25. /* Private function prototypes -----------------------------------------------*/
  26. void SystemClock_Config(void);
  27. /* USER CODE BEGIN PFP */
  28. /* USER CODE END PFP */
  29. /* Private user code ---------------------------------------------------------*/
  30. /* USER CODE BEGIN 0 */
  31. /* USER CODE END 0 */
  32. /**
  33.   * @brief  The application entry point.
  34.   * @retval int
  35.   */
  36. int main(void)
  37. {
  38.   /* USER CODE BEGIN 1 */
  39.   /* USER CODE END 1 */
  40.   /* MCU Configuration--------------------------------------------------------*/
  41.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  42.   HAL_Init();
  43.   /* USER CODE BEGIN Init */
  44.   /* USER CODE END Init */
  45.   /* Configure the system clock */
  46.   SystemClock_Config();
  47.   /* USER CODE BEGIN SysInit */
  48.   /* USER CODE END SysInit */
  49.   /* Initialize all configured peripherals */
  50.   MX_GPIO_Init();
  51.   MX_USART1_UART_Init();
  52.   /* USER CODE BEGIN 2 */
  53.   /* USER CODE END 2 */
  54.   /* Infinite loop */
  55.   /* USER CODE BEGIN WHILE */
  56.   while (1)
  57.   {
  58.                 HAL_Delay(2000);
  59.                 DHT11_READ_DATA(&Temp,&Humi);
  60.                 sprintf(DHT11_TX,"温度:%0.1f 度        湿度:%0.1f %%\r\n",Temp,Humi);
  61.                 HAL_UART_Transmit(&huart1,(uint8_t*)DHT11_TX,40,200);
  62.     /* USER CODE END WHILE */
  63.     /* USER CODE BEGIN 3 */
  64.   }
  65.   /* USER CODE END 3 */
  66. }
复制代码
五、结果展示




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

半亩花草

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表