第35章     WWDG—窗口看门狗

全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn

野火视频教程优酷观看网址:http://i.youku.com/firege

本章参考资料:《STM32F4xx中文参考手册》WWDG章节。

学习本章时,配合《STM32F4xx中文参考手册》WWDG章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。

35.1 WWDG简介

STM32有两个看门狗,一个是独立看门狗,一个是窗口看门狗。我们知道独立看门狗的工作原理就是一个递减计数器不断的往下递减计数,当减到0之前如果没有喂狗的话,产生复位。窗口看门狗跟独立看门狗一样,也是一个递减计数器不断的往下递减计数,当减到一个固定值0X40时还不喂狗的话,产生复位,这个值叫窗口的下限,是固定的值,不能改变。这个是跟独立看门狗类似的地方,不同的地方是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗,这就是窗口看门狗中窗口两个字的含义

图 351 IWDG与WWDG区别

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

35.2 WWDG功能框图剖析

图 352 窗口看门狗功能框图

1.    ①窗口看门狗时钟

窗口看门狗时钟来自PCLK1,PCLK1最大是45M,由RCC时钟控制器开启。

2.    ②计数器时钟

计数器时钟由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 = Tpclk1 * 4096 * (2^WDGTB)。

3.    ③计数器

窗口看门狗的计数器是一个递减计数器,共有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,则产生提前唤醒中断,如果真进入了这个中断的话,就说明程序肯定是出问题了,
那么在中断服务程序里面我们就需要做最重要的工作,比如保存重要数据,或者报警等,这个中断我们也叫它死前中断。

4.    ④窗口值

我们知道窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是固定的0X40,上窗口的值可以改变,具体的由配置寄存器CFR的位6:0 W[6:0]设置。其值必须大于0X40,如果小鱼或者等于0X40就是失去了窗口的价值,而且也不能大于计数器的值,所以必须得小于0X7F。那窗口值具体要设置成多大?这个得根据我们需要监控的程序的运行时间来决定。如果我们要监控的程序段A运行的时间为Ta,当执行完这段程序之后就要进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR设置成最大0X7F,窗口值为WR,计数器减一个数的时间为T,那么时间:(TR-WR)*T应该稍微大于Ta即可,这样就能做到刚执行完程序段A之后喂狗,起到监控的作用,这样也就可以算出WR的值是多少。

5.    ⑤计算看门狗超时时间

图 353 窗口看门狗时序图

这个图来自数据手册,从图我们知道看门狗超时时间:Twwdg = Tpclk1 x 4096 x 2^wdgtb x (T[5:0] + 1) ms,当PCLK1 = 30MHZ时,WDGTB取不同的值时有最小和最大的超时时间,那这个最小和最大的超时时间该怎么理解,又是怎么算出来的? 讲起来有点绕,这里我稍微讲解下WDGTB=0时是怎么算的。递减计数器有7位T[6:0] ,当位6变为0的时候就会产生复位,实际上有效的计数位是T[5:0],而且T6必须先设置为1。如果T[5:0]=0时,递减计数器再减一次,就产生复位了,那这减一的时间就等于计数器的周期=1/CNT_CK = Tpclk1 * 4096 * (2^WDGTB) = 1/30 * 4096 *2^0 = 136.53us,这个就是最短的超时时间。如果T[5:0]全部装满为1,即63,当他减到0X40变成0X3F时,所需的时间就是最大的超时时间=113.7*2^5=136.53*64=8.74ms。同理,当WDGTB等于1/2/3时,代入公式即可。

35.3 怎么用WWDG

WWDG一般被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。比如一个程序段正常运行的时间是50ms,在运行完这个段程序之后紧接着进行喂狗,如果在规定的时间窗口内还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。

35.4 WWDG喂狗实验

35.4.1 硬件设计

4、WWDG一个

5、LED两个

WWDG属于单片机内部资源,不需要外部电路,需要两个LED来指示程序的运行状态。

35.4.2 软件设计

我们编写两个 WWDG驱动文件,bsp_wwdg.h 和bsp_wwdg.c,用来存放WWDG的初始化配置函数。

1.    代码分析

这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本章配套的工程。

WWDG配置函数

代码 351 WWDG配置函数

 1 /* WWDG 配置函数
 2  * tr :递减计时器的值,取值范围为:0x7f~0x40
 3  * wr :窗口值,取值范围为:0x7f~0x40
 4  * prv:预分频器值,取值可以是
 5  *      @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1/4096)/1
 6  *      @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1/4096)/2
 7  *      @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1/4096)/4
 8  *      @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1/4096)/8
 9  */
10 void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
11 {
12
// 开启 WWDG 时钟
13     RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
14
15
// 设置递减计数器的值
16     WWDG_SetCounter( tr );
17
18
// 设置预分频器的值
19     WWDG_SetPrescaler( prv );
20
21
// 设置上窗口值
22     WWDG_SetWindowValue( wr );
23
24
// 设置计数器的值,使能WWDG
25     WWDG_Enable(WWDG_CNT);
26
27
// 清除提前唤醒中断标志位
28     WWDG_ClearFlag();
29
// 配置WWDG中断优先级
30     WWDG_NVIC_Config();
31
// 开WWDG 中断
32     WWDG_EnableIT();
33 }

			

