当前位置:首页 > 嵌入式 > 嵌入式分享
[导读]在嵌入式系统的可靠性设计中,看门狗(Watchdog)是防止程序跑飞或死锁的最后一道防线。STM32等MCU通常提供两种硬件看门狗:独立看门狗(IWDG)和窗口看门狗(WWDG)。选错类型或喂狗策略不当,轻则导致频繁误复位,重则让看门狗形同虚设。本文将深入对比两者差异,并提供RTOS环境下的实战喂狗方案。



在嵌入式系统的可靠性设计中,看门狗(Watchdog)是防止程序跑飞或死锁的最后一道防线。STM32等MCU通常提供两种硬件看门狗:独立看门狗(IWDG)和窗口看门狗(WWDG)。选错类型或喂狗策略不当,轻则导致频繁误复位,重则让看门狗形同虚设。本文将深入对比两者差异,并提供RTOS环境下的实战喂狗方案。


一、本质差异:粗犷保安 vs 精细质检员


特性 独立看门狗 (IWDG) 窗口看门狗 (WWDG)


时钟源 独立LSI (~32-40kHz),不依赖主时钟 PCLK1 (APB1时钟),依赖系统时钟


复位条件 超时未喂狗 喂早、喂晚、不喂 均复位


时间精度 低(LSI受温漂影响) 高(与系统时钟同步)


中断能力 无中断,直接复位 支持提前唤醒中断(EWI),可预警


适用场景 防系统彻底死机(死循环、时钟故障) 防程序逻辑紊乱(任务卡死但没死透)


选型黄金法则:

• IWDG:用于“保底”。只要系统还能动,就必须喂狗,防止设备变砖。


• WWDG:用于“监控”。监控关键任务是否在预期时间窗内完成,防止程序跑飞但仍在喂狗。


二、IWDG实战:裸机与RTOS的喂狗策略


IWDG配置简单,核心在于喂狗位置的合理性。


1. 基础配置(HAL库)


// IWDG超时时间 ≈ 1.6秒 (LSI=32kHz, 分频64, 重载800)

void MX_IWDG_Init(void) {

   hiwdg.Instance = IWDG;

   hiwdg.Init.Prescaler = IWDG_PRESCALER_64;   // 分频系数

   hiwdg.Init.Reload = 800;                    // 重装载值

   HAL_IWDG_Init(&hiwdg);

}


避坑:IWDG一旦启动,无法通过软件关闭,只能通过复位或断电清除。


2. RTOS下的“心跳汇总”喂狗法


在RTOS中,严禁在定时器中断或高优先级任务中单独喂狗,否则即使低优先级任务卡死,狗依然能被喂饱,失去监控意义。


推荐方案:建立“喂狗守护任务”,收集各核心任务的心跳。

// 定义任务心跳标志

volatile uint32_t g_task_heartbeat = 0;


// 核心任务每隔一段时间“报平安”

void Critical_Task(void *pv) {

   while(1) {

       // ... 业务逻辑 ...

       g_task_heartbeat |= (1 << TASK_ID); // 设置心跳位

       vTaskDelay(pdMS_TO_TICKS(100));

   }

}


// 独立的喂狗任务(低优先级)

void IWDG_Feed_Task(void *pv) {

   const uint32_t ALL_TASK_MASK = (1 << TASK_NUM) - 1;

   TickType_t xLastWakeTime = xTaskGetTickCount();

   

   while(1) {

       vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(500)); // 每500ms检查一次

       

       // 检查所有任务心跳是否到位

       if ((g_task_heartbeat & ALL_TASK_MASK) == ALL_TASK_MASK) {

           HAL_IWDG_Refresh(&hiwdg); // 只有所有任务正常才喂狗

           g_task_heartbeat = 0;     // 清零心跳标志

       }

       // 若有任务未上报心跳,则不喂狗,触发IWDG复位

   }

}


此策略确保:任一任务卡死 → 心跳缺失 → 停止喂狗 → 系统复位。


三、WWDG实战:窗口期喂狗与预警机制


WWDG的计数器是7位(0x40-0x7F),当计数器值小于窗口值(Window)且大于0x3F时,才是合法的喂狗窗口。


1. 初始化与喂狗


// WWDG配置:窗口值=0x60,计数器初值=0x7F

void MX_WWDG_Init(void) {

   hwwdg.Instance = WWDG;

   hwwdg.Init.Prescaler = WWDG_PRESCALER_8;  // 预分频

   hwwdg.Init.Window = 0x60;                 // 窗口上限

   hwwdg.Init.Counter = 0x7F;                // 初始计数值

   hwwdg.Init.EWIMode = WWDG_EWI_ENABLE;     // 使能早期唤醒中断

   HAL_WWDG_Init(&hwwdg);

}


// 必须在窗口期内(计数器值在0x40~0x60之间)调用

void feed_wwdg(void) {

   if (__HAL_WWDG_GET_FLAG(&hwwdg, WWDG_FLAG_EWIF)) {

       // 已进入预警状态,通常不在此处喂狗,而是处理异常

       return;

   }

   HAL_WWDG_Refresh(&hwwdg, 0x7F); // 重置计数器

}



2. 早期唤醒中断(EWI)的应用


WWDG计数器减到0x40时会触发EWI中断,此时距离复位还有一段时间(约几个毫秒),这是最后的数据保存机会。

void WWDG_IRQHandler(void) {

   HAL_WWDG_IRQHandler(&hwwdg); // 处理标志位

   // 紧急保存关键数据到Backup SRAM或Flash

   save_critical_data();

   // 注意:EWI中通常不喂狗,让系统复位以恢复秩序

}



四、混合部署策略:IWDG + WWDG 双保险


对于高可靠性工业设备,推荐“IWDG保底 + WWDG抓异常”的组合拳。


1.  IWDG:设置较长的超时时间(如3-5秒),作为系统彻底死机的最后屏障。

2.  WWDG:设置精细的窗口(如100-200ms),监控关键控制循环的执行周期。若程序跑飞但仍在喂IWDG,WWDG会因喂狗时机错乱而触发复位。


五、常见喂狗陷阱与避坑指南


1.  在中断中喂狗:这是最常见的错误。中断可能正常执行而主循环已卡死,导致看门狗失效。

2.  喂狗周期等于超时时间:LSI有温漂,若喂狗间隔太接近超时时间,低温下可能因时钟变慢导致意外复位。安全余量至少50%。

3.  WWDG窗口计算错误:使用CubeMX的自动计算功能,避免手动算错窗口值导致一启动就复位。


六、结语


看门狗不是简单的“初始化+定时刷新”,而是系统级的健康监控机制。IWDG是“防猝死”的保险丝,WWDG是“测心率”的监护仪。在RTOS中,务必采用“心跳汇总”策略,让看门狗真正监控到每一个核心任务的生存状态,才能构建起坚不可摧的嵌入式系统防线。


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