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

WDT ISR未执行导致程序在while循环处挂起的原因排查

问题背景

以下代码用于借助Timer1测量AVR单片机看门狗定时器(WDT)频率:将Timer1配置为221kHz计数频率,待WDT触发中断时停止计数,通过计数值乘以Timer1溢出周期计算WDT中断的时长。实际运行时WDT未产生任何中断,程序卡在轮询wdtisr标志的while循环处挂死。

参考实现代码
void watchdog_disable()
{
    cli(); // Disable global interrupt
    MCUSR &= ~(1<<WDRF); // Clear the Watchdog System Reset Flag (WDRF)
    WDTCSR |= (1<<WDCE) | (1<<WDE); // In the same operation, write a logic one to WDCE & WDE
    WDTCSR = 0x00;  // Within the next four clock cycles, write the WDTCSR.WDE and Watchdog prescaler bits group
                    // (WDTCSR.WDP) as desired, but with the WDTCSR.WDCE cleared. This must be done in one operation.
}

// RV8A1, Date: 01-Jun-2022, Enable watchdog timer for system reset
void watchdog_enable()
{
    cli();        // Disable global interrupt
    WDTCSR |= (1<<WDCE) | (1<<WDE); // In the same operation, write a logic one to WDCE & WDE
    WDTCSR = 0x08;  // Within the next four clock cycles, write the WDTCSR.WDE and Watchdog prescaler bits group
                    // (WDTCSR.WDP) as desired, but with the WDTCSR.WDCE cleared. This must be done in one operation.
                    // WDE = 1, WDIE = 0, WDP[2:0] = 000; System Reset Mode Enabled;
    sei();
}

// RV8A1, Date: 01-Jun-2022, Enable watchdog timer in Interrupt mode
void watchdog_interrupt_enable()
{
    cli();        // Disable global interrupt
    WDTCSR |= (1<<WDCE) | (1<<WDE); // In the same operation, write a logic one to WDCE & WDE
    WDTCSR = 0x61;  // Within the next four clock cycles, write the WDTCSR.WDE and Watchdog prescaler bits group
                    // (WDTCSR.WDP) as desired, but with the WDTCSR.WDCE cleared. This must be done in one operation.
                    // WDE = 0, WDIE = 1, WDP[3:0] = 1001; Interrupt Mode Enabled;
    sei();
}


//*******************************************************************************

////////////////////////////main begin////////////////////////////////////////////////////////////
char numtochar(int charrxvd)
{
    char ch = 'x';
    switch (charrxvd)
    {
        case 0: ch = '0';
        break;
        case 1: ch = '1';
        break
        case 2: ch = '2';
        break;
        case 3: ch = '3';
        break;
        case 4: ch = '4';
        break;
        case 5: ch = '5';
        break;
        case 6: ch = '6';
        break;
        case 7: ch = '7';
        break;
        case 8: ch = '8';
        break;
        case 9: ch = '9';
        break;
    }
    return ch;
}