WWDG配置函数有三个形参,tr是计数器的值,一般我们设置成最大0X7F,wr是上窗口的值,这个我们要根据监控的程序的运行时间来设置,但是值必须在0X40和计数器的值之间,prv用来设置预分频的值,取值可以是:

代码 352 形参 prv 取值

1 /*

 2 *     @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1/4096)/1
 3 *     @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1/4096)/2
 4 *     @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1/4096)/4
 5 *     @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1/4096)/8
 6 */

			

这些宏在stm32f10x_wwdg.h中定义,宏展开是32位的16进制数,具体作用是设置配置寄存器CFR的位8:7  WDGTB[1:0],获得各种分频系数。

WWDG中断优先级函数
 1 // WWDG 中断优先级初始化
 2 static void WWDG_NVIC_Config(void)
 3 {
 4     NVIC_InitTypeDef NVIC_InitStructure;
 5
 6     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
 7     NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
 8     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 9     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
10     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
11     NVIC_Init(&NVIC_InitStructure);
12 }

			

在递减计数器减到0X40的时候,我们开启了提前唤醒中断,这个中断我们称它为死前中断或者叫遗嘱中断,在中断函数里面我们应该出来最重要的事情,而且必须得快,因为递减计数器再减一次,就会产生系统复位。

提前唤醒中断复位程序

代码 353 提前唤醒中断服务程序

1 // WWDG 中断复服务程序,如果发生了此中断,表示程序已经出现了故障,

 2 // 这是一个死前中断。在此中断服务程序中应该干最重要的事,
 3 // 比如保存重要的数据等,这个时间具体有多长,要
 4 // 由WDGTB的值决定:
 5 // WDGTB:0   113us
 6 // WDGTB:1   227us
 7 // WDGTB:2   455us
 8 // WDGTB:3   910us
 9 void WWDG_IRQHandler(void)
10 {
11
// 清除中断标志位
12     WWDG_ClearFlag();
13
14
//LED2亮,点亮LED只是示意性的操作,
15
//真正使用的时候,这里应该是做最重要的事情
16     LED2(ON);
17 }

			
喂狗函数

代码 354 喂狗函数

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

喂狗就是重新刷新递减计数器的值防止系统复位,喂狗一般是在主函数中喂。

主函数

代码 355 主函数

1 int main(void)

2 {

3 uint8_t wwdg_tr, wwdg_wr;

4

5 /* LED 端口初始化 */

6 LED_GPIO_Config();

7

8 // BLUE 蓝色灯亮

9 LED3(ON);

10 Delay(0XFFFFFF);

11

12 // WWDG配置

13

14 /* WWDG 配置函数

15 * tr :递减计时器的值,取值范围为:0x7f~0x40,超出范围会直接复位

16 * wr :窗口值,取值范围为:0x7f~0x40

17 * prv:预分频器值,取值可以是

18 * @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1(45MHz)/4096)/1

19 约10968Hz 91us

20 * @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1(45MHz)/4096)/2

21 约5484Hz 182us

22 * @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1(45MHz)/4096)/4

23 约2742Hz 364us

24 * @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1(45MHz)/4096)/8

25 约1371Hz 728us

26 *

27 * 例:tr = 127(0x7f,tr的最大值)

28 * wr = 80(0x50, 0x40为最小wr最小值)

29 * prv = WWDG_Prescaler_8

30 * 窗口时间为728 * (127-80) = 34.2ms < 刷新窗口 < ~728 * 64 = 46.6ms

31 * 也就是说调用WWDG_Config进行这样的配置,若在之后的34.2ms前喂狗,

32 * 系统会复位,在46.6ms后没有喂狗,系统也会复位。

33 * 需要在刷新窗口的时间内喂狗,系统才不会复位。

34 */

35 // 初始化WWDG:配置计数器初始值,配置上窗口值,启动WWDG,使能提前唤醒中断

36 WWDG_Config(127,80,WWDG_Prescaler_8);

37

38 // 窗口值我们在初始化的时候设置成0X5F,这个值不会改变

39 wwdg_wr = WWDG->CFR & 0X7F;

40

41 while (1)

42 {

43 // BLUE 蓝色灯

44 LED3(OFF);

45 //-----------------------------------------------------

46 // 这部分应该写需要被WWDG监控的程序,这段程序运行的时间

47 // 决定了窗口值应该设置成多大。

48 //-----------------------------------------------------

49

50 // 计时器值,初始化成最大0X7F,当开启WWDG时候,这个值会不断减小

51 // 当计数器的值大于窗口值时喂狗的话,会复位,当计数器减少到0X40

52 // 还没有喂狗的话就非常非常危险了,计数器再减一次到了0X3F时就复位

53 // 所以要当计数器的值在窗口值和0X40之间的时候喂狗,其中0X40是固定的。

54 wwdg_tr = WWDG->CR & 0X7F;

55

56 if ( wwdg_tr < wwdg_wr )

57 {

58 // 喂狗,重新设置计数器的值为最大0X7F

59 WWDG_Feed();

60 }

61 }

62 }

