你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32CubeIDE的窗口看门狗WWDG经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-6 15:13
一、stm32的WWDG说明6 a3 z, m2 C5 b9 `- a
       1.1  WWDG特点:

: [* |: s8 Z3 ~, ~8 ~* p        在前一篇博文介绍独立看门狗时就指出STM32 MCU提供两个看门狗,独立看门狗和窗口看门狗。
- u4 {3 a! K$ \3 W5 H% `6 F7 Z' q9 T7 d) H
        相比独立看门狗,窗口看门狗WWDG有以下特点:
$ ^* @0 O+ ^5 @& `2 h        【1】WWDG计数器依赖于系统时钟,准确来说依赖于系统时钟通过分频、倍频得到的PCLK1时钟,即APB1 peripheral clocks输出频率。
8 f# y' N, W& I# X# |        【2】WWDG支持中断功能以及早期唤醒中断。
  W; _+ V8 c- [
  T* ^+ W) p: b% X  V  D        1.2 WWDG的cubeMX配置及说明% g  B0 A0 t: W2 f
        现在看一下WWDG在CubeMX中的设置问题,WWDG和IWDG一样,在系统内核栏目开启,开启激活选项后,可以设置5项参数,分别是计数时钟分频值,窗口值、递减计数预设值、早期唤醒中断使能以及中断功能。& \" c# Q) [0 T
98991825d78f4fbaa73212a13f1a399f.png
6 M" E  R6 g8 M9 A* y" a2 Q' V2 J* C2 _$ V) f
        【1】 一旦WWDG启用,将生成系统重置功能并启动其递减计数器,喂狗时,必须在设定的上限时间和下限时间之间喂狗,如果喂狗时间高于上限时间或者低于下限时间,都会导致看门狗触发重启机制。其中下限时间是系统固定的0X40。上限时间(窗口值)是用户可以定义的,大于0X40同时小于0X7F即可。% {( {4 [6 T0 Y2 a1 c/ `
% w% w0 l/ O7 v0 R2 A# Y
        【2】程序在达到0x3F值之前刷新计数器(计数器的低六位值,最大值111111=0X3F),到期时触发系统重置(即,当计数器值从0x40向下滚动到0x3F时生成重置,即再次减一时,0x40=0X3F+0X01)。并在计数器达到刷新窗口值之前刷新了计数器值,也会生成MCU重置。这就要求必须在有限的窗口中刷新计数器。另外WWDG启用后,除非通过系统重置,否则无法禁用WWDG。
