独立看门狗

  • ​​介绍​​
  • ​​STM32独立看门狗简介​​
  • ​​原理​​
  • ​​功能描述​​
  • ​​IWDG关键寄存器描述​​
  • ​​键寄存器(IWDG_KR)​​
  • ​​状态寄存器(IWDG_SR)​​
  • ​​预分频寄存器(IWDG_PR)​​
  • ​​重装载寄存器(IWDG_RLR)​​
  • ​​IWDG寄存器映像和复位值​​
  • ​​使用​​
  • ​​启动 STM32 的独立看门狗​​
  • ​​应用设计​​
  • ​​功能设计​​
  • ​​程序设计​​
  • ​​后续​​

介绍

STM32独立看门狗简介

STM32 有两种看门狗,提供了更高的安全性、时间的精确性和使用的灵活性,一个是独立看门狗另外一个是窗口看门狗,独立看门狗号称宠物狗,窗口看门狗号称警犬,两个看门狗设备(独立看门狗和窗口看门狗)可用来检测和解决由软件错误引起的故障;当计数器达到给定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位。本文主要来介绍独立看门狗。
独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效,LSI 的频率一般在 30~60KHZ 之间,根据温度和工作场合会有一定的漂移,我们一般取 40KHZ。窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。用通俗一点的话来解释就是一个 12 位的递减计数器,当计数器的值从某个值一直减到 0 的时候,系统就会产生一个复位信号,即 IWDG_RESET。如果在计数没减到 0 之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍能工作。
IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。

原理

单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路就是为了避免这种情况的发生。看门狗的作用就是在一定时间内(通过定时计数器实现)没有接收喂狗信号(表示 MCU 已经挂了),便实现处理器的自动复位重启(发送复位信号)。

功能描述

在键寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xFFF递减计数。当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)。无论何时,只要在键寄存器IWDG_KR中写入0xAAAA, IWDG_RLR中的值就会被重新加载到计数器,从而避免产生看门狗复位 。IWDG_PR和IWDG_RLR寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR寄存器中写入0x5555。以不同的值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。重装载操作(即写入0xAAAA)也会启动写保护功能。状态寄存器指示预分频值和递减计数器是否正在被更新。

IWDG关键寄存器描述

可以用半字(16位)或字(32位)的方式操作这些外设寄存器。

键寄存器(IWDG_KR)

地址偏移:0x00

复位值:0x0000 0000 (在待机模式复位)

STM32(七)------- 独立看门狗(IWDG)_arm


键寄存器 IWDG_KR 可以说是独立看门狗的一个控制寄存器,主要有三种控制方式,往这个寄存器写入下面三个不同的值有不同的效果。

键值

键值作用

0XAAAA

把 RLR 的值重装载到 CNT

0X5555

PR 和 RLR 这两个寄存器可写

0XCCCC

启动 IWDG

通过往键寄存器写 0XCCC 来启动看门狗是属于软件启动的方式,一旦独立看门狗启动,它就关不掉,只有复位才能关掉。在键值寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值 0xFFF 递减计数。当计数器计数到末尾 0x000 时,会产生一个复位信号(IWDG_RESET)。
无论何时,只要键寄存器 IWDG_KR 中被写入 0xAAAA, IWDG_RLR 中的值就会被重新加载到计数器中从而避免产生看门狗复位 。
IWDG_PR 和 IWDG_RLR 寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR 寄存器中写入 0x5555。将其他值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。重装载操作(即写入 0xAAAA)也会启动写保护功能。

状态寄存器(IWDG_SR)

地址偏移:0x0C

复位值:0x0000 0000 (待机模式时不复位)

状态寄存器 SR 只有位 0:PVU 和位 1:RVU 有效,这两位只能由硬件操作,软件操作不了。

STM32(七)------- 独立看门狗(IWDG)_stm32_02


如果在应用程序中使用了多个重装载值或预分频值,则必须在RVU位被清除后才能重新改变预装载值,在PVU位被清除后才能重新改变预分频值。然而,在预分频和/或重装值更新后,不必等待RVU或PVU复位,可继续执行下面的代码。(即是在低功耗模式下,此写操作仍会被继续执行完成。)

