你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32串口中断卡死

[复制链接]
aimejia 发布时间:2018-5-28 15:20
在一项目中,使用STM32作为主控,程序运行一段时间后概率出现主循环卡死现象。  x9 t6 h/ Q  S/ C

2 T8 Z3 b  U: ^. ~$ N& `问题分析如下:
6 U0 \! n) A, f3 b
3 U* a5 c, J! M; e* x" V7 t1、程序USART2不停接收并处理串口数据,波特率115200;
8 i7 [0 w8 q/ z* W
, }: d2 V6 |2 U7 _# V% P5 q3 V1 f2、主循环卡死;
# \6 g% C* V" ?
: q: d/ ?( Z: B: I5 Q3、USART1中断及TIM2中断响应函数运行正常;(USART1及TIM2中断优先级均比USART2高)
8 S$ c1 Q0 k6 `$ r
; ^% T7 a  T; T" Y* @8 {! |" ]% q4、出现现象后,拔掉USART2的接收数据线,现象不能回复正常;! w; c2 P; T0 t* G8 j: h; }

  Y- j) q" j0 G5、出现现象后,拔掉后再插入USART2的接收数据线,现象不能回复正常;
- Y2 R! ]( T! u5 n; i3 U, z3 X% m5 W" S
6、并未出现HardFault现象;
6 w3 r+ ^# @& l# [4 v4 ?! a( A' _
基于以上4点,可能原因如下:: Z+ x% o" Y1 ~. g

" M' s7 C$ ?5 {( W+ ?1 [1、USART2接收中断标志没有清除;
8 T9 k2 B1 R0 F/ K+ G- z
5 N% G0 g$ B, b; A; X( i/ U2、堆栈数据溢出,导致程序异常;
, G6 o( [0 y, t# ?9 ]6 J# l
! v% M* k! |3 u3、USART2中断重入导致异常;
/ W! t2 N- V) o" p9 z, D0 e: g; I  U% P6 Z! A8 Q. Y! y
4、USART2中断函数被异常响应;
1 _4 u! V$ ?. X7 ?, q$ e- {6 w
/ i$ s. ]/ s7 X9 E 5、USART2中断ERR;" E# W0 N4 Q/ h4 T
; {/ @' Z9 d: {5 W
对于以上可能原因一一分析:
6 A, Y5 n8 O6 t* v8 Q% p: t
& M) m' u, S  K$ a. {1 v, y  A1、中断接收标志清楚问题:
3 \1 n9 D4 `2 {) D; [- K  C3 U/ z6 m/ z6 H5 A5 r
(1)USART2接收中断响应函数如下:1 x2 y. B! l9 o# W8 _2 O2 z
[cpp] view plain copy
+ E$ j. H* C5 r9 T+ ]9 R
* q" c. ?, N4 {9 C, R  F" u6 o
! L- O8 |) x; S4 W

3 i  z! a3 T; n% G
9 q& L% a$ H) d5 J
  • void USART2_Istr(void)  
  • {   
  •     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  •     {     
  •         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  •         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  •         Data = USART_ReceiveData(USART2);  
  •         //Process Data  
  •     }  
  • }  
    / D- W; I% f) _. A! ?
[cpp] view plain copy# V; r7 T! O1 B8 J7 l/ [* U

4 y6 u1 `; F. E: q4 J! ?# w3 y

1 R9 ^  H% l! M7 G1 B' ^

) I  [) M7 n: ]9 X8 v
  • void USART2_Istr(void)  
  • {   
  •     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  •     {     
  •         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  •         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  •         Data = USART_ReceiveData(USART2);  
  •         //Process Data  
  •     }  
  • }  , D5 m2 B2 P3 q. B+ z
(2)出现现象后,通过Usart1中断获取到如下信息:
( M% i& @/ u/ ^4 N* c! o) @; ya. USART_GetITStatus(USART2,  USART_IT_RXNE)  == RESET
5 F7 Q5 T4 s8 l: l  N* f
" R$ k( V  M1 |! }b. USART_GetFlagStatus(USART2,  USART_FLAG_RXNE)  == RESET
5 k$ k0 g& a* b* X; Q
9 e2 j. ]  u& ]- X+ Dc. 执行USART_ClearFlag(USART2, USART_FLAG_RXNE)及 USART_ClearITPendingBit(USART2, USART_IT_RXNE)后无法恢复正常;. g* O$ N2 G0 @5 S$ I/ r
8 P" s, B  J4 ]3 G+ h/ Q0 m9 G
结论:与USART2 RXNE中断标志无关。
& G- f, a3 @  n# p- a
7 e3 F- x* ^# T' S/ G1 {9 o, ?2、堆栈数据溢出,导致程序异常;
' P4 H1 ^5 {8 R$ v4 Z! {% O( Q, V, r8 U. d2 I! j
(1)使用2倍栈空间,问题存在,概率不会降低;3 x8 E; _$ V$ m& @7 l( e' w
* x  O, ^5 U  S5 w- n
(2)使用0.5倍栈空间,问题存在,概率不会提高;
, P7 e$ X2 b6 @4 y
* d6 x( b4 Q9 \* [* o(3)使用0.25倍栈空间,程序运行进入HardFault;# `2 R2 `8 S1 y3 X" X& ~- u* d. z

8 V* P8 J, s3 V9 P" O; @% d& S结论:与堆栈无关。5 p" k& h) k# D  Z# A

7 u- w$ S& A9 r5 T3、USART2中断重入导致异常;8 ~6 O& u- z7 z5 S! l  `

; m7 X4 p  z! x, F/ @/ H(1)使用标志法,确认出现问题时,中断响应函数没有重入;
: h6 a+ y. |# V+ X2 I5 R1 Z
. n& O5 q% D+ ~# ]* n结论:中断响应函数没有重入。
% m; Q9 m1 `/ j- [: @
, ?# N$ w4 @2 y' G4 `. Q, o' K7 F4、USART2中断函数被异常响应;/ g3 S' g  J1 k" p
# B9 Q/ h7 H+ T
(1)USART2中断函数可以被正常调用,只是不停进入中断响应函数,卡死主循环;( J% M8 v+ F  ~- g# U& B

- v/ X3 v1 a0 B% B0 F; b/ u(2)检查程序Map,没发现与中断响应函数地址相同的函数;' ~( ^1 W/ X8 z- k( r, X
, ?* V. X: @5 P: E
(3)检查中断向量表,没发现异常;! ?* @" s# ]& z4 S3 E
7 Y3 z& |3 f2 D, s+ X) _  S
结论:中断函数没有被异常调用;. M* J; h, l6 G. v* Z7 M7 I% H" K9 c

0 T& {# d/ ?- O3 h$ Z  C5、USART2中断ERR;
% v5 g8 h7 p7 Z& x# A; Z" C/ r% w1 K% Q
(1)关闭USART2中断,主循环恢复正常;
" Y/ c, P' x2 d/ C- F$ p( `  S+ g; O, D7 h5 P
(2)启动USART2中断,主循环卡死;
: |- e: U2 C, J1 c/ J+ Y, A, z5 V' o/ u/ @( o, \
(3)获取到DR=0x0000;
1 o3 s) G" u. G# k
5 m- L& h9 M0 E; J(4)USART_GetITStatus取到:RXNE=0,PE=0,TXE=0,TC=0,IDLE=0,LBD=0,CTS=0,ERR=0,ORE=0,NE=0,FE=0;
4 s' B# L2 k6 V! Z, F
% \* x6 Q8 H$ k+ F(5)通过USART_ClearITPendingBit清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均无法恢复正常;# M' |/ x% H$ h3 w, K: ]* }

$ p/ k. f' E* {3 a' l3 Q% R(6)通过USART_GetFlagStatus:
1 P, k  _6 b; h. q0 |
! J) ~  v% b3 a5 }  a.第一次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=1,ORE=1,NE=0,FE=0,PE=0' X" E4 l8 q2 C, [) }' G

, S0 c  M2 a" f9 M( E$ _* A, q  b.第二次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0
# }  [! A2 {0 x3 j1 }& n/ v' O
3 |" i; K1 @; Q2 N( I) _  c.第三次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0
( t" L1 m, L2 ]: p; B; U% N  h0 f) s: z
(7)通过USART_ClearFlag清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均无法恢复正常;
2 p' e, r6 K; C9 l* v' H6 l* a3 Q2 l) N* s3 b
分析:
+ h4 k3 V4 }% Q3 s  E, D, @% \) l
# R  D- j2 m7 X! b0 t! h5 G(1)为什么通过USART_GetITStatus获取了所有中断标志,均为RESET(TC、TXE中断没开),还会进中断?6 y) C" t0 Z  U
  ^5 E8 K; A: p% b
