在项目中有时候会遇到单片机莫名奇妙复位的情况,为了判断是那种原因引起复位,就需要对单片机的复位源进行判断。现用STM32F103C8T6单片机进行测试。
9 [& C, }% L/ k先看看单片机复位源都有哪些?
Y0 f) Z+ c# g2 N2 J
q: S8 A8 Y" O% v( z; m: L
% R4 B& [) ]. J8 ~: G在STM32中文参考手册中可以看到,复位源可以通过状态寄存器来读出。
: k0 m- r) t* [1 h2 L% A于是写一段程序来读取复位状态寄存器:
& r K1 `3 q4 @4 ~
) o9 L, I3 C) s& B! X- void Check_Rst(void)
, p, B2 C. _/ |9 a8 v1 H& F - {( d8 e V' n( U8 Y9 L% D
- printf(" CSR = %x\r\n", RCC->CSR);; N! V" |; d& j
- if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET ) // NRST 引脚复位
5 K, V3 _3 O$ t - {; T' K/ `# ^2 r r6 v" O
- printf("PIN reset \r\n");
* p; x+ m+ Z+ _2 u9 I# Y$ Y: X3 X/ j - }2 i \: D: i: G }/ ~ e! Q
- if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET ) // 上电掉电复位# ]6 a* o( n2 | d
- {
8 v2 C0 n8 o% C4 f9 F" D# O6 o - printf("POR/PDR reset \r\n");. y4 E* Y. G" h+ Q# s
- }" e0 w" d, F8 N4 I7 r
- if(RCC_GetFlagStatus(RCC_FLAG_SFTRST) != RESET ) // 软件复位* Z8 I2 C4 k$ R
- { o/ ^0 z0 R5 j8 t
- printf("Software reset \r\n");7 q6 T u; M' h8 M" L! O; f4 Y8 t# B
- }, W* j ^$ o j; w$ B8 d
- if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET ) // 独立看门狗复位
8 q0 m8 d' I: {; q0 H, n* Y, x - {
. O9 V8 g" t2 o; X4 j5 `2 \ - printf("Independent watchdog reset \r\n");" I% i; s5 r2 c4 G
- }+ k2 z( H7 M7 h4 X! [3 c
- if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET ) // 窗口看门狗复位0 d0 L/ o5 |4 Z0 e! z
- {2 i2 @8 E% ^$ ]4 q4 p( v
- printf("Window watchdog reset \r\n");
; o1 W% j! h- O9 i - }
/ D4 q( |* w) {" F - if(RCC_GetFlagStatus(RCC_FLAG_LPWRRST) != RESET ) // 低功耗复位9 \3 R! v9 J4 K2 a% Z5 J% \
- {/ P5 T! O0 @- H# h0 ?" g) n; A
- printf("(Low-power reset \r\n");0 K+ P: B* G4 J; R! N6 q$ [
- }; ~. w$ J6 q+ D6 Y1 o7 u( b$ B; y2 d
- RCC_ClearFlag(); //清除复位标志
: _8 A m# j( ^ - printf("\r\n");; z) V$ g; e3 Q3 X, q
- . e7 q7 Q0 {) r) V# o
- }
复制代码 6 ~1 J4 z6 ? A' {. v
通过串口将信息打印出来。3 @8 `* `. H+ b1 j) q
现在写个程序测试,引脚复位、掉电复位、看门狗复位都比较好测试。就是软件复位要用代码实现。通过查找资料发现软件复位可以分为系统复位和内核复位。系统复位会复位所有硬件电路,包括IO口状态。内核复位只复位内核,不影响硬件电路。
0 P9 u) z$ F7 Z系统复位实现代码如下:
g/ t# ]6 i7 d; P
- c9 k# X' p, d) d( ~% W- //系统复位 所有电路都会复位/ ?# `' Q& k* d% J) u
- void mcuSysRestart(void)6 b1 W: R7 G% a$ Q
- {8 z C' F% j- c
- __set_FAULTMASK(1); //关闭所有中断5 x) s! y2 ?4 ~7 q
- NVIC_SystemReset(); //系统复位 源码见 core_cm3.h 文件 static __INLINE void NVIC_SystemReset(void) 函数
0 J, T" q; u, P/ E, i - 1 {# n! e( i- [6 ~
- }
复制代码 2 ~4 J7 K7 Z# W) S, I, A/ [
内核复位代码如下:
4 `8 d7 I5 ]. ?- O- //内核复位 不会影响外设和其他电路' R' k: H- }3 {
- void mcuCoreRestart(void)
5 M6 g% a0 \, ?( r% O - {- x$ t0 O; c4 j2 }& n- d4 p0 f
- __DSB();0 O. f% u2 t/ c
- //置位VECTREST+ p4 C7 m8 K9 Y |( ]5 {- U
- SCB->AIRCR = ((0x5FA AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
: K& U/ r1 r: N) Y: f- H - SCB_AIRCR_VECTRESET_Msk);" Y0 C' T# o& I
- __DSB();
0 [9 e+ V7 J+ S1 M6 | - while(1);
; b& g. P6 D: H* t' B* { - }
复制代码 5 ^) Y( ~) n$ s# F& r% G" H
在程序中通过不同的按键控制不同复位情况,打印信息如下:
% a' p8 `4 @& a( j2 A; Y上电复位:
" c+ c; r* ?& F( n) a; Y A: r6 ~! v( z
" L6 C6 M0 h5 `2 J4 d( ^
V5 R8 Y8 `% A$ {0 w
按复位键复位:: ]# x. P4 r5 Y
) Z1 s u6 b+ _9 a' s
- W9 H R. d; w" Q- o6 H$ A+ ?
' H2 @) U' e$ B; q0 r( i* [/ a# D
独立看门狗复位:
# N9 C2 Y4 T: ^. Z. v0 a }
$ n) I8 k: E0 ^6 q' M
% r2 R& O! Y9 m9 G8 @7 `5 @) n& d
! r4 F4 V D$ e5 O* W& }9 P+ B6 J窗口看门狗复位:
! k8 P1 _$ `( j) v" o
4 v5 A- x& a; m5 @- r
9 d; S6 N. i0 r! C0 B/ D' [" R, |9 [
系统复位:/ J: I3 d3 t M; M
[- u. b; j4 j* A
8 i8 Z5 I: G& d1 |) H7 w% P0 p& f. a Y) @, E$ A' Z! ` ^7 W( s, z, J
内核复位:9 u6 f$ S2 I' g& s: T- K
* z- k* Q; r6 U0 n K/ f
, Z: A) N6 ^. l% W9 H
. n7 I: {3 v, X' J1 f通过上面复位测试可以发现,每种复位都会检测到NRST 引脚复位,难道每种复位都会将复位引脚电平拉低吗?通过示波器看看复位引脚电平:6 s# V+ L3 L- j/ [$ [( M5 |
' P* b Y/ R" g, [
- r& g$ H: ^7 Z( Q2 }* a- N( C P x& t& w) v/ }
通过复位引脚波形可以看出,在其它复位情况发生时,复位引脚会有一个很短的负脉冲。说明其他复位源产生时,复位引脚电平也会变化。看来上面程序检测是正确的。
) h# K2 f- y9 v3 J2 L8 e6 N
1 R* Z+ N: v: P! B+ I0 H
0 i! ^* F4 A: k |