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
- 26-28μs高电平代表
正确做法是先等待低电平结束,再计时高电平的持续时间来判断位值,而不是固定延时后读取。
修复读位循环:
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
相关产品推荐
相关产品推荐