* {! V4 `+ c, c6 B  }5 V& z% p! f* T6 R/ Y
        【3】如果启用了早期唤醒中断(Early Wakeup Interrupt,EWI)功能,在WWDG到期之前发出警告(即计数器达到0x40时会产生中断)。使用早期唤醒中断(EWI),在生成MCU重置之前可执行特定的安全操作或数据记录。此机制要求在NVIC中启用WWDG中断设置。同样,EWI启用后,EWI中断不能被禁用,除非通过系统重置。中断状态感知可在RCC_CSR寄存器中的WWDGRST标志判断何时发生WWDG重置。: K. D5 l0 `' D5 \, t

: b) J( ?9 {* U* ~, s

) [0 S+ N, W& z        1.3 WWDG喂狗时间计算

, M. G% i/ G# q/ N3 }& v        WWDG计数器输入时钟由PCLK1频率(APB1 peripheral clocks输出频率)除以计数时钟分频值得出。
/ O$ j. ~0 k" }" \3 {. n! ?' T0 v) c) w+ Y) G
e61915a0f0ff49f69ba6ec1fa1697eef.png & z) Y2 O+ N6 I8 F6 X

* b2 b2 o& m. ]: t0 t; f         WWDG时钟(Hz)=PCLK1/(4096*预分频器);
. c! Q. v1 [* v& K& H( z, J, E! R$ m% g. p
        WWDG周期(mS)=1000/WWDG时钟(Hz);
" ^, L9 I$ B" k/ |: u
5 i0 D& M+ l5 j0 A; z( N        WWDG超时MinT(mS)=WWDG周期(mS)*(计数器-窗口),因此最好设置递减计数值≥窗口值。
* p1 `& \) V# |' z- f( S# S3 x2 @- C. d  b8 z; N) A1 }$ Q/ Z
        WWDG超时MaxT(mS)=WWDG周期(mS)*(计数器-0x40),0x40=0X3F+0X01;
9 i, `, m, J: I6 }- u/ ^5 {
- [$ F( L' [* ]6 P        WWDG喂狗时间MinT(mS)<t<MaxT(mS)。
' Z- r4 C  @, ?! S9 l+ w+ A

" J! d1 N- r# G$ ]/ |二、WWDG工程创建及源码分析
. T$ d5 j" _' E; d, y/ s       2.1 cubeMX界面配置WWDG

+ d2 F/ H1 ^3 I* D  {9 A         本博文基于前面独立看门狗的工程直接增加窗口看门狗功能,并关闭独立看门狗。  D2 o/ j9 {! r
" }0 D6 {3 W9 e  {, K
        双击.ioc文件打开cubeMX界面,开启WWDG,设置其参数如下,其中分频值2,窗口值0X64(100),递减计数预设值0X64(100),开启早期唤醒中断:
  E+ S/ G3 H$ O, U1 [$ m
7 w& F7 _5 _5 T5 x: c
f1f7497080cd40f1853040eb75b2a652.png $ U2 f( i6 [, j& ~  I& b9 d
1 c' v+ c" f& F. U
         开启WWDG中断功能
& |% P0 d% w( I  V# l* _0 W+ v+ x
261f23989a6b41498df65be316df09cf.png
: @. b3 \  b9 [$ E8 ]
; F- P  U: \$ L" x) G9 K, E
         APB1时钟输出频率设置10MHz(10 000 000Hz),设置该值小一些,主要是本博文采用按键触发切换喂狗时间间隔,而按键捕获到松开是人为操作,反应较慢,实时性不好体现。
  t; g$ B7 b+ U) n. ?, Z; b+ ~
, c5 U' m6 T( ^* E         2.2 WWDG超时时间实例计算
' E% A4 H9 ~7 N4 x; A        在WWDG的喂狗时间按前面计算公式,喂狗时间范围:) y: j8 ]* m3 N: O: C
1 ], g8 A9 y9 D  ~, J0 D! \
        WWDG周期(mS)=1000ms/10MHz/(4096*8)=3.2768ms。8 @# L- Y+ N" ?, t' L

/ y7 }" |6 [# P( q. b        WWDG喂狗时间是在WWDG启动后的t时间内:, v3 P3 k3 ]( k0 {) J8 l
; T1 I7 m. m1 [5 x  E
        t>3.2768ms*(0X64-0X64)=0ms;
$ }, z  B) Z8 S+ A- k
( {& k9 D/ K  A2 {
        t<3.2768ms*(0X64-0X40)=117.9648ms。
* j3 `. N% F& Y! Q- v; N$ a! E9 o- ^& Z. W# ~

6 l* |3 y- p/ i# m1 u) W       2.3 工程高级配置$ F, `4 u1 W6 H, A2 T
         在工程高级配置中,取消WWDG的自动初始化,本博文将自己添加初始化,主要是HLA的WWDG初始化启动就立即进入计数,会给第一次喂狗造成时间差异较大。
- ~! Z7 J0 b, L: P
5 W2 r" n: b1 d
1bfc3d8fa7d24e54a97dbc87ab8f4317.png
! t" z3 {; u5 e+ F8 h
# J1 A) ?4 O4 a7 H/ W0 |1 Q" n        生成代码输出。) u' s5 |5 u: Q3 n  @3 I# L' K- }

: S- z, w2 Q4 @* M2 K5 f! S三、WWDG源码分析及应用$ G( I& M& ]: G2 u. D$ p* T
        3.1 WWDG的HLA库源码分析

' l0 n0 g( d& r* I, q        WWDG会在Core源码目录下的Inc及Src目录,分别生成wwdg.h和wwdg.c驱动文件。在wwdg.c文件中,主要定义了MX_WWDG_Init函数和HAL_WWDG_MspInit函数。MX_WWDG_Init主要做两件事情,一是将CubeMX上配置的参数传递给WWDG缓存Init和生成WWDG句柄Instance,二是调用HLA库的HAL_WWDG_Init来实现真正的初始化设定。HAL_WWDG_MspInit是HLA内的弱函数,根据实际配置CubeMX会生成新的函数覆盖原来的弱函数,而在HAL_WWDG_Init函数中会调用到HAL_WWDG_MspInit函数。! ^" t: F6 v1 a  m; T

+ m  g. t2 E. Z
2b4c2b5b42104381bb7a213382fff3ca.png
+ w" p$ U9 g( O/ G4 V
4 M* Z# B4 L4 m; K         在stm32l4xx_hal_wwdt.c源文件中定义了HAL_WWDG_Init函数,它做以下事情:诊断配置参数是否合规(如果不是采用CubeMX配置,而是自己手动配置或调整过参数的,这里可能异常);调用HAL_WWDG_MspInit函数完成WWDG时钟以及中断初始化;最后将依据参数写入WWDG寄存器。0 p& ~. s0 Z( ?, m- i
) i4 L4 m  x6 Y9 X6 z$ x5 y
136b6b9e484a4fc2ad6b049467a4542a.png
: j# r1 ], ~7 @- R8 _! F3 o# ]( O" u, J  T- Y9 g' z0 K
         程序在依据参数将WWDG计数器值写入WWDG寄存器CR,将窗口值和时钟分频值写入WWDG寄存器CFR内。; S1 r5 Y9 V$ Q6 R  G/ z2 T5 Z

% {$ R1 _3 o% t: b* \7 Q, u' ]
d799e52574e943baa64598274903a5ed.png
$ b6 L$ U+ v( _* k5 {* s
% N' q7 O' J) z0 Y) c& R eb67a4bdb772428e92f464444c98c2a1.png
& Z- `  ?* O' m; j/ `& A0 u! G/ l: K" H- Q, P% h8 a
         再回到wwdg.c内,HAL_WWDG_MspInit函数实现了WWDG时钟启动设置和中断初始及启动设置。
4 {( g' ]5 F; c. p' }( B# s7 P- y" g( u
d081f9832148473daa7a3f8b7bb2009c.png
0 o8 [; M- x- W& s" A
3 p1 l/ |3 ~2 O  e         HAL_NVIC_EnableIRQ启动后,如果有WWDG中断事件时,当中断服务例程触发HAL_WWDG_IRQHandler时,将自动清除标志,并执行HAL_WWDG_WakeupCallback用户回调函数报警。该回调函数在stm32l4xx_hal_wwdt.c定义,是个弱函数,用户可以通过自定义回调AL_WWDG_WakeupCallback来添加自己的代码。例如本文将在wwdg.c文件内重新定义该函数:
8 T$ y) e" e( O' {' ~0 l
  1. /* USER CODE BEGIN 1 */
    & Z; y9 R5 P* D& t8 D& o
  2. void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
    2 A& W! v% {; ?7 r8 B! x1 Z
  3. {
    4 J( R' t3 O# f
  4.         printf("I know, but do nothing!\r\n");
    9 g$ Q+ R, }0 p) X. f/ }
  5. }
    # G$ l0 n$ p: `
  6. /* USER CODE END 1 */
复制代码
% x5 r+ V- C/ q
         3.2 延时函数设计
( v; f# p& i: V* C" E7 T        在ICore目录下添加delay目录,并在该目录下创建delay.h和delay.c源文件,实现自定义延时函数,主要满足本博文更高精度的延时要求。0 c: }! c' l( b& M

/ [5 A8 Y& r3 n0 X: R        delay.h,声明微妙、毫秒、秒的延时函数。
& O2 A  r8 S: J
  1. #ifndef DELAY_DELAY_H_5 ~3 s2 ?8 B3 K- ]% b
  2. #define DELAY_DELAY_H_- Y' M  X& _& B4 J) J( ~
  3. + n" h% z$ g& h3 F9 O( E* D% ~
  4. #include "stm32l4xx_hal.h" //HAL库文件声明
    7 I8 S. D* t" u7 J& r
  5. , s$ m, J( F$ Q( |( y
  6. void delay_us(uint32_t us);        //延时微妙
    5 l8 R. }) J7 K/ k& Y0 a
  7. void delay_ms(uint32_t ms);        //延时毫秒
    2 M/ S( q: Z" {3 O" |7 i
  8. void delay_s(uint32_t s);        //延时秒4 _2 {. l2 |1 c) J

  9. 0 y/ y: O( {; M" r; V. e% i4 r
  10. #endif /* DELAY_DELAY_H_ */
复制代码

6 I& {; k; G3 l# S  Z        delay.c,  T- r; Z' b, s( z( ]0 ]! s
  1. #include "delay.h"
    ! @4 J' N0 C. s; B  Y
  2. 8 G& q% l" j8 L3 O
  3. #define MFP_VAL 8000000    //80MHz& P5 C! Q/ t, @1 f0 V

  4. 2 D! q- Z; o6 e+ V! x
  5. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数( q, n$ w" n: N2 h6 P
  6. {
    5 o' T9 X3 F" a4 y. a
  7.     uint32_t delay = (HAL_RCC_GetHCLKFreq() /  MFP_VAL* us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数
    # s( |& G; Z% @) q' S
  8.     while (delay--); //循环delay次,达到1微秒延时
    ( j7 Q* O# h. ~. h$ U! [
  9. }8 V8 U1 |7 K$ a  V3 g7 `
  10. , e& N: U. E/ R! S
  11. void delay_ms(uint32_t ms){ //mS毫秒级延时程序6 P) \! L$ D6 z! ?' }2 R# A( d7 O
  12.         while( ms-- != 0){$ n0 \1 \: b+ G# {8 W2 k
  13.                 delay_us(1000);        //调用1000微秒的延时3 E, l% ?! a- u7 t
  14.         }
    ) C" g- _' g3 ^  C) M( v- R& E- f
  15. }
    / |& n  [/ L2 L
  16. / j. t- a+ I( s" _
  17. void delay_s(uint32_t s){ //S秒级延时程序4 `# J4 K$ ?! T! E
  18.         while( s-- != 0){; H' U- h& M; V* n( |. T0 |
  19.                 delay_ms(1000);        //调用1000毫秒的延时
    4 Q" E! Z) p( u
  20.         }3 @/ Z  y0 B, Q$ o
  21. }
复制代码
% M0 E! d4 U2 z8 Y
        3.3 WWDG使用程序设计1 H$ o& [* x1 t2 m' z
        在本博文中,我们设计通过按键切换喂狗时间间隔,来测试喂狗窗口及时间间隔效果。- c/ c, w9 F7 {8 T( ?8 ?$ N" v. m
6 c$ t0 R. g: i  b! ~
0 h7 M" T4 h' [3 i& Y% K
        在main.c源文件中,添加驱动头文件,注意由于在CubeMX取消了自动初始化WWDG,因此需要手动添加wwdg.h头文件:
* c- I9 j5 W5 z4 G$ {
  1. /* Private includes ----------------------------------------------------------*/
    2 Z+ `' q! ^9 s% O) ]
  2. /* USER CODE BEGIN Includes */
    8 `: G: r( i0 l8 C4 u) {
  3. #include "wwdg.h"
    9 h. {; @. }) y0 c, F) ~
  4. #include "../../ICore/key/key.h"! _/ z8 ~' v( m9 f$ A9 a
  5. #include "../../ICore/led/led.h"( Z5 V/ q" d1 W# I% P
  6. #include "../../ICore/print/print.h"
    & B6 w( V) `" m& Y+ r; U
  7. #include "../../ICore/usart/usart.h"
    / o- X. P$ g( |7 V) E/ t
  8. #include "../../ICore/delay/delay.h"
    . c( U3 T+ r' u/ J: F
  9. /* USER CODE END Includes */
复制代码

2 i! v9 E# _7 Y/ @: R7 R( K: D; z        在main主函数前,声明WWDG句柄,用于喂狗函数是调用' {' q1 V" J+ x$ d  B+ A
  1. /* Private user code ---------------------------------------------------------*/: M2 P9 r$ q6 c- t/ F" f2 |8 r
  2. /* USER CODE BEGIN 0 */& T3 a# E; V4 Z+ S; k3 \, w
  3. extern WWDG_HandleTypeDef hwwdg;1 s9 y2 ]/ Q4 T. f) o
  4. /* USER CODE END 0 */
复制代码
, ^; O4 z" d7 ], J5 d8 q; X$ r! e
        在main主函数内,设置各外设功能及手动初始化WWDG驱动。) z6 X3 g& B) E* R
  1.   /* Initialize all configured peripherals */1 l. g( u+ l1 q, `
  2.   MX_GPIO_Init();; i# P7 A9 K; g/ ^. Z
  3.   MX_LPUART1_UART_Init();
    $ o. \; t# W2 N. B
  4.   /* USER CODE BEGIN 2 */. M4 O. m2 G" o. \
  5.   ResetPrintInit(&hlpuart1);  y3 O% r# }% j. q
  6.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
    6 F6 U6 U/ X( \8 ?
  7.   HLPUSART_RX_STA = 0;
    1 U5 z: \4 m6 Z( e; O
  8.   //
    " Q; ~+ ]. y( w/ l
  9.   printf("app restart now!\r\n");
    # R6 m) k5 _3 v8 P
  10.   uint8_t wdt_flag = 1;% h0 j$ h0 \! ?! b
  11.   uint8_t printf_flag = 1;7 w- i4 P/ ?5 j4 D' ]& z* }
  12.   MX_WWDG_Init();1 [9 d" ^: C9 ]6 v. F1 p: s4 Z& d2 e
  13.   /* USER CODE END 2 */
复制代码

: o4 V+ x, |+ U0 M' P        在main函数主循环体内,进行喂狗测试,默认是10微妙喂狗一次,按键0停止喂狗,按键1间隔10毫秒喂狗,按键2间隔1秒喂狗。注意前面计算得知0<t<117.9648ms内喂狗有效。按键1间隔10毫秒喂狗主要考虑到按键按下及松开时间效应问题,因此不能设置太大,否则可能因为按键动作耽搁时间太久无效。在实际项目中,我们通常会采用独立线程持续喂狗,各种异常触发打断喂狗来设计。
4 i( H, I7 f6 I" t$ ?( `
  1. /* Infinite loop */& r# q  p! ^! Z7 j, k& g
  2.   /* USER CODE BEGIN WHILE */
    8 V- C5 `9 ?* a1 }
  3.   while (1)6 B9 E3 E$ k- W2 E9 U$ R
  4.   {
    0 D) x2 l6 @( l/ e# c5 \( L8 J
  5.           if(1==wdt_flag){
      R; {, N4 u+ F- b- V' L9 v
  6.                   HAL_WWDG_Refresh(&hwwdg);
    * c' g/ ]6 P: ~1 W4 m
  7.                   delay_us(10);//等待" m5 f, g0 i6 W& Y1 ~4 \  w
  8.           }  n; a$ f4 j0 O/ h* a8 y
  9.           if(2==wdt_flag){7 }& E) ^, }+ b0 L# m( C, ]
  10.                   HAL_WWDG_Refresh(&hwwdg);, V) |! Y; z0 z- b) k3 `1 T1 k2 S1 R
  11.                     delay_ms(10);//等待
    8 s2 ], v- o* s9 x. d- I, N& v
  12.             }+ e* C* k7 T- I  f4 O( B
  13.           if(3==wdt_flag){0 v- w* O* e/ M: z( ~! o, E. W; g( H
  14.                   HAL_WWDG_Refresh(&hwwdg);7 a# Z3 R% \8 C5 X' L) a0 w. b
  15.                   delay_s(1);//等待# e! ]6 W9 m* `
  16.           }
    . y" U9 k5 ^% l$ [, j. a( c* ?
  17.           if(printf_flag)
    3 B$ w- n; [' K  Y& \
  18.           {; c7 b7 m% l' e% W; d
  19.                   printf("current wdt_flag=%u!\r\n",wdt_flag);
    . P! N8 B- N' N# P8 O
  20.                   printf_flag = 0;: C5 Z  e9 T5 q- S7 M7 Z% q
  21.           }
    * X& R& n# D6 L! _, v
  22.           if(KEY_0())- \+ ]& G9 d  m! [+ _$ N" }
  23.           {
    # V; x! t. g/ T0 h: I4 S3 J
  24.                   wdt_flag = 0;. h  O0 S& a; b( ]  g. u! [
  25.                   printf("WWDG_Refresh stop!\r\n");/ I( U1 E; Z1 V0 b. u
  26.                   delay_us(1);//等待
    7 W7 b' `* _, x% Z
  27.                   printf_flag =1;
    ; r" @) r9 U/ {- E
  28.           }
    9 i# d# M: W* d4 I
  29.           if(KEY_1())# z; k! _  i6 E4 t4 [2 j7 B
  30.             {
    1 y8 S* j0 P1 o2 v1 b
  31.                   wdt_flag = 2;- G& y$ m) l: Y; W" h! {; m+ P1 A
  32.                   printf("WWDG_Refresh before WIN Time!\r\n");7 N! h; P/ H# g4 R! h- ^0 k- y) E9 L
  33.                   delay_us(1);//等待
    $ O0 H: ^; [6 n: D# t
  34.                   printf_flag =1;
    - U/ J' U# |1 M$ `2 J" T& `5 h8 y
  35.             }
    " o2 ^/ n7 e0 q- W1 H! ~
  36.           if(KEY_2())- O2 K& m* o7 k
  37.             {+ I. q' v: q$ \, f! H
  38.                   wdt_flag = 3;5 t5 O7 j) \" A% n5 t8 I
  39.                   printf("WWDG_Refresh after 0X40 Time!\r\n");6 b$ @$ k# f$ K. t; p* O0 Q4 f
  40.                   delay_us(1);//等待
    6 p5 T0 m& _  j) N1 s) s
  41.                   printf_flag =1;
    8 }9 k# P6 j* Z8 t2 K1 F* H: S
  42.             }
    - Q2 A5 h7 F; l" j
  43.     /* USER CODE END WHILE */
复制代码
: G, Z3 U) Y# Q8 a! l
四、编译及测试/ M( U% k1 G, y8 n: Z, r
        4.1 编译
& ?7 }# ~7 V4 n  w
8 R# U$ T& ?# r2 h0 m4 l/ X' E: p
d6fbffd0d40342e296933a45a64771c8.png / S/ f" k. i4 d6 p: d
2 t1 G4 \8 t. o6 o% W0 [

7 [" G) Y: l: U% z! c9 L         4.2 测试

4 R  h  ^: X7 b; @" f        打开串口助手,连接上开发板,按键0、1、2观察效果:# Q6 u! S" {7 a  W, \2 F* o" t- P) i
  T/ R& [/ a- u# P
5886dd71a550426786ef791de6427f51.png # X1 e9 h0 E1 h

1 Y+ s" X, Y) ?, ^7 Q* x4 b; }————————————————
3 D7 Z. N! ^/ i  ]1 i7 e. B版权声明:py_free-物联智能
% `0 S/ r% b3 U. q如有侵权请联系删除
) J8 Q! F- m* b+ S7 S, p/ R: d2 O8 }9 _+ M. h# T! Z! o" k1 c

1 f9 g! L( Y2 i
013d642e04b445829bf93b4b52820792.png
收藏 评论0 发布时间:2023-4-6 15:13

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版