历史上的今天
返回首页

历史上的今天

今天是:2024年09月19日(星期四)

正在发生

2019年09月19日 | 第35章 WWDG—窗口看门狗—零死角玩转STM32-F429系列

2019-09-19 来源:eefocus

本章参考资料:《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也没被点亮过,说明喂狗正常。

推荐阅读

史海拾趣

Gigarams Semiconductor Device Corp公司的发展小趣事
这可能是由于传感器精度不足、控制器算法不准确或驱动器性能不稳定等原因导致的。解决方案包括提高传感器精度、优化控制器算法和更换性能更稳定的驱动器。
EDSYN公司的发展小趣事

2014年,Econais宣布推出新一代IEEE802.11b/g/n Wi-Fi模块——EC19D01。这款模块是物联网领域的一次重大突破,它采用了系统级封装(SiP)技术,实现了世界上最小、最容易集成和最低待机功耗的Wi-Fi模块。EC19D01的推出,进一步巩固了Econais在超低功耗物联网微型Wi-Fi模块领域的领先地位。

ARCOL公司的发展小趣事

品质是ARCOL公司的核心竞争力。公司始终坚持以质量为核心,建立了严格的质量管理体系。从原材料的采购到产品的出厂,每一个环节都经过严格把关,确保产品的质量和性能达到最高标准。同时,ARCOL还注重品牌建设,通过不断提升产品质量和服务水平,树立了良好的企业形象和口碑。

Daito Communication Apparatus Co Ltd公司的发展小趣事

随着微电子学的快速发展,电子设备对元器件的要求也越来越高。Daito公司敏锐地捕捉到了这一市场趋势,决定对保险丝进行进一步的创新。在1995年,他们成功开发出了适用于电路板安装的高精度小型报警保险丝。这一产品的推出,不仅满足了市场对小型化、高精度保险丝的需求,也进一步巩固了Daito公司在电子行业中的领先地位。

随后,Daito公司又针对微电子学的进一步发展,推出了可以连续自动安装的方形微型保险丝。这一产品的推出,大大提高了生产效率,降低了成本,同时也为客户提供了更加便捷的使用体验。近年来,随着面安装技术的兴起,Daito公司又迅速推出了适用于面安装技术的片状保险丝,再次展示了他们在电子行业中的创新实力。

请注意,由于篇幅限制,以上仅为两个故事示例。如果需要更多故事,可以进一步深入研究和探索Daito公司在电子行业中的发展历程和创新实践。

贝特莱公司的发展小趣事

深圳贝特莱电子科技股份有限公司成立于2011年7月,从一开始,公司就明确了以技术研发为核心的发展战略。依托专业团队多年的行业资源积累,贝特莱致力于开发具有自主知识产权的核心技术。在指纹识别、触控、生命感知及MCU等芯片领域,贝特莱不断取得突破,为后续的市场拓展奠定了坚实的基础。

Abbotec Incorporated公司的发展小趣事

随着技术的不断成熟,Abbotec开始将目光投向国际市场。公司积极参与国际电子展会,与多家国外企业建立了合作关系。通过与这些企业的合作,Abbotec不仅将产品销往全球各地,还引进了一些先进的生产技术和管理经验,进一步提升了自身的竞争力。

问答坊 | AI 解惑

比较全面的电子元器件符号集

比较全面的电子元器件符号集…

查看全部问答>

适合DIY的灯具设计

  比利时布鲁塞尔的年轻女设计师Nathalie Dewez设计了这个简约但是实用和美观的落地灯。简单的线条构成的支架将一切元素简到了极致。在大多数装饰风格里,这实在是一个值得称道的好设计。  对于我们来说,我们未必要花大钱去买啦,自己想些办法 ...…

查看全部问答>

怎样更轻松地理解阻抗匹配?

本帖最后由 paulhyde 于 2014-9-15 09:10 编辑 我想很多朋友都遇到这种问题! 希望对大家有所帮助  …

查看全部问答>

嵌入式 单片机 请过来人给点意见!!

我大四了,计算机专业,以后想做嵌入式系统工程师,但是只有一学期的时间了,我想,现在开始搞arm+linux肯定来不及,到上学期完的时候,出去肯定找不到相关的工作,时间太短了,学不到多少。 之前一直在弄单片机,可是看了一些招聘,都需要至少3款 ...…

查看全部问答>

各位大侠谈谈你们的单片机的具体方向和待遇呀

各位大侠谈谈你们的单片机的具体方向和待遇呀,我现在做MTK准备转行,大家说说自己的方向和待遇,我参考下呀,谢谢 有分拿哦…

查看全部问答>

急求打开打印机端口程序

VB或C# 打开打印机端口程序怎么写阿,急求~~~谢谢…

查看全部问答>

c51调用汇编函数的入口问题

欲调用现有函数—— Send(uchar slv_adr,uchar idata *databfr,uchar len); Send(0xb2,SerBfr,6); 其中SerBfr是个数组,从这个函数进入汇编代码, 作用:发送6个字节的东东, 以下汇编中的代码 ?_send?BYTE:     slv_adr?142:& ...…

查看全部问答>

求助合众达DM642试验箱例程问题

例程里有这样一个语句: int intTemp; Uint32 tempDisYbuffer    = 0x80300000;         fTemp = (*(Uint8 *)(tempSrcYbuffer + (numLines/2+i-1)*numPixels + (j-1))) +        ...…

查看全部问答>

xmega快速入门软件cvavr2.05

xmega速度快快   玩了几天xmega(用的是xmega128a3u),速度超快,秘籍是使用内部 RC振荡器 + PLL,可以倍频运行到48M Hz以上,而且这个频率是可以用外部32.768KHz钟表晶体标定的。另外一个秘籍是使用软件CVAVR2.05(crack版本),里面有代 ...…

查看全部问答>