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

ATtiny25驱动DHT22时出现异常时序与行为问题排查

项目实现方案

采用ATtiny25作为主控,通过MOSFET为DHT22温湿度传感器、超声波测距传感器供电,MOSFET输出端同时接入供电总线,总线上配有3.3k上拉电阻。主程序绝大多数时间处于休眠状态,到达工作触发时机后执行以下逻辑:

if ((buff[1]<<8) + buff[0] <= powerCutoff) {
    generalStatus &= wipeMask; // 清除低3位状态

    setOutput(signalPin);
    setLow(signalPin);

    MOSFETPowerOn(devPower)
    initSleep(1<<WDP2);

    measureDHT();
    measureDistance();

    // sendData();
    MOSFETPowerOff(devPower)
}
相关宏定义与函数实现
#define MOSFETPowerOn(line) { line ## _port &= ~(1<<line); line ## _ddr |= (1<<line); asm("nop"); }
#define MOSFETPowerOff(line) { line ## _ddr &= ~(1<<line); line ## _port |= (1<<line); asm("nop"); }

#define ping(bit) { \
    bit ## _port &= ~(1<<bit); \
    bit ## _ddr |= (1<<bit); \
    bit ## _port |= (1<<bit); \
    asm("nop"); \
    bit ## _port &= ~(1<<bit); \
    asm("nop"); }

/** 设备供电引脚定义 */
#define devPower PB2
#define devPower_port PORTB
#define devPower_ddr DDRB
#define devPower_pin PINB

/** 调试引脚定义 */
#define debug PB0
#define debug_port PORTB
#define debug_ddr DDRB
#define debug_pin PINB

void initSleep(uint8_t timing) {
    asm("WDR");
    WDTCR = 1<<WDIE | timing;

    MCUCR &= ~(1<<SM0);
    MCUCR |= 1<<SE | 1<<SM1;
    asm("sleep");
}
void measureDHT() {
    generalStatus |= 1<<fDHTMeasurementInProgress;

    initSleep(1<<WDP2); // 休眠0.25s

    for (uint8_t i = 2; i < 7; i++) buff[i] = 0;
    dht22_status.status = dht22_inPresence;
    dht22_status.bitCounter = 0;
    dht22_status.byteCounter = 0;

    setOutput(devBus);
    _delay_us(1200); // 1ms起始低脉冲
    setInput(devBus);
    _delay_us(50);
// ... 其余代码省略
故障现象
  • 系统基础配置:时钟为8MHz,电源由稳压器提供,板载小型去耦电容。initSleep()等模块已在多个其他项目中复用,可正常工作。
  • 时序异常表现:根据芯片手册,看门狗配置1<<WDP2对应0.25s休眠时长。按代码逻辑,MOSFET上电后先执行一次0.25s休眠,进入measureDHT()后几乎第一时间再次执行0.25s休眠,之后拉低通信总线,因此从上电到拉低总线的理论间隔应略大于500ms,但实际测量值为2349ms,其余环节时序均正常。
  • 逻辑分析仪通道定义:第一通道为电源波形,第二通道为DHT22数据波形,第三通道为测距传感器波形,异常时序波形如下:
    异常时序波形
  • 临时验证:在MOSFET上电后添加一行ping(debug)代码,修改片段如下:
// ...
setOutput(signalPin);
setLow(signalPin);

MOSFETPowerOn(devPower)

ping(debug)
initSleep(1<<WDP2);

measureDHT();
// ...

此时时序恢复正常,波形如下:
正常时序波形
波形最下方通道可见ping操作产生的窄尖峰脉冲,添加该操作后时序完全正常。

  • 开发环境为Linux,avr-gcc版本为v5.4.0,编程器为AVR Dragon,初步排查未定位故障原因。
补充测试结果
  • 最小复现验证:将代码精简为最小复现版本,故障仍然存在,代码如下:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdint.h>

#include "macros.inc"
#include "pinConfig.h"

#define wakeCycle GPIOR0

#define MOSFETPowerOn(line) { line ## _port &= ~(1<<line); line ## _ddr |= (1<<line); asm("nop"); }
#define MOSFETPowerOff(line) { line ## _ddr &= ~(1<<line); line ## _port |= (1<<line); asm("nop"); }

void initSleep(uint8_t timing) {
    asm("WDR");
    WDTCR = 1<<WDIE | timing;

    MCUCR &= ~(1<<SM0);
    MCUCR |= 1<<SE | 1<<SM1;
    asm("sleep");
}

// 看门狗超时中断服务函数
ISR(WDT_vect) {
    wakeCycle = 12;
}

void measureDHT() {
    initSleep(1<<WDP2); // 0.25s

    setOutput(devBus);
    _delay_us(1200); // 1ms起始低脉冲
    setInput(devBus);
    _delay_us(50);
}

int main(void) {
    MOSFETPowerOff(devPower) // MOSFET驱动的设备默认通过上拉电阻关断
    GIMSK |= 1<<PCIE; // 使能引脚变化中断
    sei();

    while (1) {
        MOSFETPowerOn(devPower)
        initSleep(1<<WDP2);
        measureDHT();
        MOSFETPowerOff(devPower)

        initSleep(1<<WDP2 | 1<<WDP1 | 1<<WDP0); // 休眠2s
    }
}
  • 中断修改测试:将看门狗中断修改为如下空实现,此时时序运行正常:
// 看门狗超时中断服务函数
ISR(WDT_vect) {
    asm("nop");
}
  • 硬件移除测试:将电路中的DHT22移除后,精简版本代码与原代码均运行正常。
  • 当前待排查问题:无法确定该异常属于硬件电路问题还是代码/编译问题,寻求解决方案。

内容的提问来源于stack exchange,提问作者Gambanishu Habbeba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 09:09:42