锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

【正点原子MP157连载】第二十七章 DHT11数字温湿度传感器实验-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发...

时间:2022-10-05 00:00:00 48v电流传感器

1)实验平台:正点原子STM32MP157开发板
2)购买链接:https://item.taobao.com/item.htm?&id=629270721801
3)全套实验源码 手册 视频下载地址:http://www.openedv.com/thread-318813-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子STM32MP157技术交流群:691905614
在这里插入图片描述

第二十七章 DHT数字温湿度传感器实验

本章将介绍数字温湿度传感器DHT11的使用,以及前一章DS18B与20温度传感器相比,该传感器不仅可以测量温度,还可以测量湿度。我们将学习如何获得它DHT11传感器的温湿度数据,并把数据通过串口打印出来。
本章分为以下几个部分:
27.1、DHT11简介;
27.二、硬件设计;
27.三、软件设计;
27.四、编译与测试;
27.1 DHT11简介
27.1.1 DHT11简介
DHT11是温湿度一体化的数字传感器。该传感器包括一个电阻测湿元件和一个NTC与高性能8位单片机连接的测温元件。本地湿度和温度可通过单片机等微处理器的简单电路连接实时采集。DHT简单的单总线可以在11和单片机之间通信,只需要一个I/O口。传感器内部湿度和温度数据共40个 bit数据一次性传输到单片机,数据通过验证和验证,有效保证了数据传输的准确性。DHT11功耗很低,5V工作平均最大电流0.5mA。
DHT技术参数如下:
?工作电压范围:3.3V ~ 5.5V
?工作电流:平均0.5mA
?输出:单总线数字信号
?测量范围:湿度2090%RH,温度050℃
?精度:湿度±5%,温度±2℃
?分辨率:湿度1%,温度1%℃
DHT管脚排列如图431所示.1.1所示:

图27.1.1.1 DHT11管脚排列图
DHT11广泛应用于暖通空调、除湿器、农业、冷链储存、测试和测试设备
温湿度检测控制领域,如汽车、自动控制、数据记录器、气象站、家电、湿度调节器、医疗等。
27.1.2 DHT工作时序简介

  1. 单总线结构
    DHT11装置采用单总线通信,只有一条数据线,系统中的数据交换和控制由单总线完成。单总线连接约4条.7kΩ上拉电阻,当总线闲置时,总线状态为高电平。关于我们前面的单总线DS18B第20章已经解释过了。编写后面的程序时,要注意总线占用的配置IO口为泄漏输出模式。
  2. 数据结构
    单总线上的设备属于主从结构。只有当主机呼叫机器时,机器才能响应。因此,主机访问设备必须严格遵循单总线序列。如果序列混乱,设备将不响应主机。DHT11与DS18B20类似,都是单总线访问,但是DHT访问,相对DS18B20要简单得多。先来看看。DHT11数据结构。
    单总线一次传输5 byte(40 bit)高位先发送数据,数据分为小数部分和整数部分,DHT11数据格式为:
    8bit湿度数据 8bit湿度小数据 8bit温度整数数据 8bit温度小数据 8bit校验位。
    其中,验证和数据是前四个字节。传感器数据输出未编码的二进制数据,数据(湿度、温度、整数、小数)应分开处理。
    (1)温度为正数
    例如,一次从DHT如下图所示如下图所示:
    byte4 byte3 byte2 byte1 byte0
    00110101 00000000 00011000 00000100 01010001
    湿度高8位 湿度低8位 温度高8位 温度低8位 校验位
    整数 小数 整数 小数 校验位
    按上述数据计算:
    1)检查数据接收情况
    00110101 00000000 00011000 00000100=01010001
    计算结果等于验证位,接收数据正确。如果计算值与验证位不一致,则接收数据不正确,放弃并重新接收数据。
    2)计算湿度和温度的值
    湿度:
    00110101(整数)=35H=53%RH
    00000000(小数)=00H=0.0%RH
    最后湿度=>53%RH 0.0%RH=53.0%RH
    温度:
    00011000(整数)=18H=24℃
    00000100 (小数)=04H=0.4℃
    最后温度=>24℃ 0.4℃=24.4℃
    (2)温度为负数
    若温度低于0℃当温度数据低8位的最高位置为1时,该位置可视为0。如果温度为负,则验证位置和湿度计算与上述情况相同。以下是温度计算,如-10.1℃表示为00001010 计算方法为:
    0000 1010(整数)=0AH=10℃
    00000001(小数)=01H=0.1℃
    最后温度=>-(10℃ 0.1℃)=-10.1℃
  3. DHT11时序
    DHT11上电后(DHT11上电后要等1S以越过不稳定状态,在此期间不能发送任何指令),等待1s之后,可以测试环境温湿度数据,DHT11的DATA数据线由上拉电阻拉高,保持高电平DHT11的DATA引脚处于输入状态,始终检测外部信号。让我们看看。DHT11的时序:
    1)复位信号和响应信号时序
    首先,主机发送开始信号(也称为复位信号),即降低数据线并保持它t1(至少18ms,最大不超过30ms)时间,然后主机拉高数据线t2(2040us)然后主机读取时间DHT正常情况下,11的响应,DHT11将降低数据线并保持数据线t3(4050us)时间作为响应信号,然后DHT11拉高数据线,保持t4(40~50us)时间后,DHT11开始输出数据。

