DHT11是很常用的温湿度传感器,时序也比较简单,如下所示:
直接给出HAL库的驱动:
1 微秒级延时函数
HAL库并没有直接的微秒级延时函数,下面是自己实现的微秒堵塞延时函数(使用定时器TIM3);
/**
* @brief 微秒级延时
*/
void bsp_delay_us(uint16_t us)
{
__HAL_TIM_SET_COUNTER(&htim3, 0);
HAL_TIM_Base_Start(&htim3);
while (__HAL_TIM_GET_COUNTER(&htim3) != us);
HAL_TIM_Base_Stop(&htim3);
}
2 配置DHT11数据引脚的输出模式和输入模式;
/**
* @brief DHT11 输出模式
*/
static void DHT11_Mode_OUT_PP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(BSP_DHT11_PORT, &GPIO_InitStruct);
}
/**
* @brief DHT11 输入模式
*/
static void DHT11_Mode_IN_NP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BSP_DHT11_PORT, &GPIO_InitStruct);
}
3 读取一个字节的数据;
/**
* @brief DHT11 读取字节
*/
uint8_t DHT11_ReadByte(void)
{
uint8_t i, temp = 0;
for (i = 0; i < 8; i++)
{
while (DHT11_IN == 0); // 等待低电平结束
bsp_delay_us(40); // 延时 40 微秒 低电平为 0 ,高电平为 1
if (DHT11_IN == 1)
{
while (DHT11_IN == 1); // 等待高电平结束
temp |= (uint8_t)(0X01 << (7 - i)); // 先发送高位 MSB
}
else
{
temp &= (uint8_t)~(0X01 << (7 - i));
}
}
return temp;
}
4 完整的读取一次数据(读取数据间隔最好为2s及以上,不然容易出错);
/**
* @brief DHT11 读取一次数据
*/
uint8_t DHT11_ReadData(DHT11_Data_TypeDef *DHT11_Data)
{
DHT11_Mode_OUT_PP(); // 主机输出,主机拉低
DHT11_OUT_0;
HAL_Delay(18); // 延时 18 ms
DHT11_OUT_1; // 主机拉高,延时 30 us
bsp_delay_us(30);
DHT11_Mode_IN_NP(); // 主机输入,获取 DHT11 数据
if (DHT11_IN == 0) // 收到从机应答
{
while (DHT11_IN == 0); // 等待从机应答的低电平结束
while (DHT11_IN == 1); // 等待从机应答的高电平结束
/*开始接收数据*/
DHT11_Data->humi_int = DHT11_ReadByte();
DHT11_Data->humi_deci = DHT11_ReadByte();
DHT11_Data->temp_int = DHT11_ReadByte();
DHT11_Data->temp_deci = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
DHT11_Mode_OUT_PP(); // 读取结束,主机拉高
DHT11_OUT_1;
// 数据校验
if (DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int + DHT11_Data->temp_deci)
{
return 1;
}
else
{
return 0;
}
}
else // 未收到从机应答
{
return 0;
}
}
测试程序:
while (1)
{
if (DHT11_ReadData(&DHT11_Data))
{
DEBUG_INFO("\r\n读取DHT11成功!\r\n\r\n湿度为%d.%d %RH ,温度为 %d.%d℃ \r\n",
DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
}
else
{
DEBUG_INFO("Read DHT11 ERROR!\r\n");
}
HAL_Delay(3000);
}
完整的驱动程序,仅供参考。
bsp_dht11.c
/**
******************************************************************************
* @file bsp_dht11.c
* @author
* @date
* @version v1.0
* @note DHT11 driver
******************************************************************************
*/
#include "tim.h"
#include "bsp_dht11.h"
/**
* @brief DHT11 输出模式
*/
static void DHT11_Mode_OUT_PP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(BSP_DHT11_PORT, &GPIO_InitStruct);
}
/**
* @brief DHT11 输入模式
*/
static void DHT11_Mode_IN_NP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BSP_DHT11_PORT, &GPIO_InitStruct);
}
/**
* @brief DHT11 读取字节
*/
uint8_t DHT11_ReadByte(void)
{
uint8_t i, temp = 0;
for (i = 0; i < 8; i++)
{
while (DHT11_IN == 0); // 等待低电平结束
bsp_delay_us(40); // 延时 40 微秒 低电平为 0 ,高电平为 1
if (DHT11_IN == 1)
{
while (DHT11_IN == 1); // 等待高电平结束
temp |= (uint8_t)(0X01 << (7 - i)); // 先发送高位 MSB
}
else
{
temp &= (uint8_t)~(0X01 << (7 - i));
}
}
return temp;
}
/**
* @brief DHT11 读取一次数据
*/
uint8_t DHT11_ReadData(DHT11_Data_TypeDef *DHT11_Data)
{
DHT11_Mode_OUT_PP(); // 主机输出,主机拉低
DHT11_OUT_0;
HAL_Delay(18); // 延时 18 ms
DHT11_OUT_1; // 主机拉高,延时 30 us
bsp_delay_us(30);
DHT11_Mode_IN_NP(); // 主机输入,获取 DHT11 数据
if (DHT11_IN == 0) // 收到从机应答
{
while (DHT11_IN == 0); // 等待从机应答的低电平结束
while (DHT11_IN == 1); // 等待从机应答的高电平结束
/*开始接收数据*/
DHT11_Data->humi_int = DHT11_ReadByte();
DHT11_Data->humi_deci = DHT11_ReadByte();
DHT11_Data->temp_int = DHT11_ReadByte();
DHT11_Data->temp_deci = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
DHT11_Mode_OUT_PP(); // 读取结束,主机拉高
DHT11_OUT_1;
// 数据校验
if (DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int + DHT11_Data->temp_deci)
{
return 1;
}
else
{
return 0;
}
}
else // 未收到从机应答
{
return 0;
}
}
// 测试程序
/*
while (1)
{
if (DHT11_ReadData(&DHT11_Data))
{
DEBUG_INFO("\r\n读取DHT11成功!\r\n\r\n湿度为%d.%d %RH ,温度为 %d.%d℃ \r\n", \
DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
}
else
{
DEBUG_INFO("Read DHT11 ERROR!\r\n");
}
HAL_Delay(3000);
}
*/
bsp_dht11.h
#ifndef __BSP_DHT11_H
#define __BSP_DHT11_H
#include "tim.h"
#include "stm32f1xx_hal.h"
#define BSP_DHT11_PORT DHT11_GPIO_Port
#define BSP_DHT11_PIN DHT11_Pin
#define DHT11_OUT_1 HAL_GPIO_WritePin(BSP_DHT11_PORT, BSP_DHT11_PIN, GPIO_PIN_SET)
#define DHT11_OUT_0 HAL_GPIO_WritePin(BSP_DHT11_PORT, BSP_DHT11_PIN, GPIO_PIN_RESET)
#define DHT11_IN HAL_GPIO_ReadPin(BSP_DHT11_PORT, BSP_DHT11_PIN)
typedef struct
{
uint8_t humi_int; // 湿度的整数部分
uint8_t humi_deci; // 湿度的小数部分
uint8_t temp_int; // 温度的整数部分
uint8_t temp_deci; // 温度的小数部分
uint8_t check_sum; // 校验和
} DHT11_Data_TypeDef;
uint8_t DHT11_ReadData(DHT11_Data_TypeDef* DHT11_Data);
#endif /* __BSP_DHT11_H */
来源:CSDN
作者:小小刘木子
链接:https://blog.csdn.net/dingyc_ee/article/details/103530982