一、什么是看门狗: 简单来说看门狗就是一种专用定时器。; |/ Z) D0 [+ A2 \: w9 {- T
9 |2 T9 v. z: [- X3 ]
二、看门狗的功能:
: x" R. }2 M7 F4 }, k5 D3 k$ j8 L. B# S6 v5 W6 ^' Z# t
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) 。1 A2 S/ [' `: T7 _' u+ d
( L! w; _6 U* E. M! H7 y$ i T& ?
简单来说就是在系统跑飞(程序异常执行)的情况时,系统复位,程序重新执行。5 |2 Y% U6 e/ \# B* q0 C
& p5 N% C. g- `三、独立看门狗(IWDG)
6 X" ~3 m' Q' L" ?* a+ ?5 L& I! G) a2 _) w5 p/ m
1、独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它仍有效。
4 ?# C/ q# A# E7 C# V2 N) B* d7 \- K& |# Q; S O
独立看门狗适合应用于需要看门狗作为一个在主程序之外能够完全独立工作,并且对时间精度要求低的场合。! ?. ~ @) R# F p3 e
2 u6 d6 z: C# t% c. q8 t4 D
2、独立看门狗的功能5 {" s3 L7 ]' S* u' w) F, v
1 M0 o, z9 ?5 |
在键值寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗。此时计数器开始从其复位值0xFFF递减,当计数器值计数到尾值0x000时会产生一个复位信号(IWDG_RESET)。
9 G* h7 A! s! p0 f
+ m( l7 W! x! d 无论何时,只要在键值寄存器IWDG_KR中写入0xAAAA(通常说的喂狗), 自动重装载寄存器IWDG_RLR的值就会重新加载到计数器,从而避免看门狗复位。0 \0 a: g" `/ q# v" n
* e: H+ Y7 c# ~8 j4 W2 V
如果程序异常,就无法正常喂狗,从而系统复位。
7 n7 ?$ B: y5 ~! m9 J2 n$ }4 N6 w' W# @- J5 {, r
- M6 c4 ?% E: u. y3 S! b$ f+ n
' Y# Y1 ?. d# ?) I* ? 3、独立看门狗寄存器! B- B# `; q2 U/ Q2 i
8 W, f; i6 {7 e* `" i: [
5 C0 Y1 V7 C2 q4 T r6 V# a
' y# S' D5 F+ h* r5 c ①键值寄存器IWDG_KR:0~15位有效
; P( ?: u/ E) x1 w8 H( E+ B! Q; i- o: s5 s" x
* x% }& n$ k" S: W3 @7 ~
& ]% r; t* z; H
5 U0 l, v- y/ a0 M+ Q7 x②预分频寄存器IWDG_PR:0~2位有效。具有写保护功能,要操作先取消写保护: @3 Q6 Z S4 Q7 O% Y
1 f7 p/ X m+ i- E7 ?
4 S% _- m1 a0 G4 r: U3 O" a
& t" ~( c- s8 ~/ ]
③重装载寄存器IWDG_RLR:0~11位有效。具有写保护功能,要操作先取消写保护
! ]& \$ l8 p, v2 c/ k
' |9 ^4 _& X+ W' o# \, E0 w8 N; F1 x
7 B2 `8 y! j5 F
3 ~# z, r2 i) g p' O. T
. w$ Y7 z0 M- O+ Z2 K④状态寄存器IWDG_SR:0~1位有效$ B; J5 A2 r% l9 q
9 u R, b. Z2 w3 F% i7 N2 F/ \5 L% m$ y2 F/ g8 P6 H( {8 S
4、独立看门狗超时时间7 c9 a' ^6 Y2 t/ v4 q
6 a& h& e0 ?! r+ q5 m
[- H2 t* G( t" }5 P( e: h" I
+ W0 f1 ~5 r) _(适用M4)5 K# ^, w' n7 N( W* K. k
. J2 f+ o( o8 i$ g
溢出时间计算:Tout=((4×2^prer) ×rlr) /32 (M4), j. J( R7 E( }* B9 T4 K6 X( }; T
3 w/ ?6 _1 ]3 r/ d4 q* w x. Q* t 即是:最长超时时间= (IWDG_RLR寄存器最大值)X看门狗时钟周期
* _" o/ \! g& J% f( ^" d2 S1 J0 h1 P: h
注意:M4的时钟频率LSI=32K, 一个看门狗时钟周期就是最短超时时间。
. v; o* F" } z
. Q. }& D7 }0 g, p 5、独立看门狗操作步骤 . u p; I, j1 g) {9 s9 `
9 |. q0 @# m- U8 u: d& Z* t: h# h
- //①取消寄存器写保护:
0 t5 F5 B+ ~4 _* z - 1 i* i" a1 r6 n% S4 N9 `0 F
- void IWDG_WriteAccessCmd(uint16_tIWDG_WriteAccess);//取消写保护:0x5555使能: Y1 A, w7 e6 w5 ^* i7 S: v
- t4 r, I) u' U: l
- //② 设置独立看门狗的预分频系数,确定时钟:4 J+ h" v. U2 w0 E0 D2 j
- 2 K: u" p0 k( I1 a6 a' r
- void IWDG_SetPrescaler(uint8_tIWDG_Prescaler);//设置预分频系数:写PR# D( G% u. b8 G, X3 W
- //③ 设置看门狗重装载值,确定溢出时间:
* Q3 k' p4 y8 O3 H9 I - + o( Y+ F+ f% ^# V1 ]* b
- void IWDG_SetReload(uint16_tReload);//设置重装载值:写RLR5 n A; v$ g9 a
- & e! z3 O7 u/ t# ^( V }
- //④ 使能看门狗7 c& c! W3 `7 v; W ]. k3 `7 d q
P+ h) q5 p$ K$ l5 k1 E- void IWDG_Enable(void);//使能看门狗:写0xCCCC到KR) }6 n9 L( }4 n) F
- ; e0 C0 o$ N+ }' h8 b
- //⑤ 应用程序喂狗:
; |. G: V4 ?# b. c* Q9 m! l - 7 `( w6 n# c# x: r7 H
- void IWDG_ReloadCounter(void);//喂狗:写0xAAAA到KR1 t: p8 @4 A$ ^! }2 L
- //最后: G$ d M, M# D9 ]
- . }8 V/ U5 H; c
- FlagStatusIWDG_GetFlagStatus(uint16_tIWDG_FLAG);//状态:重装载/预分频 更新
复制代码 ) I+ b$ u& _$ P& _7 ?
6、代码如下: X) R3 T1 `7 e0 d9 D
2 L. x2 ~6 ]$ v8 w+ V' U, S5 y- void IWDG_Init(u8 prer,u16 rlr)
9 o/ J H0 f' I - {6 f8 k" i& `( d+ P. K1 n& B* b
- IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对IWDG->PR IWDG->RLR的写! a4 I4 W* U0 i1 h3 q
- IWDG_SetPrescaler(prer); //设置IWDG分频系数# S; l h! x" i1 v4 t* }9 `
- IWDG_SetReload(rlr); //设置IWDG装载值; _- m3 H' z0 o# n% O
- IWDG_ReloadCounter(); //reload //重载看门狗计数值
' K- z+ J$ G/ {: `4 |% Q( E4 ` - IWDG_Enable(); //使能看门狗
- F- v0 t, ] u" i6 }$ L& g - }
& [( C% p- b- z0 W' r/ D
) c2 i' B1 X' V1 U+ g- + C* y5 W+ U& G$ |$ ^6 B
- int main(void): q5 N& \+ t1 Z* M5 H
- {
5 x% P( D7 \ Z8 _$ [& V0 ?2 f - delay_init(168); //初始化延时函数
% z% u/ [7 Z( W( g - LED_Init(); //初始化LED端口0 C8 M( a5 G, U( K, y/ M
- KEY_Init(); //初始化按键
3 _8 C) ~4 r( K, V! T4 F2 W - delay_ms(100); //延时100ms
; p. V' H0 U1 U! C+ y# w ~& R - IWDG_Init(4,500); //与分频数为64,重载值为500,溢出时间为1s9 N% R4 k* H, X
- $ H' x; N% J! h; Y( q
- LED0=0; //先点亮灯
0 k1 q* b$ }: T - while(1)
7 q' N. \' I; T% X - {" x9 p I( y2 I' k+ @# y. ^2 A
- if(KEY_Scan(0)==WKUP_PRES)//如果WK_UP按下,则喂狗% Q! g. g7 g" @, B
- {+ C* }# x3 T& i i8 b% \- f3 W2 Q
- IWDG_ReloadCounter(); //喂独立看门狗8 _: Y8 ?- f# @3 Q9 f1 g( T6 s
- }; t5 F3 n5 p# D" u l5 _( |- k
- delay_ms(10);" e' W7 F4 b3 h9 J
- }
' b9 }4 d: ], E, W8 i i) L - }
8 {& _1 G; ?5 B4 F* _$ B+ p
1 {0 b) u) [. ]3 }- ^& N; B! D- //检查系统是否已经从独立看门狗复位恢复:只需要几十ms3 X+ B3 }; B# n1 O: s0 m$ I
- if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
5 i+ c0 K1 \5 V' B- l0 j+ o - {, S: l' X3 }, [) _3 @0 z
- printf("IWDG RESET OK!\r\n");9 A' N. J4 T, Y* Y8 p O& i
- PFout(8) = ~PFout(8);9 b! x7 L% a) ]9 c, L
- }
复制代码 1 Z: J) j7 n+ z! X: Z7 m
0 i+ H& C/ y* ~+ R( u
& z: A5 v1 Z9 q* V6 V. e M" }7 J8 X' ] p+ a
/ [+ h3 O2 e& l1 q
|