在项目中有时候会遇到单片机莫名奇妙复位的情况,为了判断是那种原因引起复位,就需要对单片机的复位源进行判断。现用STM32F103C8T6单片机进行测试。
3 G; z, R( e6 K; P2 v先看看单片机复位源都有哪些?
2 b; Q% j2 c' G3 }8 P& C* Z' e, Z0 A
E! r7 B7 g! ~
* m- [; [1 l! _+ o, l- P在STM32中文参考手册中可以看到,复位源可以通过状态寄存器来读出。( S( U# U& s& l [4 x# s
于是写一段程序来读取复位状态寄存器:
: @( V/ y4 J* s* W
5 D, I2 m8 n0 [- void Check_Rst(void)
" x' I% l& |5 _4 ?& r - {0 M+ X" B4 S5 I" a% E
- printf(" CSR = %x\r\n", RCC->CSR);7 @! l& @/ f' v6 D9 b/ ]
- if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET ) // NRST 引脚复位# v- ~1 [6 e* Q1 N, }/ \6 c0 y
- {
' g* c$ Z+ a2 W* b6 v; w - printf("PIN reset \r\n");
" _! E1 ]$ a9 Z' ~0 I R9 _ - }6 I9 ?+ o3 }( }3 p% g" N4 ]
- if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET ) // 上电掉电复位
& v! c% H4 y4 N# I$ ^" @' l - {
+ Y2 |# H) ]* b" v - printf("POR/PDR reset \r\n");! |. j9 r/ P" g8 O
- }0 M7 G6 J& z& E! ?
- if(RCC_GetFlagStatus(RCC_FLAG_SFTRST) != RESET ) // 软件复位
0 D s; ^* u- F3 c - {4 V* t; O5 L1 ^# u% f
- printf("Software reset \r\n");: A& U6 s- v& J4 r
- }% B, G$ I4 x: w: \
- if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET ) // 独立看门狗复位' R7 R H5 h! F. R6 F
- {
/ b3 j$ o; _& m- A3 z - printf("Independent watchdog reset \r\n");" `8 D7 |* M! I1 g! \
- }
! w# M( { O$ g - if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET ) // 窗口看门狗复位$ H3 T5 v1 L5 ]8 X& I; `( B
- {
. J) ?4 Z$ _7 S' k- { - printf("Window watchdog reset \r\n");
) a" ~6 o8 E& a! L ~2 M - }
! K( w. T9 I0 g1 m - if(RCC_GetFlagStatus(RCC_FLAG_LPWRRST) != RESET ) // 低功耗复位6 Q2 w0 U8 D+ P- P$ m
- {
; B! L' h7 E7 v0 p$ m - printf("(Low-power reset \r\n");" p P8 [5 }" D5 O# C! m6 @ h
- }: P' K$ R, b4 o2 b# L
- RCC_ClearFlag(); //清除复位标志
/ I8 H& K6 A/ M - printf("\r\n");3 D5 Q/ H# v& e) p* Q
& \/ c9 z g8 M- }
复制代码
T" h \- ~& v' B$ y* U3 W通过串口将信息打印出来。& E* G- a( h" o3 j( z
现在写个程序测试,引脚复位、掉电复位、看门狗复位都比较好测试。就是软件复位要用代码实现。通过查找资料发现软件复位可以分为系统复位和内核复位。系统复位会复位所有硬件电路,包括IO口状态。内核复位只复位内核,不影响硬件电路。( X1 V* d' F4 K4 E9 a" t! u
系统复位实现代码如下:
, j9 u& _ N+ E$ \! K7 R
, v4 v+ B4 K! p- f! F- //系统复位 所有电路都会复位& u) ~7 C; w0 L) d% c. ?8 ?
- void mcuSysRestart(void)
9 H" x/ ?% C8 `' f8 j6 S" K - {3 U9 \- m) ~7 E& n" T" V# e
- __set_FAULTMASK(1); //关闭所有中断+ X8 f0 s% b/ K4 U$ O
- NVIC_SystemReset(); //系统复位 源码见 core_cm3.h 文件 static __INLINE void NVIC_SystemReset(void) 函数3 t% w- h; ^0 O: r4 w: `
1 H3 s4 J1 }* [; \! @. f* z- }
复制代码 & {( Z, _+ s3 ~, s8 t
内核复位代码如下:
9 x# R' n* \8 h& s1 K- y$ X% T- //内核复位 不会影响外设和其他电路
5 j; S- r! U; S) {2 @8 D4 E- }8 t - void mcuCoreRestart(void)
% E* t$ z$ E3 v2 F H - {
5 ]. t2 U2 E V - __DSB();
- E, [. C8 U$ ~( @: L0 s0 ^ - //置位VECTREST
( ~ i2 o. Z6 L/ I - SCB->AIRCR = ((0x5FA AIRCR & SCB_AIRCR_PRIGROUP_Msk) |+ D7 g ?2 D, `. a8 M
- SCB_AIRCR_VECTRESET_Msk);% b9 h G. F1 Q3 O! j. M2 N, D
- __DSB();
. O9 j- U3 M- K. [ - while(1);' Q9 Z1 S5 {/ G
- }
复制代码
/ J7 |5 k' F4 V$ m; V) F0 @( v在程序中通过不同的按键控制不同复位情况,打印信息如下:! h+ H* l9 D: Y8 N; M5 ?7 k' N
上电复位:% A* {& X8 I4 ^% v( [% n! N
# f( i& m8 o% \! D
4 Y; Z. H `/ V. K
1 j" Q! @% m+ F+ }& W7 `/ O; O6 d
按复位键复位:
l" a' C1 u' o6 h" E7 {
4 {2 A5 r; u6 P4 Q0 B0 z9 |
0 D2 C' L) M; T4 ?* @ J# ]5 U4 J5 m" F. \; o
独立看门狗复位:' B. i1 H' r5 ?2 I
; r! A, ^2 e d8 Q/ `/ f3 X/ {9 d( M
8 r( h* e1 v) B" J! X0 e) X2 a
/ e9 ?, X4 x8 [, x% R) c, K0 T窗口看门狗复位:
3 I# |& Y0 ?$ G; O- n
" E: Y, u/ Q) B) v) x
4 k4 M. A/ c0 t+ c O: W- \
% {0 G9 k& R. p/ i; m9 ~0 U. V系统复位:; x- s+ U8 x* F5 P
% Y- I3 F9 q9 O" b" Z9 E$ y
; k; h. K& f/ K) |( P( n0 W4 D' y! l6 p% ^' }4 b: k) ~
内核复位:7 _7 k2 S8 Z$ @
1 e0 o# h4 k. W
. f M6 S7 F [8 L( E, a1 I
. U6 [' \/ _7 R9 A通过上面复位测试可以发现,每种复位都会检测到NRST 引脚复位,难道每种复位都会将复位引脚电平拉低吗?通过示波器看看复位引脚电平:1 B) E+ i3 w+ _3 q4 t8 k o
( F: W% M( [5 q7 L
6 u2 p4 Y# L) h
1 S" M d1 ?0 K$ y通过复位引脚波形可以看出,在其它复位情况发生时,复位引脚会有一个很短的负脉冲。说明其他复位源产生时,复位引脚电平也会变化。看来上面程序检测是正确的。
- v1 v2 J$ G1 A1 A0 g, M/ s( S. _1 D4 [0 \+ K& k( s% m, `" W
; ^" f9 n0 h& B2 ^; I$ |: Q |