概述
5 H) f: f/ r1 C4 ?系统窗口看门狗(WWDG)用于检测软件故障的发生,通常由外部干扰或无法预料的逻辑条件引起,导致应用程序放弃其正常顺序。 看门狗电路会在编程的时间段到期时生成MCU复位,除非程序在T6位清零之前刷新倒数计数器的内容。如果在递减计数器达到窗口寄存器值之前刷新递减计数器值,也会产生MCU复位。这意味着必须在有限的窗口中刷新计数器。WWDG时钟是从APB时钟预分频的,并具有可配置的时间窗口,WWDG最适合要求看门狗在准确的时序窗口内做出反应的应用。5 u/ h: U c; e# d( k# v
# B" m; D# I* M% }1 _# H6 U1 H主要特性
5 x$ U) h! G$ j6 I激活窗口看门狗后,如满足如下条件则重置芯片:5 B2 s; E/ o( w2 @7 }4 O2 I
9 H2 e8 g. l! B2 G5 K2 x; F' |当递减计数器的值小于0x40时
% }: [# ~; \, h, k窗口值外重新加载递减计数器
4 A# Q$ t) g* G$ a, z. u2 l v如果启动了窗口看门狗并允许中断,当递减计数器等于0x40时产生提前唤醒中断(EWI),可以被用于重装栽计数器以避免WWDG复位。: }1 K" D) }3 ] s
2 w/ t o, m/ {- U, Q用法9 L6 C% w! F% J4 ?( p, u
如果看门狗被激活(WWDG_CR寄存器中的WDGA位置1),并且当7位递减计数器(T [6:0]位)从0x40递减到0x3F(T6被清除)时,它启动重置。 如果软件在计数器大于窗口寄存器中存储的值时重新加载计数器,则会产生复位。( P w0 M% L* k/ d' A1 W
2 }/ R: R, o2 ~- r q在正常操作期间,应用程序必须定期在WWDG_CR寄存器中写入数据,以防止MCU复位。 仅当计数器值小于窗口寄存器值且大于0x3F时,才必须执行此操作。要存储在WWDG_CR寄存器中的值必须在0xFF和0xC0之间。
9 R5 B# w, V, |0 w: M( n- D. \" F6 N* }3 Z* h: M" u, H: E( z
框图
: V. @: K/ u6 d! e3 q" d9 A
' q3 K- d s [0 c' J: w r( {7 W6 O: b: Z8 B; ^
; O. T8 x" e7 Z
启用看门狗
9 f1 s9 N) j {" i当FLASH选项字节WWDG_SW选择“软件窗口看门狗”时,看门狗在复位后始终被禁用。通过将WWDG_CR寄存器中的WDGA位置1可以启用它,然后只能通过复位将其禁用。: o; {9 Q! I3 K$ s! {+ n% _5 l8 I
当FLASH选项字节WWDG_SW选择“硬件窗口监视程序”时,在复位后始终启用监视程序,因此不能将其禁用。 4 o+ U8 H1 o4 x* [. y
递减计数器用法
0 i( X' A8 L* f5 n+ o" M$ y: ~7 d该计数器可以自由运行,即使禁用了看门狗也可以递减计数。 当看门狗使能时,必须将T6bit置1以防止立即产生复位(即T[6:0]大于0x3F);+ p( d/ k( Q' g5 `
2 k; K/ ~" [/ H4 M8 M/ \, Z
为防止复位,当计数器的值小于窗口寄存器的值且大于0x3F时,必须重新装入递减计数器。 下图描述了过程:
% h3 ~3 `% [: }7 h7 d Q# j! v! ^8 o1 O" k5 Q6 K, ]1 Z5 g
6 `0 J1 K0 a9 L: A0 Y! i- L, C; r+ o+ Q/ s3 J
提前唤醒中断(EWI)
* z# ~+ R6 V% f$ a V& k: Z$ B5 t% _2 G/ O! x4 H
通过将WWDG_CFR寄存器中的EWI位置1,可以使能EWI中断。当递减计数器达到值0x40时,将在重置芯片之前生成EWI中断,相应的中断服务程序(ISR)应该重新装入WWDG计数器以避免WWDG复位,然后触发所需的操作。通过将WWDG_SR寄存器的EWIF位写为0,可以清除EWI中断。当无法处理EWI中断时,例如由于较高优先级任务中的系统锁定,最终会产生WWDG重置。# T" ~) y* G, m6 _ ~* x- Z. @
4 P5 Z q6 ]4 E5 _# M
计算超时时间, [; u9 `+ ^3 U+ d. z" O, _
5 Q& t( C1 Z1 N: `! j9 c6 |. j6 [% X( m/ @, G
U6 c& m2 n, O5 O( r9 @
如:当APB=48MHz,WDGTB[1:0]=3,T[5:0]=63时;
& S1 c" Z3 O6 X, t9 K- u8 P# T% q
4 ~7 r, J0 V$ L* O/ K' f
* E/ u+ Y" n( v7 q/ _( V' }: \4 S寄存器& d( H+ {9 y3 L0 z% g
寄存器可通过半字(16位)或字(32位)进行访问。
$ R4 N% _7 Y# j# @" C5 P$ Y. C S X' `+ H5 A
控制寄存器(WWDG_CR)0 }8 R1 l* F! S8 N4 H/ N
) d) x" i a/ t2 y5 f F偏移地址:0x000
# s, B& _( Z* K3 z: e2 i/ t
% b) ?( d9 p4 q复位值:0x0000 007F
6 d/ ^/ Y' A" d9 P1 Y j* T8 z+ I: Y1 h
BIT7:WDGA(r/s),启用看门狗。由软件置1,只能通过复位让硬件清0。0:禁用看门狗、1:启用看门狗
) z7 G# D2 `8 z" [, `5 q9 k; a7 y7 G. b0 H6 t
BIT 6:0:T[6:0](r/w),7位计数器(msb to lsb),当值从0x40减到0x3F时产生复位(T6bit被清除)
# h$ y- t" T B- ^. C8 w* K3 P
# z% X3 I1 W% J/ b配置寄存器(WWDG_CFG); o8 M9 [4 ^# m
$ ^, u {2 I+ u! @$ h偏移地址:0x004
, Z0 G1 o0 c& L# }: u2 I+ c# D
' i3 O$ C- M# \, |4 a1 I8 w复位值:0x0000 007F R' }! s t/ C) i
! y% Q& p3 b0 o0 }1 t1 Tbit 13:11 WDGTB[2:0] (r/w),时基
7 p0 g! P! H% l; w$ w2 j
7 E. D* n6 `4 Y ]8 J000: CK计数器时钟 (PCLK 分频4096) 除以1) W# J! a( r( @* c" e" |) E! Q
001: CK计数器时钟 (PCLK 分频4096) 除以2
& d/ j+ q3 `* g L( @2 k# v010: CK计数器时钟 (PCLK 分频4096) 除以 4
3 m; D( _# h7 i) y; U: M+ Q011: CK计数器时钟 (PCLK 分频4096) 除以8
% ] ~1 J: }, |9 x' I2 |100: CK计数器时钟 (PCLK 分频4096) 除以16
4 v$ t8 h; b, X1 G! ]6 v101: CK计数器时钟 (PCLK 分频4096) 除以328 \ p& y# Y% |8 Q3 f" Y6 M V
110: CCK计数器时钟 (PCLK 分频4096) 除以64
$ ^3 M2 b3 `# E- x0 j3 j111: CCK计数器时钟 (PCLK 分频4096) 除以1285 m/ Y7 t8 @; C) ^( p% v: x
1 T* w0 d8 |; I1 Ibit9 EWI (r/s), 提前唤醒中断位,置1时,只要计数器值到0x40就会发生中断。该中断仅在硬件复位后清楚。
! ^9 B6 a8 m& e: U3 h' \6 L W+ I$ L! x
bit6:0 W[6:0](r/w),7位窗口值,用来与递减计数器比较的窗口值。1 X0 X5 e% i( O+ f
9 u* Z, l2 V5 I8 i状态寄存器(WWDG_SR)
0 h* p" o2 \8 q0 {+ b" m/ O
( G% }9 v5 r( S R/ P- ]偏移值:0x008
4 a; i" }) M; ^
, n: z+ S6 K' D: |复位值:0x0000 0000
# d+ @# F! Y& X$ s0 L* Z- J1 u+ h, d
bit0 EWIF(rc_w0) 提前唤醒中断标志,当计数器达到值0x40时,此位由硬件置1。 必须通过软件将其写入“ 0”来清除它。 写“ 1”无效。 如果未启用中断,则该位置1。' L# D$ t2 U: ^; X
' L) ~! l) O( W' V4 @: d实验示例* m+ o2 A* D# z
1、开启调试接口、HSE# B6 @' E* F8 q- C+ ~( c. ?/ `
5 Q) j- p9 C$ [' `$ p/ k% P# a
4 A- j7 [" }8 n8 F1 ^0 y" p! d$ c" q1 b! r; K9 C# {
. n% n2 p/ j) A5 F! s5 H
0 {5 T5 W: A8 x' S
2、 PA0设置为GPIO_Input,在NVIC中使能看门狗中断
8 J2 c$ [6 s2 o. |4 \5 T* @! V
) b0 v }; ]1 A+ s2 p3 W. H# b) v2 Z9 r/ |% X
3、使能USART1,使用异步模式,波特率115200,8,none,1
1 o4 f% G5 J% x4 w* A& a6 s# j, P! P1 k: o z
: r( w. h! K1 l. V) a1 c
" r' U& y! I9 o; @
c7 R" ^! m, V) M/ R
7 s5 W' g2 D! v/ X/ U4、激活WWDG,设置分频系数128,窗口值(64~127)=64,计数值=127
( ^" }, }4 n, w
" n" ^! Y$ `9 n# I. @0 h9 t) G. a& B9 h1 A5 w H* Z1 {5 @3 k$ S
7 Q$ N$ g3 h# P9 X5、设置时钟树,HCLK=64MHz、PCLK=32MHz. Z4 e$ P- ~* i. H9 I% {, s |
! u% }# t; E: {4 B3 W% f; V5 W: r+ s/ h1 N% B, J0 s
* Z0 ^$ A; G* p$ f
6、利用上面的公式,计算当计数值T[6:0]到0x40的时间,引发EWI中断进入喂狗的时间
: T: M8 }( L# [( r% D0 n0 A
6 o4 M! J2 u% K5 H7 B =1048.576ms( {- K2 W1 B5 S1 O
5 ^, n7 y* k1 i$ j9 ?# Z9 F/ {
即每1048ms喂一次狗。
: q8 o0 O5 S; N2 w4 P9 X- V l% j; Q v( D: P2 Y: j
7、设置工程文件属性,生成代码。5 b" D% E) t$ y$ P
A' x& Y T+ `) ]1 w' {) k
( R9 Q) b- C# `0 f/ `5 ^' ~ z( N9 u
+ ?/ W, p$ }2 d* }& S* r8 H) e# T0 E, ~ ^
: Q2 l- H* m* W# q' d+ j
) d5 ]# m* @5 ?" Q1 A5 h' s) z
7 _0 U' a n) ~9 q0 x' z
* e# x+ a: q) W* d. R代码 8 [: C8 i. M3 }
1、在USART.c文件中加入串口打印代码$ ]# M! |) a8 a0 K: }
- /* USER CODE BEGIN 0 */
/ m1 ~' ^: `" o$ B7 _ - #include <stdio.h>
; c" S; P- a, I$ ?( G - #ifdef __GNUC__
4 e% J* d5 ?3 Q# W4 a2 B9 c - /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
8 r- I5 q- \' `4 F, }* l - set to 'Yes') calls __io_putchar() */
* {/ V9 Q q& B - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
- [5 I( k- q* ?! o - #else/ U7 L7 I3 J8 H. T
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
* \1 L: @2 J" t8 D - #endif /* __GNUC__ *// Z( E( ~' G; G1 C
- /**
( }+ b! V9 k+ z$ g# l, g - * @brief Retargets the C library printf function to the USART.( q8 g0 U5 p( F7 D: |2 g
- * @param None) ~; g: s g) i- y
- * @retval None8 u' P4 i$ ?! ~$ r0 r8 q, g4 K) Q
- */
t& l, ~/ v2 j. \ - PUTCHAR_PROTOTYPE
2 E; {6 D4 n$ v9 Q" e$ { - {
# N7 B+ i/ G) `' C+ y6 }" _2 s - /* Place your implementation of fputc here */
+ f* v9 B5 d5 a: w - /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
, {; [& K" y7 l/ E - HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
% w1 l& D/ j5 k) o, K - - j; ~& U' G* G, c, r+ }" [
- return ch; d1 }+ i* V8 ~8 c" W
- }5 ^9 k/ V$ ~; J6 |' f8 e4 ]+ @
- /* USER CODE END 0 */
复制代码 5 {. X! [ Q' G" n
2、在main.c文件中加入开机打印代码,
+ X+ J8 v) _% n; t* K3 G P/ d0 b% r" c- ~% A
- #include <stdio.h>& ^' v" K/ h; [0 m$ @0 e" }5 Y
- MX_GPIO_Init();" N" ^4 K+ R/ f, Y
- MX_USART1_UART_Init();% n. E# |# Y2 @! `. V$ U( p2 k; n
- MX_WWDG_Init();, \/ J, d# ?, o" }/ W9 s" [2 z+ c
- /* USER CODE BEGIN 2 */
. ~0 |" d9 n) G7 y6 n l" m - printf("...RESTARTing..."); //开机打印. R$ q: O3 ~2 P8 V0 [, g& T) G) b
- /* USER CODE END 2 */
复制代码
* e; h1 C9 O) `' n* q- C& W2 r加入EWI中断代码
2 }7 x& W2 U) T1 P6 I9 X$ a: _: m! T8 @# r6 p% l
- /* USER CODE BEGIN 4 */5 s4 [3 m9 R% G6 b B. l
- void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
0 g/ {' R9 _6 m1 d - {
R0 i# m: }* S, a0 W$ |. ~* @8 r - /* Prevent unused argument(s) compilation warning */
. Z; H" @( f7 ?- y; t7 G - UNUSED(hwwdg);( p. m K" {9 M! e& e
- if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)) //检测PA0是否按下,按下就喂狗
* p; I7 J% K& U9 A* w1 X* y( g! W - {3 f; ~; k/ I0 T% O0 B+ A" v5 t5 O1 t
- HAL_WWDG_Refresh(hwwdg);
0 x$ l. @" j# |$ r) r2 `( B" O. @ - printf("Refresh,OK");
. b8 {' G7 u2 v p+ ^/ E* Y, f, ?6 @ - }
$ L" q: K$ O- \5 s - else
5 u( t( _( |! W% e' r2 u* d: d2 r - {! z# ?' ~ z" r. N9 D5 M
- printf("Fail");
, K& v( \- R* X+ K - }
( _% w2 y1 f6 o! l/ d - __HAL_WWDG_CLEAR_FLAG(hwwdg,0); //清除中断标志
2 P8 i% ~) Y+ ]& B4 X& V - }
/ o9 x6 m9 }7 U0 q$ @' a- h$ N, l - /* USER CODE END 4 */
复制代码 ; q" J' [0 x: F% x4 x( g, G; m6 p
3、编译,烧录之后就看到效果; s1 W+ V" m& e, y8 q; C' _
' S9 |$ \1 W, e# y9 ~3 W
/ M7 s* {2 F R
4 y S1 b4 y5 e9 v4 K8 o) s8 _% G' @6 Z* T7 x; H0 Q# V& [) m
9 ]( c% ?3 z8 H& y# K
|