RVU:看门狗计数器重装载值更新,硬件置 1 表示重装载值的更新正在进行中,更新完毕之后由硬件清 0。PVU: 看门狗预分频值更新,硬件置‘1‘指示预分频值的更新正在进行中,当更新完成后,由硬件清 0。所以只有当 RVU/PVU 等于 0 的时候才可以更新重装载寄存器/预分频寄存器。

预分频寄存器(IWDG_PR)

地址偏移:0x04

复位值:0x0000 0000

STM32(七)------- 独立看门狗(IWDG)_看门狗_03


预分频寄存器(IWDG_PR)用来设置看门狗时钟的分频系数。

重装载寄存器(IWDG_RLR)

地址偏移:0x08

复位值:0x0000 0FFF(待机模式时复位)

STM32(七)------- 独立看门狗(IWDG)_stm32_04


重装载寄存器(IWDG_RLR)用来保存重装载到计数器中的值。该寄存器也是一个 32位寄存器,但是只有低 12 位是有效的。

IWDG寄存器映像和复位值

STM32(七)------- 独立看门狗(IWDG)_stm32_05

使用

启动 STM32 的独立看门狗

  1. 首先我们需要取消寄存器写保护(向 IWDG_KR 写入 0X5555),通过这步,我们取消 IWDG_PR 和 IWDG_RLR 的写保护,使后面可以操作这两个寄存器,设置 IWDG_PR 和 IWDG_RLR 的值。
IWDG_WriteAccessCmd( IWDG_WriteAccess_Enable );

这个函数非常简单,顾名思义就是开启/取消写保护,也就是使能/失能写权限。

  1. 之后我们需要设置独立看门狗的预分频系数和重装载值。
    设置 IWDG 预分频值:
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);

设置 IWDG 重装载值:

void IWDG_SetReload(uint16_t Reload);

设置好看门狗的分频系数 prer 和重装载值就可以知道看门狗的喂狗时间(也就是看门狗溢出时间),该时间的计算方式为:

Tout=((4×2^prer) ×rlr) /40

其中 Tout 为看门狗溢出时间(单位为 ms);prer 为看门狗时钟预分频值(IWDG_PR 值),范围为 0~7;rlr 为看门狗的重装载值(IWDG_RLR 的值);
比如我们设定 prer 值为 4,rlr 值为 625,那么就可以得到Tout=64×625/40=1000ms,这样,看门狗的溢出时间就是 1s,只要你在一秒钟之内,有一次写入 0XAAAA 到 IWDG_KR,就不会导致看门狗复位(当然写入多次也是可以的)。这里需要提醒大家的是,看门狗的时钟不是准确的40Khz,所以在喂狗的时候,最好不要太晚了,否则,有可能发生看门狗复位。
3. 重载计数值喂狗(向 IWDG_KR 写入 0XAAAA),按照 IWDG 重装载寄存器的值重装载 IWDG 计数器。

IWDG_ReloadCounter();

通过这句,将使 STM32 重新加载 IWDG_RLR 的值到看门狗计数器里面。即实现独立看门狗的喂狗操作。
4. 启动看门狗(向 IWDG_KR 写入 0XCCCC),使能 IWDG。

IWDG_Enable();

通过这句,来启动 STM32 的看门狗。注意 IWDG 在一旦启用,就不能再被关闭!想要关闭,只能重启,并且重启之后不能打开 IWDG,否则问题依旧,所以在这里提醒大家,如果不用 IWDG 的话,就不要去打开它,免得麻烦。

通过上面 4 个步骤,我们就可以启动 STM32 的看门狗了,使能了看门狗,在程序里面就必须间隔一定时间喂狗,否则将导致程序复位。

应用设计

功能设计

独立看门狗一般用来检测和解决由程序引起的故障,比如一个程序正常运行的时间是50ms,在运行完这个段程序之后紧接着进行喂狗,我们设置独立看门狗的定时溢出时间为60ms,比我们需要监控的程序 50ms 多一点,如果超过 60ms 还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。

程序设计

  1. IWDG 配置函数
