代码代码🔥💦DHT11温湿度传感器HAL库驱动代码大放送!🌟
最近有个新项目有用到DHT11温湿度传感器,关于这款传感器的介绍已经有好多大佬整理分享了,这里推荐几位整理的文章大家可以看看,我这里就只分享一下代码。
Cube配置
首先是引脚的配置,引脚的默认电平低电平,使用开漏上拉输出模式,DHT11数据引脚的电流很小,stm32普遍支持8ma以上的电流,所以没必要再外接上拉电阻了,使用内置的完全足以使用,引脚速度选择最低就好,这里科普一下引脚速率不是io的翻转速率是能通过的信号频率,选择高速不仅增加功耗还会引入不必要的高频噪声。这里我将引脚重命名为DHT11_DATA,当然你可以不重命名也可以重命名成其他的,只是在下面头文件代码中注意修改。
头文件
#ifndef __DRIVERS_DHT11_H__
#define __DRIVERS_DHT11_H__
#include "main.h"
typedef struct DHT11_DATA{
int8_t Temp_INT;
int8_t Temp_FLOAT;
int8_t Humi_INT;
int8_t Humi_FLOAT;
}DHT11_DATA;
typedef enum {
DHT11_PASS = 1,
DHT11_No_Response = -1,
DHT11_Wait_Timeout = -2
}DHT11_InitState;
#define DHT11_WriteDATA(x) HAL_GPIO_WritePin(DHT11_DATA_GPIO_Port, DHT11_DATA_Pin, x)
#define DHT11_ReadDATA() HAL_GPIO_ReadPin(DHT11_DATA_GPIO_Port, DHT11_DATA_Pin)
static void DHT11_delay_us(uint32_t time);
static int8_t DHT11_Getbyte(void);
DHT11_InitState DHT11_Init(void);
DHT11_DATA DHT11_GetData(void);
#endif /*__DRIVERS_DHT11_H__*/
代码部分
#include "drivers_DHT11.h"
/***********************************************************************************************
* 函数名称:DHT11_delay_us
* 功能描述:DHT11温湿度传感器微秒延时函数
* 输入参数:延时时间
* 输出参数:无
* 返 回 值:无
* 注意事项:乘方数为主频频率
* 修改日期 版本号 修改人 修改内容
* --------------------------------------------------------------------------------------------
* 2021/05/19 V1.0 WangJoy 创建
**********************************************************************************************/
static void DHT11_delay_us(uint32_t time)
{
time = time / 4 * 150;
while(--time)
{
__nop();
}
}
/***********************************************************************************************
* 函数名称:DHT11_Init
* 功能描述:DHT11温湿度传感器初始化
* 输入参数:无
* 输出参数:总线信号
* 返 回 值:DHT11_PASS, DHT11_No_Response =, DHT11_Wait_Timeout
* 注意事项:需先初始化引脚
* 修改日期 版本号 修改人 修改内容
* --------------------------------------------------------------------------------------------
* 2021/05/19 V1.0 WangJoy 创建
**********************************************************************************************/
#define DHT11_MaxTime 10000
DHT11_InitState DHT11_Init(void)
{
uint16_t time;
DHT11_WriteDATA(GPIO_PIN_RESET); //复位DHT11
DHT11_delay_us(18000);
DHT11_WriteDATA(GPIO_PIN_SET); //释放总线
time = 0;
while(DHT11_ReadDATA() == GPIO_PIN_SET) //等待DHT11拉低总线
{
if(time++ > DHT11_MaxTime) return DHT11_No_Response;
}
time = 0;
while(DHT11_ReadDATA() == GPIO_PIN_RESET) //等待DHT11拉高总线
{
if(time++ > DHT11_MaxTime) return DHT11_Wait_Timeout;
}
time = 0;
while(DHT11_ReadDATA() == GPIO_PIN_SET) //等待DHT11拉低总线
{
if(time++ > DHT11_MaxTime) return DHT11_Wait_Timeout;
}
return DHT11_PASS;
}
/***********************************************************************************************
* 函数名称:DHT11_Getbyte
* 功能描述:DHT11温湿度传感器获取一个字节数据
* 输入参数:无
* 输出参数:总线信号
* 返 回 值:字节数据
* 注意事项:需先初始化引脚
* 修改日期 版本号 修改人 修改内容
* --------------------------------------------------------------------------------------------
* 2021/05/19 V1.0 WangJoy 创建
**********************************************************************************************/
static int8_t DHT11_Getbyte(void)
{
uint8_t byte;
uint32_t time;
for(uint8_t i=0; i<8; i++)
{
time = 0;
while(DHT11_ReadDATA() == GPIO_PIN_RESET) //等待低电平持续完毕
{
if(time++ > 10000) return 0;
}
DHT11_delay_us(60);
byte <<= 1;
if(DHT11_ReadDATA() == GPIO_PIN_SET) //判断当前总线状态
{
byte += 1;
DHT11_delay_us(60);
}
}
return byte;
}
/***********************************************************************************************
* 函数名称:DHT11_GetData
* 功能描述:DHT11传感器获取温湿度数据
* 输入参数:无
* 输出参数:总线信号
* 返 回 值:温湿度数据
* 注意事项:需先初始化引脚
* 修改日期 版本号 修改人 修改内容
* --------------------------------------------------------------------------------------------
* 2021/05/19 V1.0 WangJoy 创建
**********************************************************************************************/
DHT11_DATA DHT11_GetData(void)
{
static DHT11_DATA DATA;
int8_t DHT11_CRC, DHT11_buf[5];
if(DHT11_Init() != DHT11_PASS) return DATA; //DHT11未响应,返回上一次获取的数据
for(uint8_t i=0; i<5; i++) //获取5个字节数据
DHT11_buf[i] = DHT11_Getbyte();
for(uint8_t i=0 ; i<4; i++) //计算校验和
DHT11_CRC += DHT11_buf[i];
if(DHT11_CRC != DHT11_buf[4]) return DATA; //数据有误,返回上一次获取的数据
DATA.Humi_INT = DHT11_buf[0];
DATA.Humi_FLOAT = DHT11_buf[1];
DATA.Temp_INT = DHT11_buf[2];
DATA.Temp_FLOAT = DHT11_buf[3];
return DATA;
}
注意!!!
移植一定要改的!!!
第一个函数DHT11_delay_us,因为HAL库的延时函数最小单位是ms,这里需要us函数判断总线的电平,DHT11是以时间长短表示数据01,所以us延时函数非常重要。
我使用的是G431CBT6没有外接晶振,最高主频150Mhz,因为是m4内核,延时函数是粗略估算的,实际上我拿示波器测精度还可以,请把延时函数的具体内容换成你自己芯片的延时函数,也可以用硬件延时,不过单独占用一个定时器实在是太浪费了,如果你有写自己的us延时函数可以自己用这句话替换:
#define DHT11_delay_us(x) You_delay_us(x)
使用
我是在操作系统上跑的所以这里提供了单独为DHT11创建任务的函数:
注意!!!DHT11对时序要求严格,一定要放在临界区运行,防止被其他程序长时间占用。
static void DHT11_Task(void *pvParameters)
{
osDelay(2000);
DHT11_InitState DHT11_State = DHT11_Init();
if (DHT11_PASS == DHT11_State)
printf("DHT11 init is PASS \n");
if (DHT11_No_Response == DHT11_State)
printf("DHT11 init is FAIL, The ERROR is: No_Response \n");
if (DHT11_Wait_Timeout == DHT11_State)
printf("DHT11 init is FAIL, The ERROR is: Wait_Timeout \n");
osDelay(2000);
while (1)
{
taskENTER_CRITICAL(); /*进入临界区*/
DHT11_DATA DATA = DHT11_GetData();
taskEXIT_CRITICAL(); /*退出临界区*/
xSemaphoreTake(USART1_Mutex, portMAX_DELAY);
printf("Temp: %d.%d°C, Humi: %d.%d%% \n", DATA.Temp_INT, DATA.Temp_FLOAT, DATA.Humi_INT, DATA.Humi_FLOAT);
xSemaphoreGive(USART1_Mutex);
osDelay(500);
}
}
如果是是裸机开发,使用就比较简单,也要注意不要被其他中断占用。
使用__disable_irq();
函数可以临时禁用所有中断。在代码开始前调用此函数,执行完关键时序代码后再调用__enable_irq();
恢复中断。这个操作影响全局中断状态,并且是非常底层的控制,应当谨慎使用。
HAL库提供了一个宏HAL_ENTER_CRITICAL_SECTION()
和HAL_EXIT_CRITICAL_SECTION()
来实现类似的功能,这两个宏内部也是通过禁用和启用中断来工作的,但提供了更规范的用法,便于代码阅读和维护,推荐使用。
如果你的STM32是Cortex-M4或更高版本,可以使用内核锁定(Kernel Lock)功能。这通过__DSB();
(数据同步障碍)和__ISB();
(指令同步障碍)指令来实现,但这通常用于确保内存访问顺序,不推荐使用。
这里也放一下裸机开发的使用代码:
int main(int argc, char * argv[])
{
HAL_Delay(1000);
DHT11_InitState DHT11_State = DHT11_Init();
if (DHT11_PASS == DHT11_State)
printf("DHT11 init is PASS \n");
if (DHT11_No_Response == DHT11_State)
printf("DHT11 init is FAIL, The ERROR is: No_Response \n");
if (DHT11_Wait_Timeout == DHT11_State)
printf("DHT11 init is FAIL, The ERROR is: Wait_Timeout \n");
HAL_Delay(2000);
while (1)
{
DHT11_DATA DHT11_data = DHT11_GetData();
printf("Temp: %d.%d°C, Humi: %d.%d%% \n", DHT11_data.Temp_INT, DHT11_data.Temp_FLOAT, DHT11_data.Humi_INT, DHT11_data.Humi_FLOAT);
HAL_Delay(2000);
}
return 0;
}