主函数中我们把WWDG的计数器的值设置 为0X7F,上窗口值设置为0X5F,分频系数为8分频,则计数器减1的时间约为728us。在while死循环中,我们不断读取计数器的值,当计数器的值减小到小于上窗口值的时候,我们喂狗,让计数器重新计数。

在while死循环中,一般是我们需要监控的程序,这部分代码的运行时间,决定了上窗口值应该设置为多少,当监控的程序运行完毕之后,我们需要执行喂狗程序,比起独立看门狗,这个喂狗的窗口时间是非常短的,对时间要求很精确。如果没有在这个窗口时间内喂狗的话,那就说明程序出故障了,会产生提前唤醒中断,最后系统复位。

35.4.3 下载验证

把编译好的程序下载到开发板,LED3被点亮,一段时间之后熄灭,之后LED3一直就没有被点亮过,说明系统没有产生复位,如果产生复位的话LED3会再被点亮一次。中断服务程序中的LED也没被点亮过,说明喂狗正常。

第35章 WWDG—窗口看门狗—零死角玩转STM32-F429系列的更多相关文章

  1. 第34章 IWDG—独立看门狗—零死角玩转STM32-F429系列

    第34章     IWDG—独立看门狗 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  2. 第14章 启动文件详解—零死角玩转STM32-F429系列

    第14章     启动文件详解 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege ...

  3. 第39章 ETH—Lwip以太网通信—零死角玩转STM32-F429系列

    第39章     ETH—Lwip以太网通信 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...

  4. 第42章 电源管理—实现低功耗—零死角玩转STM32-F429系列

    第42章     电源管理—实现低功耗 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  5. 第44章 MPU6050传感器—姿态检测—零死角玩转STM32-F429系列

    第44章     MPU6050传感器—姿态检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

  6. 第33章 TIM—电容按键检测—零死角玩转STM32-F429系列

    第33章     TIM—电容按键检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  7. 第29章 电容触摸屏—触摸画板—零死角玩转STM32-F429系列

    第29章     电容触摸屏—触摸画板 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  8. 第26章 FMC—扩展外部SDRAM—零死角玩转STM32-F429系列

    第26章     FMC—扩展外部SDRAM 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...

  9. 第12章 GPIO输入-按键检测—零死角玩转STM32-F429系列

    第12章     GPIO输入—按键检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...

随机推荐

  1. RobotFramework AppiumLibrary 用户关键字

    RobotFramework AppiumLibrary 用户关键字 最近在用robotframework搞安卓app 的自动化,其中用到了 AppiumLlibrary 的关键字,我都映射成了用户关 ...

  2. vue axios 跨域

    qs是一个npm仓库所管理的包,可通过npm install qs命令进行安装. 1. qs.parse()将URL解析成对象的形式 2. qs.stringify()将对象 序列化成URL的形式,以 ...

  3. SparseArray替代HashMap来提高性能

    SparseArray是 Android框架独有的类,在标准的JDK中不存在这个类.它要比 HashMap 节省内存,某些情况下比HashMap性能更好,按照官方问答的解释,主要是因为SparseAr ...

  4. [转]dataTables-使用详细说明整理

    本文转自:http://blog.csdn.net/mickey_miki/article/details/8240477 本文共四部分:官网 | 基本使用|遇到的问题|属性表 一:官方网站:[htt ...

  5. Linux常用操作命令介绍

     Linux常用操作命令介绍 重要概念 CPU:就像人的大脑,主要负责相关事情的判断以及实际处理的机制.查询指令:cat /proc/cpuinfo 内存:大脑中的记忆区块,将皮肤.眼睛等所收集到的信 ...

  6. 项目中使用的spring 注解说明

    以前在项目中spring 的依赖注入使用 xml 配置,现在使用 注解(Annotation) 来实现配置. 1声明bean 1.1实例 有类: public class MyBean{ //do s ...

  7. Tips In C

    C语言中的使用操作 宏定义时使用do while防止语句的分离, 但是不使用与需要有返回值的语句, 这个时候可以参考第二条 宏定义时使用({}), ()加上{}的方式, 在代码中填写逻辑算法, 最后的 ...

  8. join() 和 sleep() 区别

    来源于<Java多线程编程核心技术> 一.join() 作用 在很多情况,主线程创建并启动子线程,如果子线程中需要进行大量的耗时计算,主线程往往早于子线程结束.这时,如果主线程想等待子线程 ...

  9. MongoDB 搭建Node.js开发环境

    理解Mongoose Elegant MongoDB object modeling for Node.js   安装Mongoose   $ cnpm install --save mongoose ...

  10. C# 多线程之线程同步

    多线程间应尽量避免同步问题,最好不要线程间共享数据.如果必须要共享数据,就需要使用同步技术,确保一次只有一个线程访问和改变共享状态. 一::lock语句 lock语句事设置锁定和接触锁定的一种简单方法 ...