概述* H* \( L7 s3 v+ ]2 Z
系统窗口看门狗(WWDG)用于检测软件故障的发生,通常由外部干扰或无法预料的逻辑条件引起,导致应用程序放弃其正常顺序。 看门狗电路会在编程的时间段到期时生成MCU复位,除非程序在T6位清零之前刷新倒数计数器的内容。如果在递减计数器达到窗口寄存器值之前刷新递减计数器值,也会产生MCU复位。这意味着必须在有限的窗口中刷新计数器。WWDG时钟是从APB时钟预分频的,并具有可配置的时间窗口,WWDG最适合要求看门狗在准确的时序窗口内做出反应的应用。" n1 N+ \# r2 r/ D* _! X5 M
2 Z3 U* Z$ D2 f1 O! q. ~5 {主要特性
! P$ V* |" e: E激活窗口看门狗后,如满足如下条件则重置芯片:
/ ?- _) \; c6 e/ ^) y# M4 V
4 |( O$ _- ~3 K( n5 n+ w1 N当递减计数器的值小于0x40时
3 n/ P& F1 ^" ^- g0 |6 `4 A. `5 m; {窗口值外重新加载递减计数器- u8 M8 ~' A' T- ~0 M& w% a
如果启动了窗口看门狗并允许中断,当递减计数器等于0x40时产生提前唤醒中断(EWI),可以被用于重装栽计数器以避免WWDG复位。
$ x+ l# ^+ y. x3 e, @
+ A- D% @2 t. L' V5 G5 e3 G用法
0 l: H3 t; O! s* i& K如果看门狗被激活(WWDG_CR寄存器中的WDGA位置1),并且当7位递减计数器(T [6:0]位)从0x40递减到0x3F(T6被清除)时,它启动重置。 如果软件在计数器大于窗口寄存器中存储的值时重新加载计数器,则会产生复位。* D* D H0 z& {/ a6 D9 X: R2 e+ c
# }% E' k1 I: V! _7 U+ T+ O" h- [/ o
在正常操作期间,应用程序必须定期在WWDG_CR寄存器中写入数据,以防止MCU复位。 仅当计数器值小于窗口寄存器值且大于0x3F时,才必须执行此操作。要存储在WWDG_CR寄存器中的值必须在0xFF和0xC0之间。: E2 Z& P- ]- H- l6 p. F5 L# ]/ t
* R( M% Z6 l& j) y框图
: w9 d8 M5 E: _. ^5 J' M) i
- h4 S4 }; E! o, p/ G. }
+ L* z9 @' b1 A1 M0 A- g4 O5 X4 P& D2 |, O1 g/ R7 `, ]
启用看门狗) C3 {2 B0 N9 K. A. B/ r* V9 V$ K( B. H
当FLASH选项字节WWDG_SW选择“软件窗口看门狗”时,看门狗在复位后始终被禁用。通过将WWDG_CR寄存器中的WDGA位置1可以启用它,然后只能通过复位将其禁用。1 ^; {$ Z9 i, O. `3 j, F
当FLASH选项字节WWDG_SW选择“硬件窗口监视程序”时,在复位后始终启用监视程序,因此不能将其禁用。 6 J3 d" H- ?" R5 C
递减计数器用法
0 u3 l3 J2 u% T' E该计数器可以自由运行,即使禁用了看门狗也可以递减计数。 当看门狗使能时,必须将T6bit置1以防止立即产生复位(即T[6:0]大于0x3F);8 ]9 L! v& O' Z' ^7 s0 ?4 ]$ i, b7 H
- P/ P7 U S. d' S% q/ B* {为防止复位,当计数器的值小于窗口寄存器的值且大于0x3F时,必须重新装入递减计数器。 下图描述了过程:* U7 S* Q8 h- T2 I
$ U/ d( L0 E0 C$ j" n
% W# _, x; u) |
# Z8 o3 Q& h: e
提前唤醒中断(EWI)
3 _4 k/ o) |9 O* l/ p. B3 N& i" v# N: I2 x
通过将WWDG_CFR寄存器中的EWI位置1,可以使能EWI中断。当递减计数器达到值0x40时,将在重置芯片之前生成EWI中断,相应的中断服务程序(ISR)应该重新装入WWDG计数器以避免WWDG复位,然后触发所需的操作。通过将WWDG_SR寄存器的EWIF位写为0,可以清除EWI中断。当无法处理EWI中断时,例如由于较高优先级任务中的系统锁定,最终会产生WWDG重置。# L& q, a0 D% I& q
9 R8 o+ s1 |( }8 H6 A计算超时时间 a. K; z0 t" L; { g+ H7 C
& ]9 X+ G' k& V0 G( U6 m- u
p# b: v* ~! l5 x, f2 C% e/ ^: H1 s) J& ~0 i8 V$ O0 y5 p; q/ Z3 ^
如:当APB=48MHz,WDGTB[1:0]=3,T[5:0]=63时;. m3 N' ]7 k) a1 w, S L+ ~. Y
& M J7 }" J- n2 N2 ~) L( X$ B, {% m( f2 V. G5 r6 x& i
: N& u" C0 L- O0 h寄存器
' p/ }2 n# E, F! o" D寄存器可通过半字(16位)或字(32位)进行访问。
+ L2 T# D! X q3 }% S+ F
! C$ S0 J$ i) L8 Y/ Q 控制寄存器(WWDG_CR)* ~, s( ?) ]+ K3 S
h, M; @) W- c- k; I+ Z! V: `; p
偏移地址:0x000 r; A; E' c0 T4 F2 T2 ]
, q2 K( |1 Y* s# V
复位值:0x0000 007F2 ]8 i- l( u7 B# }+ r4 B6 ^# E0 M4 W
! V$ C& h6 P! p- @1 y8 k
BIT7:WDGA(r/s),启用看门狗。由软件置1,只能通过复位让硬件清0。0:禁用看门狗、1:启用看门狗
$ b2 @4 [: I- k. P! H9 z; b" c" P- P# {9 g/ P$ m" v9 M. x: `
BIT 6:0:T[6:0](r/w),7位计数器(msb to lsb),当值从0x40减到0x3F时产生复位(T6bit被清除) U% d/ s" p ?( o6 J
9 T& a& O+ d. f l" b, i( T; y* s配置寄存器(WWDG_CFG)
" ~' o" o3 ^2 U: n' L8 `! T+ s6 G& i/ Y* E- n
偏移地址:0x004
8 c2 Y8 S0 s- q/ h3 s6 s, L, L6 b9 H2 b
复位值:0x0000 007F
6 o5 K; \ D3 j3 b5 K/ c$ O0 V- i( c8 d% \
bit 13:11 WDGTB[2:0] (r/w),时基# x. P8 r( @$ ~ s* x) W# e5 E
4 v' \: m2 b# t) X2 i
000: CK计数器时钟 (PCLK 分频4096) 除以1! G$ F/ K# r: D/ n5 J
001: CK计数器时钟 (PCLK 分频4096) 除以2
- }4 Z y. \ ?5 _$ }. |0 I010: CK计数器时钟 (PCLK 分频4096) 除以 4
4 J3 s( L/ i5 ?- e011: CK计数器时钟 (PCLK 分频4096) 除以8 H9 w& i) X" K# {; s# O0 m3 L
100: CK计数器时钟 (PCLK 分频4096) 除以16
% Q6 x5 D% G) P9 j0 M) ]) `$ P101: CK计数器时钟 (PCLK 分频4096) 除以32
( A+ |; ?/ M9 k/ \110: CCK计数器时钟 (PCLK 分频4096) 除以64
$ E% p( A/ Q9 _" [4 O' P3 D3 s111: CCK计数器时钟 (PCLK 分频4096) 除以128. s1 a3 z3 Z$ T0 n# F, U: r
7 @% W4 {' D Z& P5 t8 V# Ibit9 EWI (r/s), 提前唤醒中断位,置1时,只要计数器值到0x40就会发生中断。该中断仅在硬件复位后清楚。7 G0 \, B$ x& g" \" @; w8 _
5 ^- ^3 ^% N; [, bbit6:0 W[6:0](r/w),7位窗口值,用来与递减计数器比较的窗口值。( g0 f& J! s( T% _1 t
' m& U3 b7 f1 ?. _7 {: E. }
状态寄存器(WWDG_SR)
% R8 \* i% M9 o! v2 ]2 T: p9 m6 Y4 K0 I) J3 D
偏移值:0x008( r4 S" N; O: n$ v, X
% t* g$ o4 G$ y# Y' U! e
复位值:0x0000 0000
2 Z* \& b1 J, i: ~* N: m$ U j# _$ N/ v5 j! k6 j/ e
bit0 EWIF(rc_w0) 提前唤醒中断标志,当计数器达到值0x40时,此位由硬件置1。 必须通过软件将其写入“ 0”来清除它。 写“ 1”无效。 如果未启用中断,则该位置1。
7 S# [- K+ t6 S5 Y1 B1 B& {, t1 B, \( Q, }# ^( j" T" w6 M8 l
实验示例
( T! c' { ?6 W! u5 f1、开启调试接口、HSE, E" m) `: G9 o
; f( v7 t; S% `' r" c5 h$ O
+ X* y s \4 W/ b( T, ^% x y: J( l, d
# \; t8 s: `- i: a0 ~
1 B- P4 m3 a! d" P4 [& i+ T5 H8 J! A) Z5 T& w7 p; v
2、 PA0设置为GPIO_Input,在NVIC中使能看门狗中断
7 q: e, [& z( f9 ~8 ?6 i2 A: u# d
; B$ h0 p! P6 ^" [, a, s$ \+ ?
8 g* Q, J! W, b7 L2 o% Y {
3、使能USART1,使用异步模式,波特率115200,8,none,17 S% ~) |, t7 J% e
5 n0 I" t! B+ u. z. W1 x
& S8 M* h8 f6 o2 L3 N3 R/ l5 A* W3 A8 M8 v7 p8 W
- Y4 o7 ?( a/ S! L+ e& j& F+ ?
, W' \% Q' f8 z$ F2 W4、激活WWDG,设置分频系数128,窗口值(64~127)=64,计数值=127
6 o* N0 b$ f# e4 J9 B. |
, E9 l( n0 H6 \' I3 g b2 Y& r" u% ^/ M! e
& }. V9 a4 Z8 J2 v/ K( i3 [5、设置时钟树,HCLK=64MHz、PCLK=32MHz
# ]3 U2 V% _; ?! G9 ?+ P9 R! V* @$ H) w7 Z; H7 O$ S
( E* R( U t4 U! E/ v9 @+ k& Y3 m: W! p
6、利用上面的公式,计算当计数值T[6:0]到0x40的时间,引发EWI中断进入喂狗的时间
& o5 J6 O8 a. I4 F
9 s$ w0 W; z' L =1048.576ms$ z! b% \3 t3 c' y9 e4 _
. m# T, k" A( f
即每1048ms喂一次狗。
# } Y( G: x+ c) x- r% x+ {/ W, }9 Z+ B
7、设置工程文件属性,生成代码。& f$ ?0 O+ v$ \# j* k
8 g ?; Z- X+ o' N @
$ g1 t0 h1 n0 }3 V- l) P
( [' h# k: A: c! N7 K/ d& V- b+ g' V E4 E6 e3 o% m
$ m# i0 Y+ S; o4 t g0 A/ T1 B
; i- m$ S) I: ]7 A3 |' h) _, Q4 m3 s* q: C
% n9 L" \8 k; R1 V. W e
" ^! x2 S U! x0 s1 W$ @* I d. }代码
0 y& O8 x) v" J3 {% `1、在USART.c文件中加入串口打印代码5 L0 s6 f" C9 |0 ~
- /* USER CODE BEGIN 0 */
- k6 G8 l4 r3 ?% p2 @1 K( _ - #include <stdio.h>
3 C) _9 v# f: y l2 @8 M2 i* B - #ifdef __GNUC__4 d& j7 D1 a: W3 a1 n
- /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf3 M& X; O/ w9 u' N; ]" {
- set to 'Yes') calls __io_putchar() */
# ]4 c* e0 i& Y4 R4 _ - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)8 y* H# J! M4 w! I$ T% n* x
- #else
5 M2 N# F6 e$ V6 l {% p( M - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
; D% U1 ^) ?( w6 L X - #endif /* __GNUC__ */) S* [- {5 _1 L2 }
- /**
2 H! b/ C2 ^2 {' g - * @brief Retargets the C library printf function to the USART.- a+ H% `; B T& V
- * @param None
2 R6 u6 Z) {( e4 _: M4 L - * @retval None
# a5 Z& ~5 X6 z/ t$ ^ - */
8 f! A+ j4 p4 _ - PUTCHAR_PROTOTYPE
1 i# U7 ]7 Y( n; G( e7 N - {2 M# G+ g( x" l; B4 N
- /* Place your implementation of fputc here */
, Y2 H+ u9 C8 o7 J9 d6 ~ - /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
6 a$ u" L+ a2 ]. n4 O - HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);; r, \" h3 x; B
- 2 Y! ]9 N# J$ q( j/ x5 ?/ r
- return ch;+ W6 \% V5 b7 G
- }6 u! e( J2 }; J! {7 r$ u
- /* USER CODE END 0 */
复制代码 ( X4 _" a' M7 p
2、在main.c文件中加入开机打印代码,1 o7 @- S/ I! H# }
% X# W( [; {: A7 l: d5 F/ `5 b) K
- #include <stdio.h>+ m$ _6 b) s0 l3 K; _
- MX_GPIO_Init();
/ H4 ?% p6 k9 P( ~ - MX_USART1_UART_Init();! T! I/ g+ {8 _8 I$ }0 p
- MX_WWDG_Init();
- V" y" e- m4 ?5 Q5 p: V9 W - /* USER CODE BEGIN 2 */% v; I1 V" p$ ]# j9 i9 a3 U/ Q0 K4 ?. |
- printf("...RESTARTing..."); //开机打印
% v! v8 E. N- l1 G# m - /* USER CODE END 2 */
复制代码
! U) {; _8 l/ ]7 B, N- u4 k加入EWI中断代码
3 T, N& ]' |5 _: u; N; Q8 k' k& Z9 J5 i0 j" A
- /* USER CODE BEGIN 4 */+ b2 U( t n- y0 k% ]
- void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)% Z+ ^1 q; H9 C
- {6 }7 w( l; z8 u* b2 _
- /* Prevent unused argument(s) compilation warning */
7 |2 j& j+ W) m4 @ - UNUSED(hwwdg);
1 ^- W: j7 q ~. L; d9 T! R - if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)) //检测PA0是否按下,按下就喂狗
# Q0 |7 U2 [- k$ L: e - {, `/ T! L. l# c' ^6 v1 Z3 R: {6 S
- HAL_WWDG_Refresh(hwwdg);
( s. X+ L! G; j; @ - printf("Refresh,OK");
0 q! V9 M1 r* x6 t7 x7 v - }
# G8 b6 k7 ^. q( V - else
# B0 A: X4 s6 K3 l7 o U - {
% n" V2 t1 E6 }1 F( P2 p* k: ` - printf("Fail");
6 V5 r$ K8 ^" l+ O% a. l# A: ] - }
) V. c9 q' _% j5 Z7 D - __HAL_WWDG_CLEAR_FLAG(hwwdg,0); //清除中断标志* ^3 W6 Q3 z$ u+ F4 P8 v* i
- }2 R) b2 V& J0 m! ]; Y
- /* USER CODE END 4 */
复制代码 # `/ p( C5 H, ~7 {* O7 d
3、编译,烧录之后就看到效果 V' C5 F; _1 h( y: P0 M+ _
5 z1 ~& @6 L" [( S8 U$ k
6 a+ L5 \9 Z- w+ y2 }4 D) O' o9 _ P, O0 k$ d9 q( U
. r7 O0 w. i2 A( U0 O
3 n+ \0 B4 B2 e% k& c! M* S/ f |