在项目中有时候会遇到单片机莫名奇妙复位的情况,为了判断是那种原因引起复位,就需要对单片机的复位源进行判断。现用STM32F103C8T6单片机进行测试。% g o- h, N! O: ?4 r
先看看单片机复位源都有哪些?
8 l! k# h1 @( b; ]
/ O. R* V3 O+ w' @ r+ [/ A
2 K n, H! c; k在STM32中文参考手册中可以看到,复位源可以通过状态寄存器来读出。% ]$ L9 R$ N6 y! Z9 F# H8 D* a3 O
于是写一段程序来读取复位状态寄存器:
: ~0 G3 R1 O' a5 o- G7 H1 \+ Z3 M1 `; F* `/ @1 u4 [0 s
- void Check_Rst(void) t1 I" V: i0 o
- {
3 D, w) z& t) [" k: ^3 M6 Z! H5 _ - printf(" CSR = %x\r\n", RCC->CSR);
, E' h/ Q: ]: y4 _% V - if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET ) // NRST 引脚复位9 N I9 b2 {$ \9 _8 ^, W6 _
- {
: q! { g, E7 J+ L - printf("PIN reset \r\n");
& I, H2 o+ n+ k+ T - }* \7 h p. S( t7 X* x7 R
- if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET ) // 上电掉电复位
5 H/ N# a7 Q; A2 f+ V% J' A - {+ \4 |! {# J: T6 c5 Q' o& r2 j
- printf("POR/PDR reset \r\n");
' y% e; o1 b, w& p. S - }" K' r7 ?2 Z+ F# `- u
- if(RCC_GetFlagStatus(RCC_FLAG_SFTRST) != RESET ) // 软件复位
/ O# p, k6 V. O: v - {; X/ M2 z- _9 D Z
- printf("Software reset \r\n");) E1 A$ `, ]& q _2 z2 ^$ P/ V. g
- }
- @9 G6 F6 U$ z* { - if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET ) // 独立看门狗复位2 Q/ `9 H7 }( q* P$ T
- {
, e% t+ m& U/ u4 Z1 R - printf("Independent watchdog reset \r\n");
( m( o _* @/ S5 t+ ` - }: Q, ^* f( D/ F5 S" v
- if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET ) // 窗口看门狗复位
* H5 ~+ ?' P9 j4 z* b2 s - {
3 r6 g! p7 R5 j0 {% I - printf("Window watchdog reset \r\n");
3 r1 \2 j' J# Q4 Z1 J1 d7 S - }* C4 v; q1 Y5 V7 c! ~3 ~
- if(RCC_GetFlagStatus(RCC_FLAG_LPWRRST) != RESET ) // 低功耗复位9 g& D" L6 }8 |# R
- {
" d, M$ V! ?& l( P' D - printf("(Low-power reset \r\n");( y0 J4 M$ r* q$ L
- }9 c& Z2 M7 z% m) N5 t X0 Y
- RCC_ClearFlag(); //清除复位标志
" s: l; V4 g4 C/ W% } - printf("\r\n");. b: Y- h8 a" r4 m
$ c! q8 t5 V/ ?& W8 q- }
复制代码 ' J$ h/ l) @% J! T5 y' P3 ?
通过串口将信息打印出来。
* V! V5 w; Q" X( O! z3 ~现在写个程序测试,引脚复位、掉电复位、看门狗复位都比较好测试。就是软件复位要用代码实现。通过查找资料发现软件复位可以分为系统复位和内核复位。系统复位会复位所有硬件电路,包括IO口状态。内核复位只复位内核,不影响硬件电路。" M4 }0 a0 g) f
系统复位实现代码如下:* o: q! G( [/ ^" W3 S
. F2 ^2 W6 r9 P9 K+ Z. J+ m3 v
- //系统复位 所有电路都会复位 t! S, y* t% f
- void mcuSysRestart(void)
' g D4 C- { m9 s" u8 p7 A - {
& [/ l L: a( c3 B9 i - __set_FAULTMASK(1); //关闭所有中断0 ~0 N& L8 @5 r4 ]& ]
- NVIC_SystemReset(); //系统复位 源码见 core_cm3.h 文件 static __INLINE void NVIC_SystemReset(void) 函数
; O w( m4 P; D; E" o - : Q9 B- P8 R0 e! ^1 l3 Q. }2 t1 [- `
- }
复制代码
5 @/ B' M, p5 l v! [. c( \- ?内核复位代码如下:
! ^9 H# X% W. x6 r M I$ B8 X V) h- //内核复位 不会影响外设和其他电路
* S* b! R, g! G: P7 I- [$ ?+ G - void mcuCoreRestart(void)
2 q9 R( i$ b6 t5 w; A" f! Q - {1 ?) Q4 i% u$ B* b5 Y: q
- __DSB();8 y3 S: r0 L; o) _& x$ w% T0 Z! k
- //置位VECTREST3 [+ a9 R5 z- F2 l" _; n. p# i
- SCB->AIRCR = ((0x5FA AIRCR & SCB_AIRCR_PRIGROUP_Msk) |+ Y5 X6 r9 |; ?& F0 q# t f h
- SCB_AIRCR_VECTRESET_Msk);6 e" d* s. F$ G5 m
- __DSB();
) d; U( G! \" s9 e1 c X. R - while(1);. u0 P8 T0 c3 L! r7 }
- }
复制代码
0 G, R0 S+ R# h2 E. e在程序中通过不同的按键控制不同复位情况,打印信息如下:
% W0 g5 [0 [$ k- y上电复位:2 E# Y' \! t/ _$ j1 u5 j
: f& a# ]8 @; h" Q l
9 h% o3 O) T, h- U9 {/ n R
" l" z+ k& \" p$ D) p/ l. N0 J按复位键复位:3 U; u( ]! X* f$ u" f( `
" c- b2 w4 v8 v% U* k. o
. A& T1 F. N' [3 z, |: y& p4 M5 U5 D: m( `8 M& y
独立看门狗复位:
) S) i$ \$ @4 u, q) M
7 a$ l$ @6 F0 I: w& D9 K- C, ~; {4 n
# G) P9 r* _" P& R y, b: k, B4 n
窗口看门狗复位:% T3 h+ I' N: L4 |& a
: W. Y e& ]8 s2 y* W
2 R z; {- O5 a
6 ^% u% ]6 T# H8 @1 P3 U系统复位:
0 X: M+ u; _& l+ u6 V8 ^' z- j3 ~) Z' i7 I, p0 y M
: B+ I( d. K+ O) y, W; P
, ]) G8 I, f& k" K. d) l. @
内核复位:
6 _1 }$ x }9 p1 n$ l
v* L$ i9 ~9 w |- W3 J$ s9 x
- P% D& |0 i8 M4 y7 l7 |
, |1 e8 c3 c( B0 y2 @通过上面复位测试可以发现,每种复位都会检测到NRST 引脚复位,难道每种复位都会将复位引脚电平拉低吗?通过示波器看看复位引脚电平:
3 r, i) F H# W' h5 U0 R& G
) C# L& M) c( U1 E
3 C8 x# @# }$ Z& Z* u) i4 t9 u
+ W, ?' h" J) L/ A6 G9 l( [
通过复位引脚波形可以看出,在其它复位情况发生时,复位引脚会有一个很短的负脉冲。说明其他复位源产生时,复位引脚电平也会变化。看来上面程序检测是正确的。4 L: j1 C, u4 i: A- C7 h5 ^" Z
5 Y3 }2 @) x) K4 r% W) K
- C( A. B8 m2 {' o |