概述
, e7 i3 |6 F% A/ J系统窗口看门狗(WWDG)用于检测软件故障的发生,通常由外部干扰或无法预料的逻辑条件引起,导致应用程序放弃其正常顺序。 看门狗电路会在编程的时间段到期时生成MCU复位,除非程序在T6位清零之前刷新倒数计数器的内容。如果在递减计数器达到窗口寄存器值之前刷新递减计数器值,也会产生MCU复位。这意味着必须在有限的窗口中刷新计数器。WWDG时钟是从APB时钟预分频的,并具有可配置的时间窗口,WWDG最适合要求看门狗在准确的时序窗口内做出反应的应用。2 R1 ~6 E, M% V: I4 K1 R. y }
- B2 m* n! m9 t7 e4 Q
主要特性
( a H4 B* R& t0 j% R- Z A激活窗口看门狗后,如满足如下条件则重置芯片:
7 i2 Z: i! I8 ^$ b `5 [% S- `# y' D/ J7 a9 W4 G( b0 d" z; X
当递减计数器的值小于0x40时
$ E3 O& D: n; B' r/ M; p7 a窗口值外重新加载递减计数器
; }, K5 c5 T# L; j如果启动了窗口看门狗并允许中断,当递减计数器等于0x40时产生提前唤醒中断(EWI),可以被用于重装栽计数器以避免WWDG复位。
8 `# S5 @6 M$ {$ h0 y4 _& f
9 I3 z4 ~, @1 l0 Q4 J! { r! {用法
% I- b, v: l# s; T, u+ g! T# l2 w如果看门狗被激活(WWDG_CR寄存器中的WDGA位置1),并且当7位递减计数器(T [6:0]位)从0x40递减到0x3F(T6被清除)时,它启动重置。 如果软件在计数器大于窗口寄存器中存储的值时重新加载计数器,则会产生复位。/ z, A+ V4 ~. P$ ?: [" V6 A' ~7 i
, ~0 t; w: j _
在正常操作期间,应用程序必须定期在WWDG_CR寄存器中写入数据,以防止MCU复位。 仅当计数器值小于窗口寄存器值且大于0x3F时,才必须执行此操作。要存储在WWDG_CR寄存器中的值必须在0xFF和0xC0之间。
* m4 g$ E8 ^# U6 e. Q4 f( O3 Q; `0 J( a! Z/ G% C
框图+ R$ w' ~% R1 ~# h
( r8 I6 p+ N2 I3 ]
! E6 L# [! K' G# p4 L/ l
; o/ D! `# U9 t( W3 F. B4 M. b2 u启用看门狗
7 c0 m. r' E, P. H+ z6 X- s. N当FLASH选项字节WWDG_SW选择“软件窗口看门狗”时,看门狗在复位后始终被禁用。通过将WWDG_CR寄存器中的WDGA位置1可以启用它,然后只能通过复位将其禁用。
% b0 q! a+ j* K当FLASH选项字节WWDG_SW选择“硬件窗口监视程序”时,在复位后始终启用监视程序,因此不能将其禁用。 3 @- k, q0 J7 j4 D: w
递减计数器用法
' B' g4 W+ B9 E% u$ e) y$ Q该计数器可以自由运行,即使禁用了看门狗也可以递减计数。 当看门狗使能时,必须将T6bit置1以防止立即产生复位(即T[6:0]大于0x3F);
, o; v6 f" F' A* K
7 F8 u7 S2 D7 M) i6 q为防止复位,当计数器的值小于窗口寄存器的值且大于0x3F时,必须重新装入递减计数器。 下图描述了过程:& q* k: u' R5 I6 g. V
+ I+ O$ l j- F# D3 R. U) T7 s) G1 I) V
0 X* I# I7 y1 |' ~) { 提前唤醒中断(EWI)
% O7 D" @) L( c* a) ]- s& f" E A
; t4 n |" i8 _8 R3 V0 L 通过将WWDG_CFR寄存器中的EWI位置1,可以使能EWI中断。当递减计数器达到值0x40时,将在重置芯片之前生成EWI中断,相应的中断服务程序(ISR)应该重新装入WWDG计数器以避免WWDG复位,然后触发所需的操作。通过将WWDG_SR寄存器的EWIF位写为0,可以清除EWI中断。当无法处理EWI中断时,例如由于较高优先级任务中的系统锁定,最终会产生WWDG重置。
3 o" ~7 Q: L% l3 ]$ u) S3 E6 d1 M6 I* `4 B6 V- c
计算超时时间
/ c3 j, L3 ^% h: M& v7 z, T) Q5 u: ?: M5 u* M! [# Z( ~
; A V$ [0 P1 I2 b8 a$ N1 D5 {
% x5 ]- X: i' S# a2 l如:当APB=48MHz,WDGTB[1:0]=3,T[5:0]=63时;
% z6 ^/ E$ v) J) W6 g
4 `' D( m; @0 p( g# R+ r R
$ D' Q; i8 N' ?% |# u
; `' m. f: c( s寄存器
8 O' l d( `4 V! O5 \; U8 D3 r寄存器可通过半字(16位)或字(32位)进行访问。& e& b! t; u7 }+ u: D7 e0 @4 u0 B
; z! j7 U$ t' r5 J7 D# j. u7 M 控制寄存器(WWDG_CR)% I& p6 B- T; u' ~5 A& f- _) a
5 l$ p* _6 u' g# z" I, i
偏移地址:0x0002 Y) O: G5 o, @: v% t }8 r5 `
5 V. {+ d& Z: x! l! }# ^复位值:0x0000 007F
3 O4 V6 t' y3 b* }
n( g* A& P9 lBIT7:WDGA(r/s),启用看门狗。由软件置1,只能通过复位让硬件清0。0:禁用看门狗、1:启用看门狗
7 j0 A" r' J( t; K1 V6 w1 E- a0 W9 ]2 h$ v3 Y' F
BIT 6:0:T[6:0](r/w),7位计数器(msb to lsb),当值从0x40减到0x3F时产生复位(T6bit被清除)! W" f- i. _6 h# X2 x0 V
, J T! q* T0 S7 ]配置寄存器(WWDG_CFG)7 R8 A5 m y, w, D1 V8 k
+ D; C3 \ _- o u$ G
偏移地址:0x004
! W( w% i: I! I$ j. [8 D
7 i/ e X$ b, L8 E& H$ ^+ O复位值:0x0000 007F+ h1 G3 i0 f+ P' Y X
7 a9 y4 a' o- U0 Q
bit 13:11 WDGTB[2:0] (r/w),时基
4 E# E# S. u5 |; h; y4 \5 J6 s: I' L$ Y) S0 T# U! Y" ~' n
000: CK计数器时钟 (PCLK 分频4096) 除以1
! K4 b( I! d! x2 r. F4 J$ b4 Z001: CK计数器时钟 (PCLK 分频4096) 除以2& u$ l+ W4 u, T! @: H6 F+ J4 j
010: CK计数器时钟 (PCLK 分频4096) 除以 4; S7 d \% j$ o: O4 f5 l! H0 m l; a; ]
011: CK计数器时钟 (PCLK 分频4096) 除以8
- B- s. G8 t& j: w0 X- K100: CK计数器时钟 (PCLK 分频4096) 除以16 T" Q! \; V- {- p, [
101: CK计数器时钟 (PCLK 分频4096) 除以329 ] v* {0 \& y3 X& p3 `
110: CCK计数器时钟 (PCLK 分频4096) 除以64
% y( h2 j8 x; s" v+ g$ {+ u111: CCK计数器时钟 (PCLK 分频4096) 除以128
1 f' R; l. c9 X# o. j9 K4 E% N& t! G. q
bit9 EWI (r/s), 提前唤醒中断位,置1时,只要计数器值到0x40就会发生中断。该中断仅在硬件复位后清楚。 O- k% E0 Q; D0 H9 m' {6 p1 A9 V4 t
+ y) V% ?' }! _8 n4 @; W7 Obit6:0 W[6:0](r/w),7位窗口值,用来与递减计数器比较的窗口值。9 K* l6 G& Y- K* e* D
$ g; B' {$ O1 ?" T9 x6 h% M3 M状态寄存器(WWDG_SR)
- K/ C. }, W9 m- R X1 C- }& c0 y" T) T
偏移值:0x008/ E6 d* q- p+ T/ N1 |7 Z
# c2 I2 t: T5 a4 }- l复位值:0x0000 0000
" B6 Q6 v8 k. n* s! K
$ c: \/ R% G1 q3 W9 t* Sbit0 EWIF(rc_w0) 提前唤醒中断标志,当计数器达到值0x40时,此位由硬件置1。 必须通过软件将其写入“ 0”来清除它。 写“ 1”无效。 如果未启用中断,则该位置1。. m: r, v9 y% C! i
" N5 o* Y3 z7 F) `; \* B( E2 H# u实验示例
5 O5 H/ e2 f4 \, s/ r8 H7 X: x1、开启调试接口、HSE8 W, v2 K& x- e1 [
" A% g6 W$ J3 G$ i, j
# ?1 a4 W7 r. P9 f _, S
/ t& l/ I3 W5 B" i; q4 z+ K8 c( ~1 N
2 [3 g6 m' H0 b" d1 Z5 U- I0 x4 I: c6 w: k0 |1 d: L2 W0 B
2、 PA0设置为GPIO_Input,在NVIC中使能看门狗中断+ g* V* ]$ E! G. L6 B; \, s% H
5 A" J6 r& h* |
5 Q, x3 F N, b& ~/ O+ W
4 m$ X+ _1 B n3 i0 s& z& S( P3、使能USART1,使用异步模式,波特率115200,8,none,15 U7 @1 K' p3 O( e: v
' v; b' Q# i* o$ q; q. q# u- I
. S8 {1 Z# q8 V' v. T
" d# K& f0 P/ \* D. ?
7 u& v. {/ z) G4 c. B
7 y3 k# C j! m' v3 @4、激活WWDG,设置分频系数128,窗口值(64~127)=64,计数值=1275 i" U+ ?/ a' Y! u4 k& G0 d6 r
- y/ q7 T6 G. F( e: b I
2 _2 ^& t/ ^7 _) L
. G7 d" V* _8 c7 y% Y4 ^! m5、设置时钟树,HCLK=64MHz、PCLK=32MHz3 O; D# `6 r2 g0 K* I. R3 i1 F
3 h4 `: i& [' O$ `# h
+ W8 @2 |8 b2 W" C% a3 Z
) J# e, F3 ~( g9 n _
6、利用上面的公式,计算当计数值T[6:0]到0x40的时间,引发EWI中断进入喂狗的时间
9 ~' w5 J6 @$ D2 x
0 y( b( B/ y0 [' S# W =1048.576ms
* G8 C+ P$ m# s; z9 H# M' h& D
8 f9 ^+ u: K' J( G& {) f3 k即每1048ms喂一次狗。- y6 `/ B$ T1 f6 d8 J
, \; `3 a+ p( K8 M, J' Q6 E( r* L
7、设置工程文件属性,生成代码。 V: t8 _( n ^; z" A- x
* {/ \5 D$ |9 }
7 b! Y" H4 T9 W& b
% T7 L/ | O7 `& I8 i6 j* j3 H
- I1 p- d) Q% G1 t
1 l; B I/ B+ y: f* s0 Q' F3 ]' Z3 y. i; q: V: O
6 g. Z e9 P; [+ `) X/ L2 h) b! h) Q* q8 G0 d! Q
. l; A( I: ^- U H3 ]; u3 d0 d代码
9 h8 v4 P+ z/ f1、在USART.c文件中加入串口打印代码3 }, z8 n5 S3 I
- /* USER CODE BEGIN 0 */
% {, n, P/ W! C+ l$ M3 n) \3 k - #include <stdio.h>
. I6 s8 d1 D/ ~: e, \9 M - #ifdef __GNUC__
7 ~ `! V# V% \! S0 g/ C u - /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf. i, R' G9 c! p! c& s
- set to 'Yes') calls __io_putchar() */
8 t5 i5 f% u6 \9 j6 M5 w1 _, X - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
: L8 n3 B) Q3 }/ P! u - #else4 s# L0 A, r4 k
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)' j% c/ t9 R. a1 M5 T$ S, ^; L# I
- #endif /* __GNUC__ */
$ N4 i9 U }' |# ` - /**
; Y# J9 e w# |2 \9 }* i( k' R - * @brief Retargets the C library printf function to the USART.) c2 [! h) w* O4 o
- * @param None, d* ^& F7 ?( J8 W1 y W
- * @retval None1 R7 ~$ G* ^- }# x( K/ D, t
- */# U2 A7 e" l/ X4 y
- PUTCHAR_PROTOTYPE
8 G7 P' B* A# G) {7 r3 M - {: H( v4 L- V- V1 w+ N# G* Y5 y
- /* Place your implementation of fputc here */
" `- N8 _" k7 V3 Q6 R! B* h# n0 |- } - /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */$ w& F: I% K; R2 _
- HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);! o" D( ?* f$ N3 W& A7 _
- ; P6 w1 ~8 C1 c" f: q; B& c! M
- return ch;
" R( d3 X) i W; v" ?+ r5 ^ - }
; a7 D7 ]" S: q2 ]: Q: f" P - /* USER CODE END 0 */
复制代码 $ J% _( }7 l5 H
2、在main.c文件中加入开机打印代码,
0 V: {4 _7 d( p* C; s4 F e0 s: B* ]+ o8 W
- #include <stdio.h>' r; M n& h' M
- MX_GPIO_Init();
2 ~ ]/ Z# [$ G3 [& F6 j - MX_USART1_UART_Init();
G, b* q. T4 p4 V# ]/ W - MX_WWDG_Init();
4 A( `% n8 V: t0 y( h6 M4 x P7 y - /* USER CODE BEGIN 2 */9 {2 d) u5 x, G, T5 |6 T% R
- printf("...RESTARTing..."); //开机打印- o8 L4 e! |4 j: i! m; k" c9 v/ l
- /* USER CODE END 2 */
复制代码 5 u# A! b( y: n6 Y
加入EWI中断代码
7 P. q) l. B' |% u3 y f* W! W& S4 k$ K) |- T
- /* USER CODE BEGIN 4 */
8 G9 n R; j4 ]& H+ R5 h, ]" h - void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)2 K! p6 A2 F' u* g- u0 d
- {
- _4 z, S7 x; D$ U3 n: M - /* Prevent unused argument(s) compilation warning */
* {7 [+ C( ^' A+ _9 [7 T8 e - UNUSED(hwwdg);
Y! @0 k5 _1 v' w - if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)) //检测PA0是否按下,按下就喂狗
" Z ^$ e5 A; B1 r& I - {
& F1 {& I9 |, P3 }- J* t$ `' O - HAL_WWDG_Refresh(hwwdg);
" O% i8 a' G1 r8 q/ p9 I+ ^ - printf("Refresh,OK"); 6 a6 v. C/ L5 Z' D) \
- }) D7 A6 Q# A* J; c+ g; M8 `: x
- else0 s3 K! n. T9 |% Z0 y R- m- U
- {/ h6 _5 F! ~: m9 T5 R& T# H
- printf("Fail");
7 ]' ~6 z) |$ m& [- \' n( w* n - }
: Y. i! |9 u6 _" R& |$ [0 o - __HAL_WWDG_CLEAR_FLAG(hwwdg,0); //清除中断标志) W" I' u8 S0 M2 }0 k
- }
1 U, z& P+ N# b- l( u - /* USER CODE END 4 */
复制代码 " k3 ?1 L/ W6 f
3、编译,烧录之后就看到效果 q- ?2 _; v9 ]# W, y: ~& q6 n
9 d! B) U7 ] i' X0 ]9 P
" X) t9 m! C0 S+ s9 j, `8 K
) _( O' `2 u% K0 I( E( d( r( u! A4 L& p4 ] f# V, d5 x/ c
( \' y% u' m; _' h; T" O; M: { |