STM32串口中断卡死主循环问题分析

在一项目中,使用STM32作为主控,程序运行一段时间后概率出现主循环卡死现象。

问题分析如下:

1、程序USART2不停接收并处理串口数据,波特率115200;

2、主循环卡死;

3、USART1中断及TIM2中断响应函数运行正常;(USART1及TIM2中断优先级均比USART2高)

4、出现现象后,拔掉USART2的接收数据线,现象不能回复正常;

5、出现现象后,拔掉后再插入USART2的接收数据线,现象不能回复正常;

6、并未出现HardFault现象;

基于以上4点,可能原因如下:

1、USART2接收中断标志没有清除;

2、堆栈数据溢出,导致程序异常;

3、USART2中断重入导致异常;

4、USART2中断函数被异常响应;

5、USART2中断ERR;

对于以上可能原因一一分析:

1、中断接收标志清楚问题:

(1)USART2接收中断响应函数如下:

[cpp] view plain copy

  1. void USART2_Istr(void)
  2. {
  3. if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  4. {
  5. USART_ClearFlag(USART2, USART_FLAG_RXNE);
  6. USART_ClearITPendingBit(USART2, USART_IT_RXNE);
  7. Data = USART_ReceiveData(USART2);
  8. //Process Data
  9. }
  10. }

(2)出现现象后,通过Usart1中断获取到如下信息:

a. USART_GetITStatus(USART2,  USART_IT_RXNE)  == RESET

b. USART_GetFlagStatus(USART2,  USART_FLAG_RXNE)  == RESET

c. 执行USART_ClearFlag(USART2, USART_FLAG_RXNE)及 USART_ClearITPendingBit(USART2, USART_IT_RXNE)后无法恢复正常;

结论:与USART2 RXNE中断标志无关。

2、堆栈数据溢出,导致程序异常;

(1)使用2倍栈空间,问题存在,概率不会降低;

(2)使用0.5倍栈空间,问题存在,概率不会提高;

(3)使用0.25倍栈空间,程序运行进入HardFault;

结论:与堆栈无关。

3、USART2中断重入导致异常;

(1)使用标志法,确认出现问题时,中断响应函数没有重入;

结论:中断响应函数没有重入。

4、USART2中断函数被异常响应;

(1)USART2中断函数可以被正常调用,只是不停进入中断响应函数,卡死主循环;

(2)检查程序Map,没发现与中断响应函数地址相同的函数;

(3)检查中断向量表,没发现异常;

结论:中断函数没有被异常调用;

5、USART2中断ERR;

(1)关闭USART2中断,主循环恢复正常;

(2)启动USART2中断,主循环卡死;

(3)获取到DR=0x0000;

(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;

(5)通过USART_ClearITPendingBit清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均无法恢复正常;

(6)通过USART_GetFlagStatus:

a.第一次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=1,ORE=1,NE=0,FE=0,PE=0

b.第二次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0

c.第三次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0

(7)通过USART_ClearFlag清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均无法恢复正常;

分析:

(1)为什么通过USART_GetITStatus获取了所有中断标志,均为RESET(TC、TXE中断没开),还会进中断?

(2)为什么通过USART_ClearITPendingBit清除了所有中断标志,还会进入中断?

(3)为什么关闭USART2中断后再次启动它还会进入卡死状态?

(4)为什么通过USART_GetFlagStatus第一次和第二次读的不一样?而且USART_ClearFlag清掉所有Flag,也没法恢复正常?

带着以上几个疑问,查看了参考手册,才恍然大悟!如下:

(1)打开RXNEIE,默认会同时打开RXNE和ORE中断。

(2)必须第一时间清零RXNE,如没及时清零,下一帧数据过来时就会产生Overrun error!

(3)错误就是ORE导致的

出现错误时,读了RXNE=0,出错应该是上图打勾的情况,如下

(4)如文档说明,要清除ORE中断需要按顺序读取USART_SR和USART_DR寄存器!

那就是说USART_ClearFlag清掉所有Flag后,还必须读一遍USART_DR寄存器!

经过测试出现问题后依次读读取USART_SR和USART_DR,程序回复正常!

(5)那还有一个问题,为什么USART_GetITStatus读不到ORE中断标志?

读USART_GetITStatus函数就知道了,只有CR3的EIE置1且SR的ORE置1,读出来USART_GetITStatus(USART2,  USART_IT_ORE)  才是 SET。

见CR3的EIE位说明。

解决办法,出现通过接收时,通过USART_GetFlagStatus读取ORE,若不为RESET,则读取DR数据丢弃。

修改如下:

[cpp] view plain copy

  1. void USART2_NewIstr(void)
  2. {
  3. if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)
  4. {
  5. USART_ReceiveData(USART2);
  6. USART_ClearFlag(USART2, USART_FLAG_PE);
  7. }
  8. if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
  9. {
  10. USART_ReceiveData(USART2);
  11. USART_ClearFlag(USART2, USART_FLAG_ORE);
  12. }
  13. if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)
  14. {
  15. USART_ReceiveData(USART2);
  16. USART_ClearFlag(USART2, USART_FLAG_FE);
  17. }
  18. if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  19. {
  20. USART_ClearFlag(USART2, USART_FLAG_RXNE);
  21. USART_ClearITPendingBit(USART2, USART_IT_RXNE);
  22. Data = USART_ReceiveData(USART2);
  23. }
  24. }

