You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DHT11传感器正常但STM32 F4读取值始终为0的技术求助

DHT11读取温湿度始终为0的排查与修复(STM32F4)

针对你代码里的问题,核心出在DHT11的时序处理错误和GPIO配置缺失,以下是具体排查点和修复方案:

1. 响应阶段的时序逻辑完全错误

DHT11的通信时序要求:

  • 主机拉低总线至少18ms后释放(你这部分做对了)
  • DHT11会先拉低总线80μs,再拉高总线80μs,以此作为响应
  • 之后才开始发送40位数据

原代码里仅delay_us(40)后直接检查引脚,完全没处理DHT11的响应时序,导致根本没进入读数据的分支,温湿度一直是初始0值。

修复代码:替换响应检查部分的逻辑:

// Wait for DHT11 to respond: first low 80us, then high 80us
while(GPIOA->IDR & GPIO_IDR_ID1); // Wait until pin is pulled low by DHT11
while(!(GPIOA->IDR & GPIO_IDR_ID1)); // Wait until pin goes high

2. GPIO输入未配置上拉电阻

DHT11的数据线是开漏输出,需要外部上拉或MCU内部上拉才能正确读取电平。原代码设置PA1为输入时,未启用内部上拉,引脚处于浮空状态,无法稳定读取DHT11的信号。

修复代码:设置输入模式时同时启用上拉:

GPIOA->MODER &= ~GPIO_MODER_MODE1; // Set PA1 as input
GPIOA->PUPDR |= GPIO_PUPDR_PUPD1_0; // Enable internal pull-up on PA1

3. 读位的时序判断逻辑错误

原代码固定delay_us(40)后读引脚,不符合DHT11的位定义:

  • 每个位的起始是50μs低电平,之后:
    • 26-28μs高电平代表0
    • 70μs高电平代表1

正确做法是先等待低电平结束,再计时高电平的持续时间来判断位值,而不是固定延时后读取。

修复读位循环:

for (int i = 0; i < 40; i++) {
    // Wait for the start of the bit (low level end)
    while(!(GPIOA->IDR & GPIO_IDR_ID1));
    
    // Start timing the high level duration
    uint32_t start = micros(); // 这里需要一个高精度的微秒计时函数,比如用定时器实现
    while(GPIOA->IDR & GPIO_IDR_ID1);
    uint32_t duration = micros() - start;
    
    // 判断位值:高电平超过40μs则为1
    if (duration > 40) {
        bits[i / 8] |= (1 << (7 - (i % 8)));
    }
}

4. 校验失败未重置温湿度值

如果校验失败,原代码不会修改humidity和temperature,导致它们一直保留初始的0值。建议在校验失败时主动标记无效:

if (bits[4] == checksum) {
    humidity = bits[0];
    temperature = bits[2];
} else {
    humidity = 0; // 或设置为特殊值标记无效
    temperature = 0;
}

5. 微秒延时精度不足

你用SysTick配置的是1ms中断,delay_us如果基于SysTick实现,精度无法满足DHT11的时序要求(误差会导致读错位)。建议用定时器实现高精度的micros()和delay_us()函数,或者在编译优化等级为-O0时用空循环实现临时的微秒延时(注意不同主频下循环次数需要调整)。


内容的提问来源于stack exchange,提问作者Wolfgang Amadeus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:04:50