STM32F10xxx内置两个看门狗,提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备( 独立看门狗 和 窗口看门狗 )可用来检测和解决由软件错误引起的故障;当计数器达到给定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位。
( ?) Y. ?8 s+ l# A$ @" [# j! B, r6 K Q4 R0 X
独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。' s4 P) Q. K! }. _
6 g. s2 t8 g; A$ G IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序。" U$ t v+ f. ^6 g$ Q* s5 q
/ n. i- f0 b2 @% W* }
看门狗主要是用来对系统运行状态进行监控的,以免系统被干扰后代码跑飞了,导致系统混乱。看门狗的使用也比较简单,下面就分别来看一下独立看门狗和窗口看门狗的使用方法。: \6 v/ |- s5 k; g8 T9 T' Z8 X/ ?
3 L, q( q, q- Y( s6 X独立看门狗
: G2 j1 r5 N2 K0 b2 b/ J' g1 a, K1 U8 a I. J
- //初始化独立看门狗
' m5 W/ x" D" \, b7 x - //prer:分频数:0~7(只有低 3 位有效!)/ B9 n1 R( k- \( c. d* ?
- //分频因子=4*2^prer.但最大值只能是 256!
% i/ J2 x' o, Z2 l, { - //rlr:重装载寄存器值:低 11 位有效.1 w; N- ]$ c1 E4 P+ M% n
- //时间计算(大概):Tout=((4*2^prer)*rlr)/40 (ms).
$ t) A3 _: y8 I7 O - void IWDG_Init(u8 prer,u16 rlr)
) B" p" G8 W8 Z0 d( K - {) g; g' b9 H2 Q& h( | {; g
- // 1、取消寄存器写保护 写0x5555$ ~2 _$ P4 g5 V: i; e: k8 t5 w
- IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);8 x! s' D7 O. h, D+ g: e/ O3 z
- // 2、设置独立看门狗预分频系数
$ M% ]- \+ D1 [2 q I: g1 p - IWDG_SetPrescaler(prer);0 _, b5 U: M, G! J9 U
- // 3、设置独立看门狗重装载值- C( k/ _/ l- l, a5 X7 D
- IWDG_SetReload(rlr);; J' }% g9 W3 ~; f
- // 4、重载计数值喂狗 写0xAAAA
- p6 O, W- b, I6 T- U6 w - IWDG_ReloadCounter();
1 { X, T9 z+ z) U - // 5、启动看门狗 写0xCCCC# Q+ w4 Y+ x& c' J3 v' X/ K
- IWDG_Enable();
; L1 ?/ `2 R# f9 b. \$ F$ _' g$ _ - }
8 \, _/ W* h9 C. @ - void IWDG_Feed(void)9 ]- Z( u- |8 c V. Z
- {
; C8 m2 m3 S* C - IWDG_ReloadCounter();
8 k t- i) W* G( S* k$ W - }
复制代码 . u" D' R; z# D9 x6 U% e
独立看门狗的初始化很简单,主要就是设置一下喂狗的时间。然后在程序运行过程中不停的喂狗。
; O$ U3 k9 c, h& O& i
( M) I$ p& y3 h* E9 M, r- int main(void)
+ o! ~+ S4 P$ Y0 N* x - {4 S8 X0 _3 R) T5 x
- u8 key = 0;
! |! u% u6 f5 Y' p* C/ i - delay_init(); //延时函数初始化
) Y) }- B" v# a( e* U- B; A - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);' [" z& s. o( P1 g3 T% m4 t
- LED_Init();
& u: r4 N: O2 A. ? - KEY_Init();! @/ A/ i) V/ i) o1 ~* ?% {$ }
- IWDG_Init(4, 625); //溢出时间为1s (4*2^4)*625/40=1000ms9 g4 l9 ^* V: S
" T) @: U$ [2 f- LED0 = 1;. x) M- A' ?& m' R" D6 C7 }/ v7 V
- LED1 = 1;
0 n) b5 e0 _5 X0 n7 L2 Z2 ]' I - delay_ms(500);
; b" w9 q5 d. w) f5 ]0 x& b/ N, m4 \ - LED0 = 0;% n# ?( j; G) z
- LED1 = 0;
5 H# {# T0 a- Z" a7 N7 _ - 0 a- x" R4 ]* Q7 w+ |$ @7 A% f/ {
- while(1)4 O. l& K! ?. i2 n" r$ A
- {
4 U) @$ p4 \! O9 ]% t, c p - key = KEY_Sacn(1);7 f- Q% h. {! L. `% g4 c
- if( key == WKUP_PRES)
3 w3 n \+ T' ?5 t+ [0 H( c* [ - {* l7 V7 Z q2 X/ h
- IWDG_Feed();
: P6 j% u. r) S5 S4 a+ T - }
( Z; F$ j" B3 Y1 T; K1 E - delay_ms(10);+ M" P0 B r7 \5 ~) [* D
- }2 q! ^7 @4 D7 T% Y* A
- }
复制代码
, G& M3 l, j- w1 j3 L7 N- z5 k( Z+ I1 h这里通过一个按键来模拟喂狗,当按键按一次,就会喂狗一次。如果按键超过喂狗时间没有按下时,独立看门狗就会使系统复位。
& f/ D9 v: ~( v
5 F+ {' F4 K( ^; @: ~4 I窗口看门狗
9 e1 y" r8 O7 v1 ~3 @, X
+ [9 y4 J0 }7 v, q9 k2 F6 L- u8 WWDG_CNT = 0x7f;
_$ a% h. U# q, M3 l) g3 a - void WWDG_NVIC_Init(void)
% P! ^& n8 T- G - {5 b2 Q: O- E9 k3 Z) [8 A# N7 g
- NVIC_InitTypeDef NVIC_InitStructure;0 ~; a' \% j; P( ~) B' d0 o
- NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;# Q' b/ K6 d0 z& G: Z4 i
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
8 e k* f3 }$ q$ l$ A1 } - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;7 b2 Q4 k0 `. L$ s$ m4 w
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
8 N5 `& B5 o9 u9 X# d6 W - NVIC_Init(&NVIC_InitStructure);+ F+ _* T/ h" {3 L
- }# B& z, g) v# Q& D8 ~- H: ]
- ) _7 O- U7 Y8 [5 w5 J
- //初始化窗口看门狗5 \! l- x: T* O! F# N* ~
- //tr :T[6:0],计数器值
j) O6 o' f# r( h, p+ d1 A" D' R - //wr :W[6:0],窗口值: p. x% |4 W5 b$ l+ v6 q' e
- //fprer:分频系数(WDGTB),仅最低 2 位有效% k% v4 ]3 ]- a7 O l1 b
- //Fwwdg=PCLK1/(4096*2^fprer)
: G, Y: G* v9 ~% c# @, c& m( e1 B - void WWDG_Init(u8 tr, u8 wr, u32 fprer)) B+ y; z# ^: p
- {
" B/ k+ A$ ?0 V1 g - RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //时钟使能0 ]" A& i- g: a
- WWDG_CNT = tr & WWDG_CNT;) V3 d6 x; y) p
- WWDG_SetPrescaler(fprer); //设置预分频值2 ]& |; Q, D8 V' m
- WWDG_SetWindowValue(wr); //设置窗口值 上窗口值 与喂狗间隔没关系* n( n2 o0 x3 Q2 R1 e8 m% i
- WWDG_Enable(WWDG_CNT); //使能看门狗,设置计数值( t8 a/ K0 k: y1 E$ f, P& T: G
- WWDG_ClearFlag(); //清除提前唤醒中断- Y/ C" D7 c$ m6 o& l
- WWDG_NVIC_Init(); //设置中断优先级" y/ h" o% V9 ]5 ?0 ~: O
- WWDG_EnableIT(); //开启窗口看门狗中断7 I! c% r+ n" S0 Y; {# ^
- }
8 `/ B9 Q. _1 l: o$ Z. p' v - void WWDG_Set_Counter(u8 cnt)
4 G* r$ k& _ e8 O+ { - {' z( s$ j( Q4 k& A- \
- WWDG_Enable(cnt); //使能看门狗,设置计数值
/ n! Z7 K4 y& q% {/ E6 V3 g - }
8 o" E6 \; S& i/ h! s' m2 t0 t - void WWDG_IRQHandler(void)
0 s/ ?! i+ {! p( ^ - {
0 b" B. T) K" I/ s - WWDG_SetCounter(WWDG_CNT); //喂狗
0 ]8 @8 K. [6 V4 O6 \8 W- q - WWDG_ClearFlag(); //清除提前唤醒中断
( |0 c7 \9 Y- b6 n9 k9 j3 b - LED0=!LED0;+ Z0 `" d6 f0 u- V& J% N$ V
- }
复制代码
( X( P! q/ t" X* U# F- Z6 P由于窗口看门狗的喂狗时间很短,在程序运行过程中很难判断出什么时候该喂狗,所以这里喂狗使用中断来执行,在需要喂狗的时候,直接触发中断,在中断中进行喂狗,每喂一次狗,LED就取反一次。通过观察LED的闪烁就可看出中断函数的执行情况。* j: [1 L+ r. T! z$ w; ?' Y
9 t+ Z2 D$ }* w5 J$ n7 G, j" Z- int main(void)
' c1 f G* |4 `$ X8 \) A - {& I9 W, E7 e; y* H8 _
- u8 key = 0;
! i7 a" Q& j2 ? T - delay_init(); //延时函数初始化
, K: Q" S* a5 x) ]6 _2 I' q - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/ M* o; ~0 a* M3 L- U1 Y7 u b - LED_Init();
1 e( t }1 c9 j- N' E- F- u9 r - KEY_Init();
& N1 d5 V- x/ p" ^ - //IWDG_Init(4, 625); //溢出时间为1s (4*2^4)*625/40=1000ms
. J+ W- z& Z; F: m" Q& ] - 0 W$ o/ ~# ]% ~+ @" i
- LED0 = 1;! u6 }/ b8 b w7 F! K5 G: d; s
- LED1 = 1; C8 y; y5 p. P+ l! v! ]% c
- delay_ms(500);* ?$ p, c4 T# B2 v) N
- LED0 = 0;
. ]* L6 P3 | |$ f1 e. J - LED1 = 0;6 A; c$ }# ~2 a" S
- ' h1 C, u' q3 z
- //窗口看门狗喂狗间隔 只和 tr 低6位有关 wr 可以设置为0x40---0x7f 之间的任意值
0 S' q! N1 q2 F! T G% G1 p - // 4096*2^3*64/36000000 = 58.25ms (64为0x7f 低6位值)5 N1 H6 p/ I0 U0 l2 z
- WWDG_Init(0x7f, 0x7f, WWDG_Prescaler_8); //计数器值7f,窗口寄存器5f,分频数为8
! @5 z% V" \; H" `1 m -
7 s s% i- W) @7 x# u ~, H9 B - // 4096*2^3*31/36000000 =28.22ms (31为0x4f 低6位值)
G1 Q' i* _: n+ O - //WWDG_Init(0x5f, 0x5f, WWDG_Prescaler_8);. c! I# i# U7 K1 U
- , C" {. T8 H* n6 d
- // 4096*2^3*15/36000000 =13.65ms (15为0x4f 低6位值)4 Q5 O7 R6 y9 H! {& G
- //WWDG_Init(0x4f, 0x5f, WWDG_Prescaler_8);
4 v! H% r x1 s3 Q% c( ` -
) t/ m" A- g; z: { ^& G% v! p - // 4096*2^3*1/36000000 =910us (1为0x41 低6位值) 窗口最小值为0x40
0 G! Z/ v) i8 l/ V - //WWDG_Init(0x41, 0x5f, WWDG_Prescaler_8);/ j# D/ V* q3 Y
- while(1): y1 V, {, `% D' R9 X
- {
: |* U- S7 `: P7 Y+ o* h) z, ^: R/ c. A6 S - }
/ L b- G# E$ E2 |1 K - }
复制代码 ; ^, [8 G |. j/ W2 Q- D
在主函数中通过设置不同的溢出时间来观察LED灯的闪烁频率。
0 b3 [! b8 a) m( u2 w. u* w" ?' t$ I9 B3 R
) |& r- D5 _: L2 f4 \* \
: Y/ G; Z, V/ }2 o* d' i |