void sendnumber(unsigned int num)
{
    cpsrvrflg = 0;
    Send2esp8266("AT+CIPSERVER=0\r\n");
    for(i=0; i<10; i++)
    {
        _delay_ms(250);
    }
    //////////////////////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////////////////////
    Send2esp8266("AT+CIPMUX=0\r\n");  // Single
    for(i=0; i<6; i++)
    {
        _delay_ms(250);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////

    //Send2esp8266("AT+CIPSTART=\"UDP\",\"192.168.42.14\",5001\r\n");
    Send2esp8266("AT+CIPSTART=\"UDP\",\"192.168.42.1\", 5002\r\n");
    for(i=0; i<10; i++)
    {
        _delay_ms(250);
    }
    //////////////////////////////////////////////////////////////////////////////////////////
    Send2esp8266("AT+CIPMODE=1\r\n"); //
    for(i=0; i<5; i++)
    {
        _delay_ms(250);
    }
    //////////////////////////////////////////////////////////////////////////////////////////
    Send2esp8266("AT+CIPSEND\r\n"); // 7 characters
    for(i=0; i<6; i++)
    {
        _delay_ms(250);
    }
    //////////////////////////////////////////////////////////////////////////////////////////
    Send2esp8266("WDT FREQ = ");
    int x;
    while((num/10.0) != 0)
    {
        x=num%10;
        uart_transmit(numtochar(x));
        num=num/10;
    }

    Send2esp8266("+++");

    for(i=0; i<15; i++)
    {
        _delay_ms(250);
    }
    Send2esp8266("AT+CIPCLOSE\r\n");

    for(i=0; i<10; i++)
    {
        _delay_ms(250);
    }

    Send2esp8266("AT+CIPMODE=0\r\n"); // Transparent mode off
    for(i=0; i<6; i++)
    {
        _delay_ms(250);
    }
}

// timer freq = 11059200  Hz; for 1 tick = 1/11059200 sec = 5.79 usec
// total tick = 50; tcnt0 start 255-50 = 205 = 0xCD; timer frequency = 11059200/50 = 221184 Hz
float wdttimeout = 0;
int wdtisr = 0;

void timer1_init()
{
    TCNT1 = 0xFFCD; // 0x80 org // dec 128
    TIMSK1 = 0x01;
    TCCR1A &= ~(1<<WGM10); // RV09_H, Date: 05-May-2022, set Normal mode operation
    TCCR1A &= ~(1<<WGM11);
    TCCR1B &= ~(1<<WGM13);
    TCCR1B &= ~(1<<WGM12);
    TCCR1B |= (1<<CS10); // No prescaler; freq = fosc = 11059200 Hz
}

void timer1_stop()
{
    TCCR1B = 0x00;
    TIMSK1 = 0x00;
}

ISR(TIMER1_OVF_vect)
{
    //uart_transmit(timeoutsec);
    TCNT1 = 0xFFCD;
    wdttimeout++;
    //tmrflag = 1;
    //uart_transmit(timeoutsec);
    //uart_transmit('\n');
}

float trackwdt()
{
    wdttimeout = 0;
    wdtisr = 0;
    int num = 0;
    timer1_init();
    watchdog_interrupt_enable();
    while(wdtisr == 0)
        ;
    watchdog_disable();   // RV8A1, 01-Jun-2022, watchdog disable
    num = (int)(wdttimeout*(50/11059200))*1000; // Time in ms
    return(wdttimeout);
}

ISR(WDT_vect)
{
    timer1_stop();
    wdtisr = 1;
}

void main()
{
    trackwdt();
}
故障根因分析
  • 看门狗配置寄存器写入值错误,违反硬件配置时序要求
    代码注释明确要求,置位WDCE/WDE位后写入新配置时必须清零WDCE位,但watchdog_interrupt_enable中实际写入WDTCSR的值为0x61,换算为二进制是0b01100001,其中WDCE位(位5,对应掩码0x20)仍为置1状态,不符合硬件操作规范,导致整个WDT配置操作无效,看门狗中断始终未被使能。
    此外注释要求WDP预分频位配置为1001(对应典型超时时间2s),但0x61的低四位为0001,预分频配置也完全错误。按照注释的功能需求,正确的配置值应为0x49:仅WDIE位(位6)置1,WDCE、WDE位清零,WDP3、WDP0位置1,对应二进制0b01001001。
  • 配置WDT前未清除看门狗复位标志
    watchdog_disable函数中包含清除MCUSR寄存器WDRF(看门狗系统复位标志)的操作,但watchdog_interrupt_enable函数中缺失该步骤。AVR硬件明确要求,修改WDT任何配置前必须先清零WDRF标志,否则WDT的配置修改操作会被硬件忽略,无法正常切换到中断模式。
  • 存在显性编译错误(非卡死直接原因但会阻碍程序正常运行):numtochar函数中case 1分支的break语句末尾缺少分号,会直接触发编译失败。

内容的提问来源于stack exchange,提问作者vishnu m c

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:39:15