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的写保护机制和调试时的注意事项。记住一句话:看门狗是最后一道防线,配置好了能救命,配置不好能坑人。