(2)为什么通过USART_ClearITPendingBit清除了所有中断标志,还会进入中断?
6 v5 r- {; s7 F; t4 ^; ~0 k/ X- H$ x1 Z' |$ @: i: j
(3)为什么关闭USART2中断后再次启动它还会进入卡死状态?$ c5 l' }' v& C& B  u
+ J/ ~- m6 J! ]; W( L; q; t3 l
(4)为什么通过USART_GetFlagStatus第一次和第二次读的不一样?而且USART_ClearFlag清掉所有Flag,也没法恢复正常?- M! K2 Y0 G. D; M7 m7 z1 U- \

8 ~* O/ o: Y, S带着以上几个疑问,查看了参考手册,才恍然大悟!如下:
  M  E* ~8 i' ~6 \9 n, p$ w 1.png 7 R4 O3 u8 L% C- M5 M. P4 {
(1)打开RXNEIE,默认会同时打开RXNE和ORE中断。, D5 n% R5 N- L8 E/ q

7 K3 B7 i. J/ y% ]! _! r, H/ A/ L(2)必须第一时间清零RXNE,如没及时清零,下一帧数据过来时就会产生Overrun error!7 g! x& J6 z8 E- C7 O; N+ p/ e3 L

3 V6 Z. c, [5 K& Q$ J(3)错误就是ORE导致的/ z8 [9 R- A  [
0 X0 u" E5 C* r) c1 ~
出现错误时,读了RXNE=0,出错应该是上图打勾的情况,如下
9 C8 r7 }" T, `5 M$ X- E9 `5 w 2.jpg
4 Q% [# i9 p5 [8 o4 d(4)如文档说明,要清除ORE中断需要按顺序读取USART_SR和USART_DR寄存器!
# T0 G3 }' t* Q* W+ X: N* ^$ S2 U9 T
那就是说USART_ClearFlag清掉所有Flag后,还必须读一遍USART_DR寄存器!
  g- y" I/ I6 q- v/ T: q$ H+ g; C1 q8 I4 t- e
经过测试出现问题后依次读读取USART_SR和USART_DR,程序回复正常!7 w. f/ D8 F+ H
+ x! K% R  ~0 F
(5)那还有一个问题,为什么USART_GetITStatus读不到ORE中断标志?' y# G1 L* m6 j* J

& v, x( c8 R/ \* t+ Q0 E读USART_GetITStatus函数就知道了,只有CR3的EIE置1且SR的ORE置1,读出来USART_GetITStatus(USART2,  USART_IT_ORE)  才是 SET。' W' g+ h4 d# o& V5 q  n7 M
) ?6 C) Y3 S9 Z) d
见CR3的EIE位说明。% T& z( q* e! R# p- O

- p2 y( |. e/ ?" |3 ^& ~- `2 ? 3.jpg
! F/ m+ n* l7 K& r2 e8 L
& [- e, G/ |% @4 ]. d 4.jpg 0 C0 P# l5 r0 S( N1 V" J
, D0 _6 I7 @, N! N  n# Z
) N* M' \- _! {! w- r: c% ?

5 l4 D3 u( C$ J1 `解决办法,出现通过接收时,通过USART_GetFlagStatus读取ORE,若不为RESET,则读取DR数据丢弃。# f8 u, P9 b' h9 x
# s* e7 W  [" c5 {% {
修改如下:, O8 j7 [: l- N) S
[cpp] view plain copy
7 _" I: u7 S0 o4 C- j
1 r0 A2 M- N& m) d) c6 l* W* d  B+ W7 b8 S
# ?" Y6 i( [7 J% j3 L+ f
' u, W2 D$ Q* E3 ^% O
  • void USART2_NewIstr(void)  
  • {   
  •     if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •      USART_ClearFlag(USART2, USART_FLAG_PE);  
  •    }  
  •       
  •    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •      USART_ClearFlag(USART2, USART_FLAG_ORE);  
  •    }  
  •       
  •     if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •       USART_ClearFlag(USART2, USART_FLAG_FE);  
  •    }  
  •       
  •     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  •     {     
  •         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  •         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  •         Data = USART_ReceiveData(USART2);  
  •     }  
  • }  + F+ o6 f( p0 ~9 ^# K* ]
[cpp] view plain copy
2 q- _4 P" p" d- y- v
$ [4 Z; T3 {4 g) o& ?) j. k

1 e4 Q* I: Y1 `1 q% d
; d" \. O: y8 G4 A  x  I: s- ^7 l3 s
  • void USART2_NewIstr(void)  
  • {   
  •     if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •      USART_ClearFlag(USART2, USART_FLAG_PE);  
  •    }  
  •       
  •    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •      USART_ClearFlag(USART2, USART_FLAG_ORE);  
  •    }  
  •       
  •     if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •       USART_ClearFlag(USART2, USART_FLAG_FE);  
  •    }  
  •       
  •     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  •     {     
  •         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  •         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  •         Data = USART_ReceiveData(USART2);  
  •     }  
  • }  
    ) H1 H. J& x( a( O. N8 e0 Z/ A1 l

9 J) O3 }/ Z$ c4 ]  z% i总结:
3 S+ l1 t7 O- E1、看文档!看文档!还是看文档!(重要的事情要说3遍)- K6 Y9 [  Z( I' `3 i3 q* ]3 g

: ^, p+ X9 C/ G+ t* e$ F2 a* `) \2、库函数用的时候,也要注意其实现,稍有不慎就可能用错。& d' m7 s. I# d1 |+ Q

9 X! K1 M- E( {; {1 g+ m. Z3、注意USART_GetFlagStatus与USART_GetITStatus的区别,还有中断响应机制。
+ x. H/ z: v( d5 V; T* h, H; \; [! S- w
4、任意时候都要考虑出错处理。
+ L  t' v8 }8 b7 z0 r
0 z8 t: P( E: p
' ]" A! @! ?8 _
% J# U4 _& d0 Q* A6 Q1 k2 d& q' p9 V7 k4 H3 N
转载自shaynerain' l3 ]/ X- c7 }6 Z. E

) Z$ e0 u7 H2 A" r/ s
赞 收藏 1 评论2 发布时间:2018-5-28 15:20

举报

2个回答
钊钊 回答时间:2018-5-28 16:58:12
每次接收都要清掉标志位是个好习惯
STM1024 回答时间:2018-5-28 17:04:57
刚看问题的时候,我还在想,是不是和" p, @4 }9 O' ?; T5 ^$ O4 N
  //Process Data  
" z  a' {: n- e0 Q8 h) z/ `/ R下面的代码有关,就是这个代码也会带来中断……
+ t" o7 B) V9 `, {0 X# W& G$ s结果还是老问题,没有及时清除中断标志位
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版