ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32F103 看门狗实战:IWDG 防死机 + WWDG 抓跑飞,双狗守护全流程拆解

STM32F103 看门狗实战:IWDG 防死机 + WWDG 抓跑飞,双狗守护全流程拆解 给一台工业控制器做现场维护客户报「设备偶尔死机断电重启就好」。第一版方案简单粗暴装独立看门狗主循环末尾喂狗卡死就自动复位——问题确实解决了。但后来另一台设备出现更隐蔽的现象程序没死指示灯乱跳输出随机变化IWDG 却一次都没触发——因为主循环还活着只是状态机被干扰跑飞了。这版换上了窗口看门狗程序「跑太快、跑太慢」都会被它抓住。本文把两只狗的原理、配置、喂狗设计一次讲透。一、两只狗IWDG 防「死」WWDG 防「乱」F103 内置两只看门狗分工完全不同配图说明左卡 IWDGLSI 独立时钟、12 位计数器、防主时钟失效右卡 WWDGPCLK1 时钟、7 位窗口计数器、抓程序节奏。IWDG 独立看门狗挂在 LSI 上——一个标称 40kHz 的内部 RC 振荡器主时钟挂了它也照常计数所以它能兜住「晶振停振、程序跑飞」这类最恶劣的故障。12 位递减计数器减到 0 就整片复位。代价是 LSI 精度差实际 30~60kHz 波动超时时间只能估算。WWDG 窗口看门狗挂在 APB1 上时钟停了它也停——它不负责兜底负责抓节奏。7 位计数器在窗口内喂狗才有效喂早了复位程序跑太快、喂晚了复位程序跑太慢只认「按计划干活」。选型一句话只要防死 → IWDG要抓「该干活时没按节奏干」→ WWDG关键设备两个一起上。双狗的经典组合是窗口内喂 IWDG主循环正常节奏里同时喂两只狗WWDG 负责盯节奏IWDG 负责兜底——程序节奏乱了WWDG 先发难程序真死了IWDG 兜住。两个看门狗互为对方的「证据」杜绝了「只装一只时另一只被假喂」的盲区。二、IWDG1 秒超时是怎么算出来的IWDG 的配置核心是键寄存器 KR 的三把钥匙以及一条超时公式配图说明LSI 40kHz → PR 分频 ÷32 → 1.25kHz 计数 → RLR 重装载 1250 拍 → 1 秒归零复位三密钥 0xCCCC 启动 / 0xAAAA 喂狗 / 0x5555 解锁。Tout (4 × 2^prer) × (rlr 1) / 40kHzprer 是预分频值0~6 对应 ÷4~÷256rlr 是 12 位重装载值0~4095。以 1 秒超时为例prer3÷32、rlr1249 → 32 × 1250 / 40000 1000ms。÷4 分频最短 0.1ms÷256 分频最长约 26 秒。注意 LSI 在 30~60kHz 之间波动1 秒的「标称超时」实际可能在 0.7~1.3 秒——所以喂狗周期取超时的三分之一到二分之一别卡临界点。voidIWDG_Init(void){/* ① 0x5555 解锁之后才能写 PR 和 RLR */IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);/* ② 分频 ÷32prer3 */IWDG_SetPrescaler(IWDG_Prescaler_32);/* ③ 重装载值 124932 × 1250 / 40kHz 1s 超时 */IWDG_SetReload(1249);/* ④ 预装载 RLR等同步完成 */IWDG_ReloadCounter();/* ⑤ 0xCCCC 启动启动后只能靠复位关闭 */IWDG_Enable();}/* 喂狗 写 0xAAAA把 RLR 重装进计数器 */#defineFEED_DOG()IWDG_ReloadCounter()喂狗即IWDG_ReloadCounter()等价于写 0xAAAA。注意修改 PR/RLR 前必须写 0x5555 解锁且改完要等 SR 寄存器的 PVU/RVU 位清零再操作——代码里IWDG_ReloadCounter()预装载一次就是规避这个同步等待。三、WWDG喂早了也复位窗口就是规矩WWDG 的计数器只有 7 位从初值通常 0x7F递减喂狗必须落在窗口内——这是它和 IWDG 最大的不同配图说明计数器 0x7F 递减窗口 0x40~0x50绿色CNT W 喂狗复位早喂区减到 0x3F 不复位也复位晚喂区EWI 中断在 0x40 触发。窗口上限 W 可配必须 0x40 W 0x7F下限 0x40 固定。喂狗条件是0x40 ≤ CNT ≤ W计数器还大于 W 时重装 → 立即复位减到 0x40 以下还没喂 → 减到 0x3F 时复位。「太早」和「太晚」都是故障——窗口机制要抓的就是程序节奏乱了。超时按T (4096 × 2^WDGTB) / 36MHz × (初值 − 0x40)算WDGTB÷8、初值 0x7F 时每计数 0.91ms全段约 57ms——窗口短只适合主循环周期稳定的场合。voidWWDG_Init(void){/* ① 开 WWDG 时钟挂 APB1 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);/* ② 分频 ÷80.91ms/计数——必须先于启动配置 */WWDG_SetPrescaler(WWDG_Prescaler_8);/* ③ 窗口上限 W0x500x40~0x50 之间喂狗有效 */WWDG_SetWindowValue(0x50);/* ④ 初值 0x7F WDGA 启动T6 必须为 1防启动即复位 */WWDG_Enable(0x7F);/* ⑤ 清残留中断标志再开 EWI 提前唤醒中断 */WWDG_ClearFlag(WWDG_FLAG_EWIF);WWDG_EnableIT();NVIC_EnableIRQ(WWDG_IRQn);}/* 喂狗重装回初值 0x7F喂狗相位由主循环节奏决定见下 */voidWWDG_Feed(void){WWDG_SetCounter(0x7F);}配置顺序是硬规矩分频、窗口、初值必须在 WDGA 启动之前配好——启动后计数器大于 W 时改 CFR 配置寄存器会立即触发复位。窗口设计有个容易忽略的点喂狗节奏必须匹配窗口相位。窗口是 0x40~0x5047 拍 ≈ 42.8ms 到 63 拍 ≈ 57.3ms喂狗动作必须落在这个时间段里——主循环 10ms 一圈每 5 圈50ms喂一次喂狗时刻 CNT ≈ 0x48正好在窗口内如果改成每圈都喂10ms 就喂一次喂狗时刻 CNT ≈ 0x74大于 W喂早了立即复位——这就是「窗口」抓跑快的机理程序节奏乱了、提前执行到喂狗代码计数器还停在窗口外一次就露馅。EWI 中断在计数器减到 0x40 时触发相当于「死缓通知」从 0x40 到 0x3F 复位只差一拍÷8 时 0.91ms中断里要么立刻喂狗要么只做紧急保存别干重活voidWWDG_IRQHandler(void){if(WWDG_GetFlagStatus(WWDG_FLAG_EWIF)SET){/* 0x40 触发主循环节奏已经乱了最多再活 1 拍 */Save_Emergency_State();/* 只做最紧急的现场保存 */WWDG_SetCounter(0x7F);/* 立刻喂狗仍在窗口内争取一次机会 */WWDG_ClearFlag(WWDG_FLAG_EWIF);/* 清 EWIF否则中断反复进 */}}「EWI 里喂狗」是策略选择默认只保存现场、不喂让复位发生用复位标志记账——比在中断里救一个已经乱掉的程序更可靠。只有在「复位代价大于救活代价」的场景比如断电丢失累计数据才选择喂。四、喂狗节奏在哪喂决定能保护谁IWDG 超时设 1s、主循环周期 10ms计数器每 20 次循环喂一次——喂狗周期 200ms是超时的五分之一配图说明正常行每 200ms 喂一次绿超时线 1s跑飞行任务段卡死在 600ms无喂狗 → 超时复位。/* 主循环IWDG 每 20 圈≈200ms喂一次WWDG 每 5 圈≈50ms喂一次 */staticuint32_tloop_cnt0,ww_cnt0;while(1){Task_ScanKey();/* 按键扫描 */Task_StateMachine();/* 状态机WWDG 窗口守护的就是这里 */Task_Report();/* 数据上报 */if(ww_cnt5){ww_cnt0;WWDG_Feed();}/* 50ms窗口内 */if(loop_cnt20){loop_cnt0;FEED_DOG();}}喂狗位置决定保护范围。主循环末尾喂任何任务段卡死循环停转看门狗照常复位——裸机最简单可靠的方案。定时器中断里喂是反例主程序跑飞但中断还正常看门狗被喂得饱饱的永不复位——装了等于没装比不装更危险。RTOS 下用分级喂狗每个任务周期汇报「我活着」一个喂狗任务汇总后统一喂任一任务卡死都会让看门狗超时。注意 IWDG 和 WWDG 的喂狗节奏完全不同IWDG 超时 1s、每 200ms 喂一次是宽松节奏WWDG 窗口只有 57ms 宽喂狗必须踩在窗口相位上——两只狗各自按自己的节拍喂互不干扰这就是「双狗」的正确用法。喂狗周期怎么定先按超时的三分之一到二分之一取比如超时 1s 就每 200~300ms 喂一次然后做一次「最坏情况测试」人为让最慢的任务段跑满比如 Flash 写页、外设重连量出最坏循环时间确认喂狗点离超时线还有两倍以上余量。调试期可以先设长超时比如 10s验证逻辑功能稳定后再收紧到目标值——一上来就 1s 超时遇到正常的慢路径首次上电、校准耗时误复位反而分不清是程序问题还是配置问题配图说明A 主循环喂裸机首选、B 定时器中断喂假活反例中断正常时看门狗失聪、C RTOS 分级喂每任务报活 汇总喂双狗组合 WWDG 抓节奏 IWDG 兜底。五、醒过来先问一句谁把我复位的看门狗复位和上电复位对程序是两回事——上电要全量初始化看门狗复位则意味着「上次运行死了带着现场信息重新来」。区分方法在 RCC 的 CSR 寄存器intmain(void){uint8_tboot_reasonBOOT_POWER_ON;if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)SET)boot_reasonBOOT_IWDG_RESET;/* 上次被 IWDG 复位 */if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST)SET)boot_reasonBOOT_WWDG_RESET;/* 上次被 WWDG 复位 */RCC_ClearFlag();/* 清标志下次才判得准 *//* 按 boot_reason 分流正常启动 / 进安全模式 / 保留现场告警 */...}RCC_FLAG_IWDGRST/RCC_FLAG_WWDGRST分别对应 CSR 寄存器的 bit29/bit30。清标志要写 RMVF 位RCC_ClearFlag()否则下次复位的原因会被上一次污染。工程里这个标志通常伴随上电日志连续多次 IWDG 复位就该告警「程序长期不稳定」而不是默默重启了事。更进一步可以把复位次数记进备份寄存器Standby 下唯一活着的地方低功耗篇讲过连续复位超过阈值就进安全模式——关掉故障功能、只保留最小通信等工程师介入而不是无限重启循环。六、六个最容易翻车的点LSI 波动当精确定时实际 30~60kHz标称 1s 可能只有 0.7s——喂狗周期取超时的 1/3~1/2。中断里喂狗「假活」主程序跑飞但中断正常看门狗被定时喂饱永不复位——喂狗必须挂在主程序呼吸上。WWDG 窗口外喂狗CNT W 时重装 立即复位——喂狗前先确认在窗口内。启动后再改配置WWDG 启动后 CNT W 时写 CFR 也复位——分频/窗口/初值必须在 WDGA 前配好IWDG 改 PR/RLR 忘写 0x5555 解锁则写不进去。复位后不查复位标志上电、IWDG 复位、WWDG 复位全按普通启动跑——main 开头查标志记日志、进安全模式。EWI 中断里干重活0x40 到 0x3F 只差 0.91ms÷8 时——只做紧急保存 立即喂狗。小结两只狗的本质区别IWDG 听心跳WWDG 看节拍。裸机主循环末尾喂 IWDG是最低成本的防死机方案要抓状态机跑飞这类「没死但乱了」的故障上 WWDG 窗口关键设备双狗齐上IWDG 兜底 WWDG 抓节奏互为备份。别忘了复位标志——看门狗每复位一次都是系统在说话听懂它比一味加狗更重要。下一站回到内核看门狗在 RTOS 下的多任务喂狗设计分级喂狗、喂狗任务与死锁检测是 uC/OS-II 系列的内容。而下篇先讲 K1 任务堆栈实战——栈会不会爆、爆了怎么救一次讲透。
返回列表