void IWDG_Config(uint8_t prv ,uint16_t rlv)
{
// 使能 预分频寄存器 PR 和重装载寄存器 RLR 可写
IWDG_WriteAccessCmd( IWDG_WriteAccess_Enable );
// 设置预分频器值
IWDG_SetPrescaler( prv );
// 设置重装载寄存器值,rlr:重装载寄存器值:低 11 位有效。形参 rlv 用来设置重装载寄存器IWDG_RLR 的值,取值范围为 0~0XFFF。
IWDG_SetReload( rlv );
// 把重装载寄存器的值放到计数器中
IWDG_ReloadCounter();
// 使能 IWDG
IWDG_Enable();
}

溢出时间 Tout = prv/40 * rlv (s),prv 可以是[4,8,16,32,64,128,256]。如果我们需要设置 1s 的超时溢出,prv 可以取 IWDG_Prescaler_64,rlv 取 625,即调用:IWDG_Config(IWDG_Prescaler_64 ,625)。Tout=64/40*625=1s。

  1. 喂狗函数
    把重装载寄存器的值放到计数器中,喂狗,防止 IWDG 复位,当计数器的值减到 0 的时候会产生系统复位。
void IWDG_Feed(void)
{
IWDG_ReloadCounter();//reload
}
  1. 主函数
int main(void)
{
// 配置 LED GPIO,并关闭 LED
LED_GPIO_Config();
Delay(0X8FFFFF);
/*------------------------------------------------------------*/
/* 检查是否为独立看门狗复位 */
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
{
/* 独立看门狗复位 */
/* 亮红灯 */
LED_RED;
/* 清除标志 */
RCC_ClearFlag();

/*如果一直不喂狗,会一直复位,加上前面的延时,会看到红灯闪烁,在 1s 时间内喂狗的话,则会持续亮绿灯*/
}
else
{
/*不是独立看门狗复位(可能为上电复位或者手动按键复位之类的) */
/* 亮蓝灯 */
LED_BLUE;
}
/*--------------------------------------------------------------*/

// 配置按键 GPIO
Key_GPIO_Config();
// IWDG 1s 超时溢出
IWDG_Config(IWDG_Prescaler_64 ,625);
//while 部分是我们在项目中具体需要写的代码,这部分的程序可以用独立看门狗来监控如果我们知道这部分代码的执行时间,比如是 500ms,那么我们可以设置独立看门狗的溢出时间是 600ms,比 500ms 多一点,如果要被监控的程序没有跑飞正常执行的话,那么执行完毕之后就会执行喂狗的程序,如果程序跑飞了那程序就会超时,到达不了喂狗的程序,此时就会产生系统复位。但是也不排除程序跑飞了又跑回来了,刚好喂狗了,歪打正着。所以要想更精确的监控程序,可以使用窗口看门狗,窗口看门狗规定必须在规定的窗口时间内喂狗。
while (1)
{
// 这里添加需要被监控的代码,如果有就去掉按键模拟喂狗,把按键扫描程序去掉
//---------------------------------------------------------------------
if ( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )
{
// 喂狗,如果不喂狗,系统则会复位,LED1 则会灭一次,如果在 1s
// 时间内准时喂狗的话,则绿灯会常亮,否则红灯闪烁
IWDG_Feed();
//喂狗后亮绿灯
LED_GREEN;
}
}
//----------------------------------------------------------------------
}

主函数中我们初始化好 LED 和按键相关的配置,设置 IWDG 1s 超时溢出之后,进入while 死循环,通过按键来喂狗,如果喂狗成功,则亮绿灯,如果喂狗失败的话,系统重启,程序重新执行,当执行到 RCC_GetFlagStatus 函数的时候,则会检测到是 IWDG 复位,然后让红等亮。如果喂狗一直失败的话,则会一直产生系统复位,加上前面延时的效果,则会看到红灯一直闪烁。

后续

如果想了解更多物联网、智能家居项目知识,可以关注我的​​项目实战​​专栏和​​软硬结合​​专栏。

欢迎关注公众号了解更多。

STM32(七)------- 独立看门狗(IWDG)_看门狗_06

编写不易,感谢支持。