一、引言
在嵌入式系统开发中,温度数据的采集是一个常见的需求。DHT11 是一款低成本、易于使用的数字温湿度传感器,它可以同时测量温度和湿度,并通过单总线协议将数据传输给微控制器。STM32F407 是一款性能强大的 ARM Cortex - M4 内核微控制器,结合 STM32 的 HAL(Hardware Abstraction Layer)库,可以方便地实现与 DHT11 的通信,完成温度数据的采集。
DHT11 传感器通常有 4 个引脚,分别是 VCC(电源正极)、GND(电源负极)、DATA(数据传输线)和一个未使用的引脚。
DHT11 一次传输 40 位数据,数据格式为:8 位湿度整数部分 + 8 位湿度小数部分 + 8 位温度整数部分 + 8 位温度小数部分 + 8 位校验和。在实际应用中,DHT11 的湿度小数部分和温度小数部分通常为 0。校验和用于验证数据的准确性,其值等于前 4 个 8 位数据之和的低 8 位。
将 DHT11 的 VCC 引脚连接到 STM32F407 的 3.3V 电源,GND 引脚连接到地,DATA 引脚连接到 STM32F407 的一个 GPIO 引脚(例如 PA0)。
#define DHT11_PIN GPIO_PIN_0
#define DHT11_PORT GPIOA
uint8_t dht11_data[5];
由于 DHT11 的时序对延时要求较高,需要实现精确的延时函数。可以使用 SysTick 定时器来实现微秒级延时。
void delay_us(uint32_t us)
{
uint32_t start = SysTick->VAL;
uint32_t reload = SysTick->LOAD;
uint32_t ticks = us * (SystemCoreClock / 1000000);
while ((start - SysTick->VAL) % (reload + 1) < ticks);
}
void dht11_start(void)
{
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
HAL_Delay(20); // 拉低至少18ms
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
delay_us(30); // 拉高20 - 40μs
}
uint8_t dht11_wait_response(void)
{
uint8_t timeout = 0;
// 等待传感器拉低
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
{
delay_us(1);
timeout++;
if (timeout > 100)
return 1; // 超时
}
timeout = 0;
// 等待传感器拉高
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET)
{
delay_us(1);
timeout++;
if (timeout > 100)
return 1; // 超时
}
return 0;
}
uint8_t dht11_read_bit(void)
{
uint8_t timeout = 0;
// 等待高电平
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET)
{
delay_us(1);
timeout++;
if (timeout > 100)
return 0; // 超时
}
delay_us(40); // 等待40μs
if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
{
// 等待高电平结束
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
{
delay_us(1);
timeout++;
if (timeout > 100)
return 0; // 超时
}
return 1;
}
else
{
return 0;
}
}
uint8_t dht11_read_byte(void)
{
uint8_t byte = 0;
uint8_t i;
for (i = 0; i < 8; i++)
{
byte <<= 1;
byte |= dht11_read_bit();
}
return byte;
}
uint8_t dht11_read_data(void)
{
uint8_t i;
uint8_t checksum;
dht11_start();
if (dht11_wait_response())
return 1; // 响应超时
for (i = 0; i < 5; i++)
{
dht11_data[i] = dht11_read_byte();
}
checksum = dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3];
if (checksum != dht11_data[4])
return 1; // 校验和错误
return 0;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
if (dht11_read_data() == 0)
{
uint8_t temperature = dht11_data[2];
// 处理温度数据
// ...
}
HAL_Delay(2000); // 每2秒采集一次数据
}
}
delay_us
函数使用 SysTick 定时器来实现微秒级延时。通过计算 SysTick 定时器的计数值和时钟频率,实现精确的延时。
dht11_start
函数将 DATA 引脚拉低至少 18ms,然后拉高 20 - 40μs,启动一次数据采集。
dht11_wait_response
函数等待 DHT11 的响应信号,检测 DATA 引脚的高低电平变化。如果超时,则返回错误。
dht11_read_bit
函数读取一位数据,通过检测高电平的持续时间判断该位是逻辑 0 还是逻辑 1。dht11_read_byte
函数读取一个字节数据,通过循环调用 dht11_read_bit
函数实现。
dht11_read_data
函数读取 40 位数据,并计算校验和。如果校验和不匹配,则返回错误。
通过以上步骤,我们可以基于 STM32F407 HAL 库实现 DHT11 温度数据的采集。理解 DHT11 的通信时序是实现数据采集的关键,通过精确的延时和引脚操作,可以确保数据的准确读取。同时,在实际应用中需要注意电源稳定性、通信速率和抗干扰等问题,以提高系统的可靠性。
有不懂的可以留言私信!!!