总结:

1、看文档!看文档!还是看文档!(重要的事情要说3遍)

2、库函数用的时候,也要注意其实现,稍有不慎就可能用错。

3、注意USART_GetFlagStatus与USART_GetITStatus的区别,还有中断响应机制。

4、任意时候都要考虑出错处理。

查了一下 ,也有人遇到了相同的情况,可参考:

http://blog.csdn.net/love_maomao/article/details/8234039

原文地址:https://www.cnblogs.com/huangyangquan/p/8966392.html

时间: 2024-08-29 13:18:59

STM32串口中断卡死主循环问题分析的相关文章

STM32串口中断的一些资料

在研究STM32串口接收发送中断的时候找到不少不错的资料,现在备份在这里.以供自己查阅,以及方便其他人. TC ====TXE 顺便预告下最近会写个有关串口处理数据的帖子,从查询和中断方面以及数据处理的方式,从队列以及FIFO方面写起. SECTION 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 /* 调试STM32串口过程中发现一个奇怪的问题,

STM32串口中断实例二

int main(void) { uint8_t a=0;//LED高低电压控制 /* System Clocks Configuration */ RCC_Configuration(); //系统时钟设置 /*嵌套向量中断控制器 说明了USART1抢占优先级级别0(最多1位) ,和子优先级级别0(最多7位) */ NVIC_Configuration(); //中断源配置 /*对控制LED指示灯的IO口进行了初始化,将端口配置为推挽上拉输出,口线速度为50Mhz.PA9,PA10端口复用为串

Cocos2d-x 动手实现游戏主循环

由于Cocos2d-x封装的很好,所以对于很多新手,他们只知道先new一个场景,在场景上添加布景或精灵,然后用Director的runWithScene便可以运行游戏了.如果给一个精灵加个动作,精灵就会动,如果给布景层添加个定时器,游戏会定时执行.你知道为什么会这样吗? 作为一个游戏开发者,我觉得进入游戏这一行业之前,一定要先搞清楚"游戏主循环"这个东东,可惜我到现在才来研究这个东东.或许网上关于Cocos2d-x游戏主循环的讲解一大把,但是这篇文章,我会教你怎么来实现游戏主循环. 一

stm32串口接收完整的数据包

借鉴了文章:<stm32串口中断接收方式详细比较> 文章地址:http://blog.csdn.net/kevinhg/article/details/40186169 串口的配置这里不做说明,仅对中断中的协议解析进行描述 数据帧协议: 帧头1 帧头2 数据长度 有效数据 crc_1 crc_2 B5 5B 03 00 57 0B 帧头1+帧头2+数据长度(包含有效数据.crc_1.crc_2)+有效数据 + crc_1 + crc_2(校验为帧头到有效数据) crc16校验未深入学习,代码也

C# 串口关闭时主界面卡死原因分析

原文:C# 串口关闭时主界面卡死原因分析 问题描述 前几天用SerialPort类写一个串口的测试程序,关闭串口的时候会让界面卡死. 参考博客windows程序界面卡死的原因,得出界面卡死原因:主线程和其他的线程由于资源或者锁争夺,出现了死锁. 参考知乎文章WinForm界面假死,如何判断其卡在代码中的哪一步?,通过点击调试暂停,查看ui线程函数栈,直接定位阻塞代码的行数,确定问题出现在SerialPort类的Close()方法. 参考文章C# 串口操作系列(2) -- 入门篇,为什么我的串口程

STM32串口悬空导致CPU持续进入中断函数

STM32的串口开启中断,在串口悬空(即不接外设)的情况下,CPU会不断的进串口中断服务函数 并且接收到的数据为0,当你把外设接上,一切OK. void USART2_IRQHandler(void) { INT8U tmp; /* OK */ if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET){ USART_ClearITPendingBit(USART2, USART_IT_RXNE); tmp = USART_ReceiveData(US

stm32的串口中断

void USART1_IRQHandler(void)                                                              //串口中断{    if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)           //USART1接收中断,,,    {            uart1_rx_buf[uart1_rx_RecvIndex] = USART1->DR;       

wxWidgets源码分析(2) - App主循环

目录 APP主循环 MainLoop 消息循环对象的创建 消息循环 消息派发 总结 APP主循环 MainLoop 前面的wxApp的启动代码可以看到,执行完成wxApp::OnInit()函数后,接着就执行wxApp::OnRun()函数进入App的主循环,wxApp继承自wxAppBase,所以实际调用的是wxApp::OnRun(),过程如下: wxAppBase::OnRun() -> wxAppConsole::OnRun() -> wxAppConsoleBase::MainLoo

STM32串口之空闲中断

NBiot模块一般都是串口接口,使用AT指令集,对接中国移动onenet平台.先用串口助手去测试,流程测试OK之后需要在MCU上重新写一遍. STM32串口 IDLE中断 IDLE其实是空闲的意思.IDLE中断叫空闲中断,不叫帧中断.那么什么叫空闲,怎么定义空闲呢?在实际发送数据的时候,比如一串字符串,我们会采用如下方式发送 void uart1_putc(char dat) { SBUF = dat; while (!TI); TI = 0; } void uart1_puts_n(char