1 概述
* R" S O, O( `2 t7 G7 G1.1 资源概述0 X/ m; m6 c6 i
开发板:ST官方NUCLEO-F103RB开发板
6 z( \) L# l+ U vCUBEMX版本:1.3.0
" O* ?9 e. j7 tMDK版本:5.23
, ?" D9 X$ T& O- }1 P' u J3 m! w3 {主控芯片型号:STM32F103RBT6
3 O9 ?) L( k; T g) d* W
6 H& v; @, D: L- A+ T A& r+ @9 `
6 X' ^; G) M( ]; ^! V, ^/ t/ G; X) _8 a; }, ]' D W9 X4 r
1.2 引脚资源分配- i* s% p7 T' J6 Z& a4 G4 d$ _8 R
/ r5 B4 x8 Q5 \
8 A$ o8 @$ h( r( ]; X! k" ?" ?9 h8 v0 ~2 t9 P6 G6 U; }
1.3 独立看门狗概述) _$ r! V: e8 u' \6 X
独立看门狗可用来检测和解决由软件错误引起的故障;当计数器达到给定的超时值时,产生系统复位。独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。9 Z$ l4 f" o; Y/ v$ J/ {
IWDG的主要性能. d7 X+ n { `! L! T# j# ~/ E) c
● 自由运行的递减计数器 ;" Y; ~! A! k) w: W9 [3 d
● 时钟由独立的RC振荡器提供(可在停止和待机模式下工作);9 o! v) C* f& D$ Y' i
● 看门狗被激活后,则在计数器计数至0x000时产生复位。, m$ n4 Q5 l9 J/ X
: U; X: V7 B6 c) b
1.4 实现功能 J, x9 L2 C! `8 B
1、上电初始化后,LED2灯亮;5 b2 @' h1 Q3 Q% ?& d
2、在While(1)中进行按键检测,若检测到按键,喂狗,将灯熄灭;
9 ?: u* S& x% k8 g6 ]$ N+ x3、若未检测到按键,系统自动复位;
}* Q$ R0 x1 r* G: Z4、采用内部LSI时钟,16分频,预装载值4096(0xFFF)。6 t( \8 O: N x, w. X' f
, q6 c8 T. z$ ~' i2 软件开发) t# R6 ~5 K8 r; s
2.1 CUBEMX配置$ ]7 M' c9 {" E/ i( c+ F! b
时钟配置
$ y7 `$ }# H0 l/ W- b
1 K7 s8 A; C' m* z2 r1 v$ s
. \8 V4 ^5 o k/ J7 l- X/ e激活IDWG,分频系数改为16,预装载值设为4096。
: f. X$ p- |$ \" P2 G
0 A6 l# I: |& q9 C1 T
2 ]9 i5 q. Y: U3 ^
: T* B r% C ^ G6 |1 a ]独立看门狗由LSI提供时钟
9 N- E: x( [5 N7 P8 F' N) X4 } M8 I& L- R
* Y8 T% l5 V: p, ^: o/ [# l' F6 G2 j. w% A
这里可以计算得到看门狗复位时间如下,这个时间足够我们操作按键喂狗。+ a* X2 G) J* C d5 [! F! {) L
t=1/(400000Hz/16)×4096=1.638S
9 y$ f! }/ R4 A9 h n8 K8 B0 Q
: _9 Y( [$ N0 w3 w2.2 代码编写
* B. W) | w; y5 G7 g1、使用CUBEMX生成代码后,会自动生成前面配置的独立看门狗的初始化函数(分频系数和预装载值)。
& I0 m& n5 y" E, ?2 X: l. O) k* @8 \: m0 ?
- MX_IWDG_Init();//看门狗初始化程序
复制代码
0 u r6 u: `0 y& |, A6 F# q下面是这个函数的定义。
! w. x( c Z- u3 f
! I1 J4 z9 A: S3 j Z7 }' [ ~- void MX_IWDG_Init(void)0 p; b; q) Y, A/ G
- {) W' j* t: n% e3 R0 @2 M
* T- p$ @$ [- ? ?- hiwdg.Instance = IWDG;9 w. r5 w) ^3 J/ @
- hiwdg.Init.Prescaler = IWDG_PRESCALER_16;
* y W( m# T" \, F6 p - hiwdg.Init.Reload = 4095;" Z( T. S. d* d9 x
- if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
* f3 {4 \, s) n, k7 U+ a8 V - {8 V! U' x* y! h) H
- Error_Handler();: m$ @7 [- I& }) @
- }8 ~2 E4 r+ v3 I9 R( J
- 4 l( _9 q1 n6 t7 T! V1 |# L
- }
复制代码
7 p; _ w; ^4 I" V我们需要在main函数中初始化LED2灯,点亮。
/ l) E* ]$ c! D! n& I) n9 Y1 A+ s7 k7 C! ^
- HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET);//初始化时将LED2灯点亮
复制代码 3 h, \8 z& C+ r( S' c# S8 O
2、在while(1)中增加按键检测和喂狗操作。当检测到按键时,执行喂狗以及将LED2灯熄灭。0 M1 S" ?4 [0 ?8 |, o
! \* a) e. D9 J; g' q- while (1)
& A. b1 G8 u. y5 v - {" Z4 p/ j: c9 u# O
- /* USER CODE END WHILE */4 i' l, B* u$ M- B* ^+ k
& c( c$ |0 z0 J3 r- u8 c- /* USER CODE BEGIN 3 */) r9 A0 l3 m. P- A2 G2 x; M* Q9 m
- if(HAL_GPIO_ReadPin(BUTTON_GPIO_Port,BUTTON_Pin)==RESET)//假设检测到按键操作1 U8 G0 J# q) Q/ w( j7 w
-
& j; y" d& \* s+ H1 Z7 j: O* a - {
2 u; I5 k! d+ K2 J" d - HAL_Delay(20);//按键抖动检测
* q* F$ l4 _1 Z - if(HAL_GPIO_ReadPin(BUTTON_GPIO_Port,BUTTON_Pin)==RESET)//假设检测到按键操作
) i4 x. D% z3 Y2 u" K% m* s! ^: C/ ` - {
) k' g3 d1 e5 k9 K5 h8 M! G. e8 l+ J - HAL_IWDG_Refresh(&hiwdg);//执行喂狗操作
3 w) a" i* b8 m) i - 4 F* b6 |- C5 J; s1 B
- HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_RESET);//LED熄灭
4 t* }+ c' c% O8 M4 i f q& j D - }
, C1 s; u8 n5 S* I - }
M) ]% p7 v. l; l - }
复制代码 ; h+ ~3 Z) ]5 B# w
这里的HAL_IWDG_Refresh函数的功能是在键寄存器IWDG_KR中写入0xAAAA,也就是喂狗操作。
$ a% s9 R! m- w0 Y7 Q这里的按键检测,是不严谨的,因为按键会抖动,所以这里可能存在喂狗多次,下面是按键检测的函数,加入了while();循环,只有在按键弹起时才返回数据。2 H. F' G" l1 M# W: [& ~7 |
在初始化按键的IO口,切记要注意上下拉操作,如果是低电平有效就上拉,如果是高电平有效就下拉,不配置或者配置相反,都有可能导致按键不可用,或者不符合逻辑。! ~5 p" e3 r/ [ `
6 B/ i! r# \+ v K. k: h- uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
2 |& E! R* h& ?, v$ X( Z$ Z# \7 J7 j - 5 w: c& y2 L( i$ i1 o9 \$ V
- { % j" L8 m6 B$ w7 \6 y7 [
- @' B; f m+ A3 ?) e% K' E
- /*检测是否有按键按下 */
5 Q5 A! X2 i& x) Z
' k7 X. m1 A5 _5 E& [$ P- if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin) == KEY_ON ) : _! p+ Z4 W; u& L4 }
+ `4 Q. j6 n5 h% f% ~- {
7 V1 i2 C+ o3 c5 Q$ c+ n, L! O7 v - ; \/ D- r6 k, Z: |9 a" E% g
- /*等待按键释放 */
! _& ^. ^' \8 i - HAL_Delay(10);
2 @8 F) V% L+ A% a/ @7 H- D, k+ E - if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin) == KEY_ON )
7 }- x. L+ A( z5 k - {' O- r2 `2 {3 T, A. A& p" d
- while(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin) == KEY_ON);
; a% L0 z3 M8 F4 ~6 n0 F- } - return KEY_ON;
5 q& a+ b" \& I4 X7 Y7 p" v. Y - }/ o5 M! m' o) |* }: H7 Q2 I2 c$ A
- " b# ^5 D; j0 i# r
- }
1 _: x: x2 o1 A3 K; l6 ? - return KEY_OFF;
9 w* Z9 W& I. l; D7 Q! w' a$ g% R. S
' x" q% i4 F3 }) R7 } D- }
复制代码
R6 o) I% `3 o; G3 实验结果" {* D9 F( @7 m' S. Y; x
实验结果:未检测到按键时,LED2灯常亮,当在规定的时间内按键操作,LED2灯熄灭。# \& l$ i0 P: u' }
8 I$ R: | \) C' ~
; V/ v( U% T' n5 Z3 _$ Y' F
|