图27.1.2.1 开始信号和响应信号
2)DHT11输出数字‘0’时序
DHT11每发送的1 bit 数据从低电平开始,低电平的延迟时间约为1214us,然后DHT11拉高总线,如果总线拉高2628us,表示发送0,然后DHT再次将总线拉低121~14us,为下一次发送数据做准备。(注意,在此时序图中,按位发送。

图27.1.2.2 DHT11输出数字0
3)DHT11输出数字1时序
如果DHT11拉低总线1214us然后将总线拉高116118us,表示发送数字1,然后DHT再次将总线拉低121~14us,为下一次发送数据做准备。(注意,此时序图中,为按位发送。)

图27.1.2.3 DHT11输出数字‘1’
27.2 硬件设计

  1. 例程功能
    把DHT11传感器插入预留接口,测试当前环境温度和湿度,并通过串口打印温度和湿度。在实验中观察LED0闪烁提示程序正在运行中。开发板底板预留接口如下:

图27.2.1 开发板硬件示意图
上图中开发板预留接口的四个引脚从左到右依次VCC、DQ、GND、GND,所以DHT这样插入开发板(注意不要插错!

图27.2.2硬件连接示意图
2. 硬件资源
1)LED灯:LED0
2)UART4
3)DS18B20(接在PF2上)

表27.21硬件资源
3. 原理图
如下图,DS18B20接在PF2上,我们通过该IO口模拟单总线的时序来控制DS18B20:

图27.2.3原理图部分
27.3 软件设计
本实验配置好的实验工程已经放到了开发板光盘中,路径为:开发板光盘A-基础资料\1、程序源码\11、M4 CubeIDE裸机驱动例程\CubeIDE_project\ 20 DHT11。
27.3.1 新建和配置工程
新建工程DHT11,然后配置LED0和UART4,再配置PF2为开漏输出、上拉、高速模式:

图26.3.1.1 配置GPIO
本节实验会用到微秒延时函数,需要将第二十三章实验的delay.h和delay.c文件。将上一章节实验的BSP文件夹拷贝到M4工程的Core/Src下,然后在BSP文件夹下新建dht11.c文件,在BSP/Include下新建dht11.h文件,最后的部分工程如下:

图26.3.2 工程部分目录
27.3.2 添加用户代码
关于LED0和UART4相关的代码请参考前面实验章节部分,DHT11驱动代码我们把它放在dht11.c和dht11.h文件中。首先我们先看一下dht11.c头文件里面的内容。

1. dht11.h文件代码
	dht11.h文件代码如下:
#ifndef __DHT11_H
#define __DHT11_H 
#include"gpio.h"
/* DHT11 引脚 定义 */
#define DHT11_DQ_GPIO_PORT GPIOF
#define DHT11_DQ_GPIO_PIN GPIO_PIN_2
/* PF口时钟使能 */
#define DHT11_DQ_GPIO_CLK_ENABLE() do{ 
           __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0) 

/* IO操作函数 */
#define DHT11_DQ_OUT(x) do{ 
           x ? \ HAL_GPIO_WritePin(DHT11_DQ_GPIO_PORT, DHT11_DQ_GPIO_PIN, GPIO_PIN_SET) : \ HAL_GPIO_WritePin(DHT11_DQ_GPIO_PORT, DHT11_DQ_GPIO_PIN, GPIO_PIN_RESET); \ }while(0) /* 数据端口输出 */
/* 数据端口输入 */
#define DHT11_DQ_IN HAL_GPIO_ReadPin(DHT11_DQ_GPIO_PORT, DHT11_DQ_GPIO_PIN) 

uint8_t dht11_init(void);               /* 初始化DHT11 */
uint8_t dht11_check(void);              /* 检测是否存在DHT11 */
uint8_t dht11_read_data(uint8_t *temp,uint8_t *humi);   /* 读取温湿度 */

#endif

以上主要是对DHT11的相关引脚、时钟使能和IO操作函数进行宏定义,方便程序中调用。
2. dht11.c文件代码
根据前面对DHT11的时序分析,我们按照时序部分进行程序设计,首先是复位DHT11函数,如下:
(1)复位DHT11

/** * @brief 复位DHT11 * @param 无 * @retval 无 */
static void dht11_reset(void)
{ 
        
    DHT11_DQ_OUT(0);    	/* 拉低DQ */
    delay_ms(20);       	/* 拉低至少18ms */
    DHT11_DQ_OUT(1);    	/* DQ=1 */
    delay_us(30);       	/* 主机拉高20~40us */
}2)等待DHT11应答
/** * @brief 等待DHT11的回应 * @param 无 * @retval 0, DHT11正常 * 1, DHT11异常/不存在 */
uint8_t dht11_check(void)
{ 
        
    uint8_t retry = 0;
    uint8_t rval = 0;
    while (DHT11_DQ_IN && retry < 100)      /* DHT11会拉低40~80us */
    { 
        
        retry++;
        delay_us(1);
    }
    if (retry >= 100)                       	/* 超时,DHT11异常 */
    { 
        
        rval = 1;
    }
    else
    { 
        
        retry = 0;
        while (!DHT11_DQ_IN && retry < 100) /* DHT11拉低后会再次拉高40~80us */
        { 
        
            retry++;
            delay_us(1);
        }
        if (retry >= 100) rval = 1;        	/* 超时,DHT11异常 */
    }  
    return rval;
}
应答信号也是按照前面的时序图进行编写的,首先DHT11将总线拉低,所以程序先等待总线变为低电平,这里在测试引脚电平的时候,设置最大的检测时间是100us,如果超过100us内电平没有变化,则认为DHT11异常。如果DHT11拉低总线后,再释放总线,则总线为高电平,所以,在测试总线拉低以后,再检测总线是否被拉高。

(3)从DHT11读取一个位
和DS18B20不一样,DHT11不需要写的过程,直接可以读取温湿度数据:

1   /** 2 * @brief 从DHT11读取一个位 3 * @param 无 4 * @retval 读取到的位值: 0 / 1 5 */
6   uint8_t dht11_read_bit(void)
7   { 
        
8       uint8_t retry = 0;
9       while (DHT11_DQ_IN && retry < 100)  /* 等待变为低电平 */
10      { 
        
11          retry++;
12          delay_us(1);
13      }
14      retry = 0;
15      while (!DHT11_DQ_IN && retry < 100) /* 等待变高电平 */
16      { 
        
17          retry++;
18          delay_us(1);
19      }
20      delay_us(40);                       	/* 等待40us */
21      if (DHT11_DQ_IN)                    	/* 根据引脚状态返回 bit */
22      { 
        
23          return 1;
24      }
25      else 
26      { 
        
27          return 0;
28      }
29  }
DHT11输出数字0或者1都是先以低电平开始的,所以第9~13行在等待DHT11变为低电平,同样,测试的最大时间为100us。DHT11通过拉高总线发送数字0或1,第15~19行在等待总线拉高,总线拉高后,延时40us后检查DHT11的IO的状态,如果此时引脚为高电平,则认为从DHT11读取到1,反之则从DHT11读取到0。

(4)从DHT11读取一个字节
读取一个字节需要对读取一个位循环8次,如下:

/** * @brief 从DHT11读取一个字节 * @param 无 * @retval 读到的数据 */
static uint8_t dht11_read_byte(void)
{ 
        
    uint8_t i, data = 0;

    for (i = 0; i < 8; i++)          /* 循环读取8位数据 */
    { 
        
        data <<= 1;                 	/* 高位数据先输出, 先左移一位 */
        data |= dht11_read_bit();   	/* 读取1bit数据 */
    }
    return data;
}

(5)从DHT11读取一次数据
DHT11的数据组成我们前面已经分析过了,40位(5个字节)数据中,高位先发送,我们设置5和Buffer用于存储这5个字节的数据,所以接收到的数据中,Buffer4是检验位,Buffer3和Buffer2分别是温度的小数和整数部分,而Buffer1和Buffer0分别是湿度的小数和整数部分。 我们先获取到这5个字节的数据,然后先通过校验位检查接收到的数据是否正确,如果正确的话,通过指针的方式指向温度和湿度的整数位。

/** * @brief 从DHT11读取一次数据 * @param temp: 温度值(范围:0~50°) * @param humi: 湿度值(范围:20%~90%) * @retval 0, 正常. * 1, 失败 */
uint8_t dht11_read_data(uint8_t *temp, uint8_t *humi)
{ 
        
    uint8_t buf[5];
    uint8_t i;
    dht11_reset();
    if (dht11_check() == 0)
    { 
        
        for (i = 0; i < 5; i++)         /* 读取40位数据 */
        { 
        
            buf[i] = dht11_read_byte();/* 读到的值存在buf[i]中 */
        }
        /* 通过校验位检查读取到的数据是否正确 */
        if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
        { 
        
            *humi = buf[0];         /* 湿度整数和小数分别在buf[0]和buf[1]中 */
            *temp = buf[2];         /* 温度整数和小数分别在buf[2]和buf[3]中 */
        }
    }
    else                           	 /* DHT11没有应答 */
    { 
        
        return 1;
    } 
    return 0;
}

(6)初始化DHT11的IO口
最后,不要忘了要初始化IO口才可以使用IO口,如下是DHT11的IO口初始化函数,配置IO口为开漏输出、上拉、高速模式,单总线中一定要配置总线为开漏输出,这点我们在前面部分已经分析过。

/** * @brief 初始化DHT11的IO口 DQ 同时检测DHT11的存在 * @param 无 * @retval 0, 正常 * 1, 不存在/不正常 */
uint8_t dht11_init(void)
{ 
        
    GPIO_InitTypeDef gpio_init_struct;
    DHT11_DQ_GPIO_CLK_ENABLE();                  /* 开启DQ引脚时钟 */
    gpio_init_struct.Pin = DHT11_DQ_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;      		/* 开漏输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                	/* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;  /* 高速 */
	/* 初始化DHT11_DQ引脚 */
    HAL_GPIO_Init(DHT11_DQ_GPIO_PORT, &gpio_init_struct); 
/* DHT11_DQ引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */

dht11_reset();                     /* 复位DHT11 */       
return dht11_check();             /* 等待DHT11的回应 */      

}
3. main.c文件代码
main.c文件的部分代码如下,我们需要在标红的字体之间手动添加代码:

1   #include "main.h"
2   #include "usart.h"
3   #include "gpio.h"
4   /* USER CODE BEGIN Includes */
5   #include "./BSP/Include/led.h"
6   #include "./BSP/Include/delay.h"
7   #include "./BSP/Include/dht11.h"
8   /* USER CODE END Includes */
9 
10  void SystemClock_Config(void);
11
12  int main(void)
13  { 
        
14    HAL_Init();
15    if(IS_ENGINEERING_BOOT_MODE())
16    { 
        
17      SystemClock_Config();
18    }
19    MX_GPIO_Init();
20    MX_UART4_Init();
21    /* USER CODE BEGIN 2 */
22    HAL_UART_Receive_IT(&huart4,&RxBuffer,1); /* 以中断方式接收函数 */
23    led_init();                               		 /* 初始化LED */
24    delay_init(209);                          	 /* 延时初始化延时函数 */
25    uint8_t t = 0;
26    uint8_t temperature;
27    uint8_t humidity;
28    /* USER CODE END 2 */
29    while (1)
30    { 
        
31      /* USER CODE BEGIN 3 */
32      while (dht11_init())                       /* DHT11初始化函数 */
33      { 
        
34        printf("DHT11 Error!\r\n");             /* 如果DHT11不在,打印信息 */
35        delay_ms(1000);                           /* 延时1s */
36      }
37      while (1)
38      { 
        
39        t++;
40        if (t == 20)
41        { 
        
42          t = 0;
43          dht11_read_data(&temperature, &humidity); /* 读DHT11 */
44          /* 打印温度值和湿度值 */
45          printf("DHT11 Temp=%d\r, Humi=%d%%\r\n", temperature, humidity);
46          LED0_TOGGLE();                                 /* LED0闪烁 */
47        }
48        delay_ms(10);                                    /* 延时10ms*/
49      }
50    }
51    /* USER CODE END 3 */
52  }

27.4 编译和测试
开发板上电,进入仿真运行后结果如下,串口打印此时测试的环境温度为24℃,湿度为63%,且LED0在闪烁。

图27.4.1 运行结果

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章