stm32看门狗

总结 stm32 看门狗的使用方法

概述

看门狗

stm32中有两中看门狗,一种是独立看门狗、一种是窗口看门狗。独立看门狗的时间精度较低,适用于对时间没有要求的任务。可以将独立 看门狗看作是宠物狗,将窗口看门狗看作是警犬。

独立看门狗(IWDG)

之所以称之为“独立”是因为:独立看门狗的时钟由独立的RC振荡器LSI提供,即使主时钟发生故障它仍然有效。

独立看门狗的计数器是一个12位的递减计数器,最大值为0XFFF,当计数器减到0时,会产生一个复位信号:IWDG_RESET, 让程序重新启动运行,如果在计数器减到0之前刷新了计数器的值的话,就不会产生复位信号,重新刷新计数器值的这个动作我们俗称喂狗。

独立看门狗的简图:

其中键寄存器就相当于控制寄存器一样。

设置多久之内需要喂狗(即重新刷新计数器值):

重装载寄存器是一个12位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着独立看门狗的溢出时间。 超时时间Tout = (4*2^prv) / 40 * rlv (s) ,prv是预分频器寄存器的值,rlv是重装载寄存器的值。

使用范围

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

编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 使能 预分频寄存器PR和重装载寄存器RLR可写
IWDG_WriteAccessCmd( IWDG_WriteAccess_Enable );

// 设置预分频器值
IWDG_SetPrescaler( prv );

// 设置重装载寄存器值
IWDG_SetReload( rlv );

// 把重装载寄存器的值放到计数器中
IWDG_ReloadCounter();

// 使能 IWDG
IWDG_Enable();

查看是否喂狗了

1
2
3
4
5
6
if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET){
//没有喂狗
...
}else{
IWDG_ReloadCounter();//喂狗,重新加载值到计数器中
}

窗口看门狗

可以设置一个时间段,而不单单是在某个时间之前。独立看门狗是当计数寄存器中的值减到0的话就会产生复位信号。但是窗口是变成0x40,而不是0,这被称之为窗口的下限,这个是固定的。上限是可以更改的,只要在上下限之间喂狗了就不会复位。这就是为什么称之为“窗口”。所以窗口看门狗需要在窗口中间将计数器的值进行刷新,就不会产生复位。

RLR是重装载寄存器,用来设置独立看门狗的计数器的值。TR是窗口看门狗的计数器的值,由用户独立设置,WR是窗口看门狗的上窗口值,由用户独立设置。

窗口看门狗时钟

这个外设的时钟是由PCLK1提供的,PCLK1最大是36M,由RCC时钟控制器开启。

计数器时钟

我们知道看门狗实际上就是一个计数器构成的,那么计数器改变一次需要多久的时间?

计数器时钟由CK计时器时钟经过预分频器分频得到,分频系数由配置寄存器CFR的位8:7 WDGTB[1:0]配置,可以是[0,1,2,3],其中CK计 时器时钟=PCLK1/4096,除以4096是手册规定的,没有为什么。所以计数器的时钟CNT_CK=PCLK1/4096/(2^WDGTB),
这就可以算出计数器减一个数的时间T= 1/CNT_CK = PCLK1 * 4096 * (2^WDGTB)

这个WDGTB是预分频数,可以是[0,1,2,3],后面会讲到一个设置预分频数的函数WWDG_SetPrescaler()可以设置这个值,但是其参数是[1,2,4,8]这里我们将它们一一对应即可。

死前中断

窗口看门狗的计数器是一个递减计数器,共有7位,其值存在控制寄存器CR的位6:0,即T[6:0],当7个位全部为1时是0X7F,这个是最大值,当递减到T6位变成0时,即从0X40变为0X3F时候,会产生看门狗复位。这个值0X40是看门狗能够递减到的最小值,所以计数器的值只能是:0X40~0X7F之间,实际上真正用来计数的是T[5:0]。当递减计数器递减到0X40的时候,还不会马上产生复位,如果使能了提前唤醒中断:CFR位9 EWI 置1,则产生提前唤醒中断,如果真进入了这个中断的话,就说明程序肯定是出问题了。

那么在中断服务程序里面我们就需要做最重要的工作,比如保存重要数据,或者报警等,这个中断我们也叫它死前中断。

具体使用

上面我们知道,使用窗口看门狗的话必须要在窗口中间进行复位,不可以是窗口之前也不可以是窗口之后。

所以我们需要知道程序的具体执行时间,才好设置上窗口的值。

窗口看门狗函数

在标准库中提供了以下函数, 我们具体来说明每一个函数的作用.

1
2
3
4
5
6
7
8
void WWDG_DeInit(void);//重新初始化
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);//设置看门狗的使用分频值由1 2 4 8 四个选项
void WWDG_SetWindowValue(uint8_t WindowValue);//设置上窗口值
void WWDG_EnableIT(void);//开启死前中断
void WWDG_SetCounter(uint8_t Counter);//设置号计数器的值
void WWDG_Enable(uint8_t Counter);//开启窗口看门狗
FlagStatus WWDG_GetFlagStatus(void);//获取中断信息位
void WWDG_ClearFlag(void);//去除中断信息位

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* WWDG 配置函数
* tr :递减计时器的值, 取值范围为:0x7f~0x40
* wr :窗口值,取值范围为:0x7f~0x40
* prv:预分频器值,取值可以是
* @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1(36MHZ)/4096)/1
* @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1(36mhz)/4096)/2
* @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1(36mhz)/4096)/4
* @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1(36mhz)/4096)/8
*/
void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
{
// 开启 WWDG 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);

// 设置递减计数器的值
WWDG_SetCounter( tr );

// 设置预分频器的值
WWDG_SetPrescaler( prv );

// 设置上窗口值
WWDG_SetWindowValue( wr );

// 设置计数器的值,使能WWDG
WWDG_Enable(WWDG_CNT);

// 清除提前唤醒中断标志位
WWDG_ClearFlag();
// 配置WWDG中断优先级
WWDG_NVIC_Config();
// 开WWDG 中断
WWDG_EnableIT();
}

// 喂狗
void WWDG_Feed(void)
{
// 喂狗,刷新递减计数器的值,设置成最大WDG_CNT=0X7F
WWDG_SetCounter( WWDG_CNT );
}

// WWDG 中断复服务程序,如果发生了此中断,表示程序已经出现了故障,
// 这是一个死前中断。在此中断服务程序中应该干最重要的事,
// 比如保存重要的数据等,这个时间具体有多长,要
// 由WDGTB的值决定:
// WDGTB:0 113us
// WDGTB:1 227us
// WDGTB:2 455us
// WDGTB:3 910us
void WWDG_IRQHandler(void)
{
WWDG_ClearFlag();
//死前中断, 在这里要做最重要的事情, 如保存好数据信息
}

由上可以看到窗口看门狗在发生中断后可以留有一定的时间来让程序做好保存的工作,那么这个时间是多久这个是位WDGTB来决定的。

具体的计算公式为;

  • Twwdg:WWDG超时时间(单位为ms)
  • Fpclk1:APB1的时钟频率(单位为Khz)
  • WDGTB:WWDG的预分频系数
  • T[5:0]:窗口看门狗的计数器低6位

stm32看门狗
https://ysc2.github.io/ysc2.github.io/2023/12/27/stm32看门狗/
作者
Ysc
发布于
2023年12月27日
许可协议