3. 独立看门狗(IWDG)寄存器配置:PR预分频器、RLR重装载寄存器详解

好,咱们接着聊独立看门狗。上一节我讲了IWDG的整体架构,说白了就是那个独立运行的“监工”。但监工怎么工作,工作节奏多快,多久喂一次食,这些都得靠寄存器来配置。

今天我就把PR预分频器和RLR重装载寄存器这两个核心寄存器掰开揉碎了讲。嗯,这两个寄存器搞明白了,IWDG的配置你就掌握了八成。

3.1 PR预分频器寄存器——决定看门狗的“心跳”

先说说PR寄存器。它的全称是Prescaler Register,预分频器。你想想看,IWDG用的是独立的LSI时钟,这个时钟频率大概在32kHz左右。但问题来了——32kHz对于看门狗来说太快了。如果直接用这个频率去递减计数器,那喂狗的时间窗口会非常短,根本来不及。

所以我们需要分频。PR寄存器就是干这个的。

PR[2:0]位值 预分频系数 实际时钟频率(LSI≈32kHz) 最大超时时间(12位计数器)
000 4 8 kHz 约0.512秒
001 8 4 kHz 约1.024秒
010 16 2 kHz 约2.048秒
011 32 1 kHz 约4.096秒
100 64 500 Hz 约8.192秒
101 128 250 Hz 约16.384秒
110 256 125 Hz 约32.768秒
111 256 125 Hz 约32.768秒

看到这个表,你可能会问:为什么最大分频系数只有256?嗯,这是硬件设计决定的。PR寄存器只有3个有效位,所以最多8种分频选择。我个人习惯是把PR配置成32或64分频,这样超时时间在4到8秒之间,对于大多数医疗制氧机的控制逻辑来说刚刚好。

关键点:PR寄存器的值只有在IWDG的“写保护”被解除后才能修改。而且修改后不会立即生效,要等到计数器重新加载RLR的值才会应用新的分频系数。

3.2 RLR重装载寄存器——设定“喂狗”的截止时间

RLR寄存器,全称Reload Register。它的作用很简单:当计数器递减到0时,系统复位。而RLR的值,就是计数器从哪个数开始往下减。

RLR是一个12位的寄存器,取值范围是0到4095。注意,是12位,不是16位。我刚开始做项目时就被这个坑过——以为RLR可以设到65535,结果发现最大只能到4095。

超时时间的计算公式:

超时时间 = (RLR + 1) × 分频系数 / LSI频率

举个例子,假设LSI=32kHz,PR设为32分频(即实际时钟1kHz),RLR设为4000:

超时时间 = (4000 + 1) × 1 / 1000 = 4.001秒

也就是说,你必须在4秒内喂一次狗,否则系统复位。

我的经验:在医疗制氧机项目中,我一般把超时时间设为主循环周期的3到5倍。比如主循环跑一次需要500ms,那我就设2到2.5秒的超时时间。这样既不会因为偶尔的延迟而误复位,也能在程序卡死时及时恢复。

3.3 配置流程——手把手教你写代码

好了,理论讲完了,咱们直接上代码。这是我在STM32F103上配置IWDG的代码,其他平台大同小异。

#include "stm32f10x_iwdg.h"

void IWDG_Config(uint8_t prescaler, uint16_t reload)
{
    // 第一步:解除写保护
    // 注意:必须写入0x5555才能解锁
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    
    // 第二步:设置预分频系数
    // 我习惯用IWDG_Prescaler_32,也就是32分频
    IWDG_SetPrescaler(prescaler);
    
    // 第三步:设置重装载值
    // 注意:reload不能超过0xFFF(4095)
    IWDG_SetReload(reload);
    
    // 第四步:重装载计数器
    // 这一步让刚才设置的RLR值立即生效
    IWDG_ReloadCounter();
    
    // 第五步:使能IWDG
    // 一旦使能,就不能再关闭,除非复位
    IWDG_Enable();
}

// 喂狗函数——必须在超时前调用
void IWDG_Feed(void)
{
    IWDG_ReloadCounter();
}

注意:我曾经在调试时犯过一个低级错误——在配置完IWDG之后,忘记调用IWDG_ReloadCounter()。结果计数器从0开始递减,系统瞬间就复位了。嗯,这个坑我踩过,你们别踩。

3.4 避坑指南——我踩过的那些雷

做医疗设备这么多年,IWDG相关的坑我遇到不少。挑几个典型的说说:

  • RLR值设得太小:有一次我把RLR设成了100,分频系数4,结果超时时间只有10ms左右。主循环稍微慢一点就复位。后来我改成RLR=4000,分频32,世界清净了。
  • 忘记考虑LSI的误差:LSI的精度其实不高,典型值32kHz,但实际可能在30kHz到34kHz之间波动。所以计算超时时间时要留余量。我一般按30kHz算最坏情况。
  • 喂狗位置不对:很多人把喂狗放在中断里。这很危险——如果主循环卡死了,但定时器中断还在跑,看门狗永远不会复位。我建议喂狗放在主循环的末尾,而且要确保所有关键任务都执行完了再喂。

3.5 实战建议——医疗制氧机的典型配置

最后,给一个我在制氧机项目中的典型配置:

// 目标超时时间:约4秒
// LSI频率:32kHz(实际按30kHz算)
// 分频系数:32(实际时钟1kHz)
// RLR值:4000

IWDG_Config(IWDG_Prescaler_32, 4000);

// 在主循环末尾喂狗
while(1)
{
    // 执行传感器采集
    // 执行PID控制算法
    // 执行故障检测
    // ... 其他任务
    
    // 所有任务完成后,喂狗
    IWDG_Feed();
}

这个配置下,实际超时时间大约4秒。即使LSI有偏差,最坏情况也在3.7秒到4.3秒之间,完全满足医疗设备的安全要求。

好了,PR和RLR这两个寄存器就讲到这里。下一节我会讲IWDG的写保护机制和调试时的注意事项。记住一句话:看门狗是最后一道防线,配置好了能救命,配置不好能坑人。