stm32HAL库驱动DHT11温湿度传感器

代码代码🔥💦DHT11温湿度传感器HAL库驱动代码大放送!🌟

        最近有个新项目有用到DHT11温湿度传感器,关于这款传感器的介绍已经有好多大佬整理分享了,这里推荐几位整理的文章大家可以看看,我这里就只分享一下代码。

STM32学习之传感器篇——DHT11温湿度传感器

DHT11详细介绍(内含51和STM32代码)

【STM32】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;
}

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于使用STM32F1HAL驱动DHT11湿度传感器,您可以按照以下步骤进行操作: 1. 首先,您需要确保已经正确连接了DHT11传感器到STM32F1开发板上。将DHT11的VCC引脚连接到STM32F1的3.3V电源引脚,将GND引脚连接到STM32F1的地引脚,将DHT11的数据引脚连接到STM32F1的GPIO引脚。 2. 在STM32CubeMX中配置相关的GPIO引脚。选择合适的GPIO引脚作为DHT11传感器的数据引脚,并设置为输入模式。 3. 在代码中初始化相关的GPIO引脚,以及使用HAL库中的延时函数。 4. 编写代码读取DHT11传感器的数据。您可以使用GPIO读取数据引脚的电平变化来读取湿度数据。具体的读取过程可以参考DHT11的通信协议。 下面是一个简单的示例代码,用于读取DHT11传感器的湿度数据: ```c #include "stm32f1xx_hal.h" #define DHT11_PORT GPIOA #define DHT11_PIN GPIO_PIN_0 void delay_us(uint32_t us) { us *= (SystemCoreClock / 1000000) / 9; while (us--) { __NOP(); } } void DHT11_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = DHT11_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct); } void DHT11_Read(uint8_t *humidity, uint8_t *temperature) { uint8_t data[5] = {0}; uint8_t i, j; // 主机拉低总线,持续18ms以上 HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET); delay_us(20000); // 主机释放总线,并等待DHT11响应 HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET); delay_us(30); if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET) { // 等待DHT11拉低总线,持续80us while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET); // 等待DHT11拉高总线,持续80us while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET); // 接收湿度数据 for (i = 0; i < 5; i++) { for (j = 0; j < 8; j++) { // 等待DHT11拉低总线,持续50us while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET); // 计算数据位 delay_us(30); if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET) { data[i] |= (1 << (7 - j)); } // 等待DHT11拉高总线,持续26-28us或70us while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET); } } // 校验数据 if ((data[0] + data[1] + data[2] + data[3]) == data[4]) { *humidity = data[0]; *temperature = data[2]; } } } int main(void) { uint8_t humidity, temperature; HAL_Init(); DHT11_Init(); while (1) { DHT11_Read(&humidity, &temperature); // 处理湿度数据 // ... } } ``` 请注意,这只是一个简单的示例代码,您可能需要根据实际情况进行适当的修改和调整。此外,为了保证准确性,您可能需要添加适当的校验和错误处理机制。 希望这能帮助到您!如果您有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值