单片机中的看门狗应用-STM32F103C8为例(10)

发布于:2025-08-09 ⋅ 阅读:(10) ⋅ 点赞:(0)

在嵌入式系统中,看门狗(Watchdog Timer, WDG) 是保障系统可靠性的“安全卫士”。当程序因干扰跑飞、死循环或硬件异常导致“卡死”时,看门狗能自动复位芯片,让系统恢复到正常状态。STM32F103C8T6(“小蓝板”)内置了两种看门狗:独立看门狗(IWDG) 和 窗口看门狗(WWDG),分别适用于不同场景。

一、看门狗的作用与分类

  1. 为什么需要看门狗?

嵌入式系统运行时可能遇到以下异常:
• 软件跑飞:代码逻辑错误导致程序跳转到非法地址(如数组越界、未初始化的函数指针调用)。

• 死循环:任务卡在某个循环中无法退出(如等待一个永远不触发的事件)。

• 硬件干扰:电磁干扰(EMI)或电源波动导致程序计数器(PC)异常。

看门狗通过定时计数机制监控程序运行状态:若在设定时间内未收到“喂狗信号”(即重置看门狗计数器),则认为系统异常,自动触发复位(Reset),强制重启芯片。

  1. STM32F103C8T6的两种看门狗

看门狗类型 名称 时钟源 特点 典型应用场景

独立看门狗(IWDG) Independent Watchdog 内部低速时钟(LSI,约40kHz) 不受主程序控制,完全独立运行;超时时间可配置(最大约26秒);复位整个芯片 防止系统整体崩溃(如主循环死循环)

窗口看门狗(WWDG) Window Watchdog APB1时钟(通常72MHz) 计数器有“窗口限制”(只能在特定时间窗口内喂狗);超时可配置(最大约86ms);复位整个芯片 监控关键任务执行时序(如中断服务函数必须按时完成)

关键区别:

  • IWDG是“傻瓜式”保护,只要超时未喂狗就复位;WWDG是“智能式”保护,必须在规定时间窗口内喂狗,否则复位。

  • IWDG的时钟(LSI)不稳定(误差±10%),适合对时间精度要求不高的场景;WWDG的时钟(APB1)稳定,适合精确时序监控。

二、独立看门狗(IWDG)实战:防止主循环卡死

  1. IWDG核心原理

• 时钟源:内部低速时钟(LSI),频率约40kHz(实际范围30~60kHz,受温度/电压影响,标准库中通常按40kHz计算)。

• 计数器:12位递减计数器(值范围0xFFF~0x000),当计数器减到0时触发复位。

• 预分频器(Prescaler):将LSI时钟分频,降低计数频率(可选4/8/16/64/128/256分频)。

• 喂狗操作:通过写入密钥0xAAAA(重载计数器值)和0xCCCC(启动IWDG)控制,实际标准库封装了简化接口。

超时时间公式:

超时时间 = (4 × 2^PR × RL) / LSI频率

其中:PR为预分频系数(4/8/16/64/128/256),RL为重装载值(0xFFF~0x000),LSI≈40kHz。

例如:PR=64(分频后频率=40kHz/64≈625Hz),RL=0xFFF(4095),则超时时间≈(4×2^6×4095)/40000 ≈ (4×64×4095)/40000 ≈ 26.2秒(最大值)。

  1. 标准库配置步骤与代码

(1)初始化IWDG(设置预分频和重装载值)

#include "stm32f10x.h"
#include "stm32f10x_iwdg.h"

// 初始化独立看门狗:预分频64,重装载值4095(约1秒超时)
void IWDG_Init(void) {
    // 启动独立看门狗(内部LSI时钟自动开启,无需手动配置)
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);  // 允许写入IWDG寄存器(密钥操作)
    IWDG_SetPrescaler(IWDG_Prescaler_64);          // 预分频64(40kHz/64≈625Hz)
    IWDG_SetReload(4095);                          // 重装载值=4095(计数器从4095递减到0)
    IWDG_ReloadCounter();                          // 立即重载计数器(避免初始化后立刻复位)
    IWDG_Enable();                                 // 启动IWDG
}

(2)喂狗操作(在主循环中定期调用)

// 喂狗函数(重载计数器值,复位倒计时)
void IWDG_Feed(void) {
    IWDG_ReloadCounter();  // 写入0xAAAA等效操作(标准库封装为直接重载)
}

(3)主函数示例(模拟正常任务+喂狗)

int main(void) {
    IWDG_Init();  // 初始化IWDG(约1秒超时)

    while (1) {
        // 模拟正常任务(例如读取传感器、控制外设)
        printf("系统正常运行...\r\n");  // 需确保串口已初始化(仅示例)

        // 关键:必须在超时时间内喂狗(例如每500ms喂一次,远小于1秒超时)
        IWDG_Feed();  

        delay_ms(500);  // 假设任务周期500ms(自定义延时函数)
    }
}

注意事项:

  • 若主循环因死循环卡住,超过1秒未调用IWDG_Feed(),IWDG计数器减到0,芯片自动复位。

  • 实际项目中需根据任务最坏执行时间(WCET)设置合理的超时时间(例如任务最慢100ms完成一次循环,则超时时间设为200ms)。

三、窗口看门狗(WWDG)实战:监控关键任务时序

  1. WWDG核心原理

• 时钟源:APB1时钟(通常72MHz),计数器递减频率稳定(误差极小)。

• 计数器:7位递减计数器(值范围0x40~0x7F,初始值由用户配置)。

• 窗口限制:计数器必须在窗口上限(W[6:0])和窗口下限(0x40)之间喂狗。

