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

发布者:太和清音最新更新时间:2022-08-08 来源: csdn关键字: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接收中断响应函数如下:

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

        }

    }


(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数据丢弃。

修改如下:


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

        }

    }


总结:

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

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

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

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


关键字:STM32  串口中断  主循环 引用地址:STM32串口中断卡死主循环一直进中断问题分析

上一篇:STM32学习之CAN控制器简介
下一篇:STM32 CAN通信滤波设置问题

推荐阅读最新更新时间:2024-11-13 03:16

位带操作在stm32中的C语言实现
首先: #define BITBAND(addr,bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) 5) + (bitnum 2)) 对上句程序的解释: 利用宏定义的方式将位带地址的映射表示出来,该函数有两个参数addr和bitnum,分别是原本的地址和在数据中的第几位。我们知道两个公式如下: 0x2000_0000‐0x200F_FFFF地址空间:AliasAddr = 0x22000000 + (A 0x20000000)*32 + n*4 0x4000_0000‐0x400F_FFFF地址空间:AliasAdd
[单片机]
STM32学习笔记(八)---通讯基本知识
通讯的基本知识 一、通讯的分类 按数据传送的方式分 a. 串行通讯:按数据位形式一位一位地传输数据 b. 并行通讯:使用8、16、32及64根或更多的数据线进行传输 按数据通讯的方向分 a. 全双工:同一时刻,两个设备之间可以同时收发数据 b. 半双工:同一时刻,两个设备之间不能同时收发数据 c. 单工:任何时刻,只能进行单一方向通讯 按数据同步的方式分 a. 同步通讯:收发双方会使用同一时钟信号线,在时钟信号的驱动下双方进行协调,同步数据 b. 异步通讯:不使用时钟信号同步。 二、通讯速率 通信速率:通常以比特率(bitrate)表示,即每秒钟传输的二进制位数,单位为比特每秒(bit/s)
[单片机]
STM32关于UART4_IRQn未定义的解决方法
这种问题一般出现在中容量(或小容量)向大容量移植程序的时候,出现原因也很简单,因为中容量设备里没有UART4自然也就没有这个中断了。我是由STM32F103C8T6向ZET6移植程序时出现的。 解决方法是: 1.确认你的设备是大容量设备(确认有UART4) 2.确认C/C++中define的是“STM32F10X_HD”而不是“STM32F10X_MD” 3.确认替换了启动文件(“startup_stm32f10x_md.s”- “startup_stm32f10x_hd.s”)
[单片机]
STM32 I2C从机发送数据_中断方式
在调试stm32 I2C中断方式发送数据时,发现上篇介绍的内容有很多不足之处,对I2C时序也有了新的认识。 上篇文章介绍在数据发送完成后,发送NACK和STOP,然后向从机DR寄存器写了一个没用的数据,目的是为了清楚传输完成事件。其实文档中说的很明白,再倒数第二个数之后发送NACK和STOP,当时没有理解,现在看来确实是这样。 利用中断方法时,对发送NACK及STOP要求比较严格,调试时在多个位置都测试了下,发现只有在读取寄存器最后一个数据之前发送NACK和STOP,但要在主机接收事件之后,逻辑代码如下: //这段代码顺序不能改变,否则无法终止总线 { /*检测主机接收数据完成事件*/
[单片机]
STM32中assert_param()的使用
在STM32的固件库和提供的例程中,到处都可以见到assert_param()的使用。如果打开任何一个例程中的stm32f10x_conf.h文件,就可以看到实际上assert_param是一个宏定义; 在固件库中,它的作用就是检测传递给函数的参数是否是有效的参数。 所谓有效的参数是指满足规定范围的参数,比如某个参数的取值范围只能是小于3的正整数,如果给出的参数大于3, 则这个assert_param()可以在运行的程序调用到这个函数时报告错误,使程序员可以及时发现错误,而不必等到程序运行结果的错误而大费周折。 这是一种常见的软件技术,可以在调试阶段帮助程序员快速地排除那些明显的错误。 它确实在程序的运行上牺牲了效率(但只是在调试
[单片机]
STM32 SPI通信时钟极性和相位设置
通过 SPI_CR1 寄存器中的 CPOL 和 CPHA 位,可以用软件选择四种可能的时序关系。 CPOL(时钟极性)位控制不传任何数据时的时钟电平状态。此位对主器件和从 器件都有作 用。如果复位 CPOL,SCK 引脚在空闲状态处于低电平。如果将 CPOL 置 1,SCK 引脚在 空闲状态处于高电平。 如果将 CPHA(时钟相位)位置 1,则 SCK 引脚上的第二个边沿(如果复位 CPOL 位,则 为下降沿;如果将 CPOL 位置 1,则为上升沿)对 MSBit 采样。即,在第二个时钟边沿锁存 数据。如果复位 CPHA 位,则 SCK 引脚上的第一个边沿(如果将 CPOL 位置 1,则为下降 沿;如果复位 CPOL 位,则为
[单片机]
msp430串口发送中断操作之简单三步
预备知识:本人用的msp430fr6989(msp430系列大同小异),datasheet中有句非常关键的一段话: 30.3.15.1 UART Transmit Interrupt Operation The UCTXIFG interrupt flag is set by the transmitter to indicate that UCAxTXBUF is ready to accept another character. An interrupt request is generated if UCTXIE and GIE are also set. UCTXIFG is automatically rese
[单片机]
STM32的三种延时方法的代码实现_纯软件延时, 系统定时器延时, 定时器延时
/* 外部调用: delay_init(72); //系统主频, 单位为MHZ, 仅对 SYSTICK_DELAY 有效 delay_ms(1000); */ #include stm32f10x.h //#define SOFT_DELAY //纯软件延时 //#define SYSTICK_DELAY //系统定时器延时 #define TIMER_DELAY //定时器延时 #ifdef TIMER_DELAY #define TIMER_DELAY TIM4 #define TIMER_DELAY_PERIOD 1000 #de
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved