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作出答复信号。发送信号如下图所示:
https://i-blog.csdnimg.cn/direct/264414cc0da24bf4b271ab80b251c862.png
步调三:
DHT11的DATA引脚检测到外部信号有低电平常,等待外部信号低电平竣事,延迟后DHT11的DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知外设预备吸收数据,微处理器的I/0此时处于输入状态,检测到I/0有低电平(DHT11回应信号)后,等待87微秒的高电平后的数据吸收,发送信号如图5所示:
https://i-blog.csdnimg.cn/direct/ffa6a3ae710d4df2b2d821d59b3e2b37.png
步调四:
由DHT11的DATA引脚输出40位数据,微处理器根据I/0电平的变革吸收40位数据,位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。位数据“0”、“1”格式信号如图6所示:
https://i-blog.csdnimg.cn/direct/b88d98eb37ff4fb188acd559ae9d83d9.png
竣事信号
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
https://i-blog.csdnimg.cn/direct/153a1f5f2d754c9cbde4d537d380cb7d.png
2、配置外部高速晶振
https://i-blog.csdnimg.cn/direct/5317293573c24475a0c99997bc8b7937.png
3、 配置时钟
https://i-blog.csdnimg.cn/direct/00e4ce0bbfa042b48da63a667387da56.png
(二)配置DHT11的驱动引脚
将任意一个引脚配置为:输出模式、内部上拉、高速模式、重定名为DHT11
https://i-blog.csdnimg.cn/direct/0dc0d7a05ea746e69ed4d42bbe699c19.png
(三)配置串口
https://i-blog.csdnimg.cn/direct/7c01b6ae1e5f40aa86d7da4c492cba2f.png
(四)天生工程文件
https://i-blog.csdnimg.cn/direct/59031d19ed6f4c90ac96e78aca5a794d.png
四、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 = {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 = DHT11_Read_Byte(); //读取 5byte
}
if(data + data + data + data == data)
{
*humi = data + 0.1*data;
*temp = data + 0.1*data;
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_RESETHAL_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;
charDHT11_TX;
/* 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 */
/**
* @briefThe 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 */
} 五、结果展示
https://i-blog.csdnimg.cn/direct/5d52a605dcae46a0a9e054d469c298f6.png
https://i-blog.csdnimg.cn/direct/1884a668436e4616b71a64fbd2e5e069.gif
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]