• 若在窗口上限之前喂狗(过早),触发复位(防止任务提前完成)。

• 若在窗口下限之后喂狗(过晚,计数器减到0x3F时),触发复位(防止任务超时)。

• 预分频器:可选1/2/4/8分频(进一步调整计数频率)。

超时时间公式:

最大超时时间(窗口下限喂狗) = (4096 × 4^WDGTB × (0x7F - 0x40)) / APB1频率

其中:WDGTB为预分频系数(0=1分频,1=2分频,2=4分频,3=8分频),APB1通常为72MHz。

例如:WDGTB=0(1分频),预装载值=0x7F(127),则计数器从127递减到0x40(64)为合法窗口,超时时间≈(4096×1×(127-64))/72000000 ≈ 0.00035秒(约0.35ms,实际需结合预装载值调整)。

更直观的配置:通常设置预装载值=0x7F(最大),窗口值=0x60(例如),则合法喂狗时间为计数器值在0x60~0x7F之间(约几十毫秒)。

  1. 标准库配置步骤与代码

(1)初始化WWDG(设置预分频、窗口值、计数器初始值)

#include "stm32f10x.h"
#include "stm32f10x_wwdg.h"

// 初始化窗口看门狗:预分频8,窗口值0x60,计数器初始值0x7F(约78ms超时窗口)
void WWDG_Init(void) {
    // 启动窗口看门狗(APB1时钟自动使用,无需手动配置)
    WWDG_SetPrescaler(WWDG_Prescaler_8);      // 预分频8(72MHz/8=9MHz,计数频率=9MHz/4096≈2.19kHz)
    WWDG_SetWindowValue(0x60);                // 窗口上限值=0x60(计数器必须>0x60才能喂狗)
    WWDG_Enable(0x7F);                        // 初始计数器值=0x7F(启动WWDG),同时使能
}

// 喂狗函数(必须在窗口内调用!)
void WWDG_Feed(void) {
    WWDG_SetCounter(0x7F);  // 重载计数器为0x7F(必须在窗口内操作)
}

(2)主函数示例(模拟关键任务+合法喂狗)

int main(void) {
    WWDG_Init();  // 初始化WWDG(窗口值0x60,计数器0x7F)

    while (1) {
        // 模拟关键任务(例如中断服务函数或定时任务)
        printf("执行关键任务...\r\n");  // 需确保任务在窗口期内完成

        // 关键:必须在计数器值>0x60时喂狗(例如每50ms喂一次,假设窗口允许)
        WWDG_Feed();  

        delay_ms(50);  // 假设任务周期50ms(需小于窗口时间)
    }
}

注意事项:

  • 喂狗时机必须严格控制在窗口内!若在计数器值≤0x60时喂狗(过早),或计数器值减到0x3F后喂狗(过晚),都会触发复位。

  • 实际项目中需通过实验确定窗口值和喂狗周期(例如用逻辑分析仪监测WWDG计数器值)。

四、IWDG与WWDG的选择与对比

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

时钟源 内部低速时钟(LSI,约40kHz,不稳定) APB1时钟(通常72MHz,稳定)

超时时间范围 几毫秒~约26秒(灵活) 几十毫秒~约86ms(较精确)

喂狗限制 无窗口限制(任何时间喂狗均可) 必须在特定时间窗口内喂狗(过早/过晚均复位)

适用场景 防止主循环整体卡死(如死循环、任务调度失败) 监控关键任务的执行时序(如中断服务函数必须在规定时间内完成)

复位影响 复位整个芯片 复位整个芯片

选择建议:

  • 如果只需要防止系统整体崩溃(如主循环死循环),用IWDG(配置简单,不依赖外部时钟)。

  • 如果需要确保某个关键任务(如传感器数据采集、电机控制中断)按时执行,用WWDG(精确控制时序)。

五、常见问题与调试技巧

  1. IWDG不复位?

• 检查LSI是否启用:IWDG依赖LSI时钟(标准库中IWDG_WriteAccessCmd会自动开启LSI,无需手动配置)。

• 确认喂狗周期:若喂狗过于频繁(如每10ms喂一次),超时时间需设置更短(减小RL值或增大PR分频)。

• 调试时禁用IWDG:开发阶段可通过注释IWDG_Enable()暂时关闭看门狗,避免频繁复位影响调试。

  1. WWDG误复位?

• 检查喂狗时机:确保在计数器值>窗口值(如0x60)时喂狗(可通过逻辑分析仪监测WWDG计数器)。

• 调整窗口值:若任务执行时间不稳定,适当增大窗口值(如从0x60改为0x70),延长合法喂狗时间窗口。

  1. 调试工具推荐

• 逻辑分析仪:监测IWDG/WWDG的计数器值或复位信号(如使用Saleae、DSView)。

• 串口打印:在喂狗函数中添加打印(需确保串口初始化不被看门狗影响)。

六、总结

STM32F103C8T6的两种看门狗(IWDG和WWDG)是保障系统可靠性的关键外设:
• 独立看门狗(IWDG):简单可靠,适合防止系统整体崩溃(如主循环死循环),配置灵活但时钟不稳定。

• 窗口看门狗(WWDG):精确控制时序,适合监控关键任务的执行窗口(如中断服务函数超时),依赖APB1时钟但限制严格。

实践建议:

  1. 在正式项目中,至少启用一种看门狗(推荐IWDG作为基础保护)。
  2. 通过实际测试调整超时时间或窗口值,确保既不会误复位,也不会因超时过长导致系统长时间卡死。
  3. 结合日志或指示灯(如复位后LED闪烁特定次数),快速定位复位原因。

网站公告

今日签到

点亮在社区的每一天
去签到