[其他ST产品] STM32串口频繁收发至其卡死的解决方案

[复制链接]
2953|53
 楼主| 斧王FUWANG 发表于 2023-7-31 14:51 | 显示全部楼层 |阅读模式
一、项目描述:
需要STM32单片机与上位机使用串口频繁收发数据,收发频率为50Hz,即单片机每秒发送50帧数据,每秒接收50帧数据,每帧数据大概14字节。

二、问题描述:
收发一段时间后,单片机卡死,无反应。

三、前期知识:
本段引自《STM32F10x-中文参考手册》STM32F10x-中文参考手册-单片机文档类资源

3.1 知识点一

6195164c75a04504d2.png

表180源自P538

由表180可知,当我们使能TXNEIE位时,不仅会开启接收中断TXNE,也会开启数据溢出中断ORE。因此,我们不仅要检测接收中断TXNE,也要检测ORE溢出位中断。


 楼主| 斧王FUWANG 发表于 2023-7-31 14:52 | 显示全部楼层
3.2 知识点二
6663664c75a3cd5b34.png

源自P523

由红线内容所示,要复位ORE,则要先读SR再读DR。即先读状态寄存器(USART_SR),再读数据寄存器(USART_DR),即执行如下两行代码。
 楼主| 斧王FUWANG 发表于 2023-7-31 14:52 | 显示全部楼层
    USART_ClearFlag(USART1,USART_FLAG_ORE);//清除ORE标志位
            USART_ReceiveData(USART1);               //抛弃接收到的数据
 楼主| 斧王FUWANG 发表于 2023-7-31 14:53 | 显示全部楼层
四、代码部分
代码是基于STM32标准库编写。
 楼主| 斧王FUWANG 发表于 2023-7-31 14:53 | 显示全部楼层
4.1 源代码:
  1. void USART1_IRQHandler(void)           //UART1中断服务函数
  2.         {
  3.         u8 Res;
  4.         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
  5.            //接收中断(接收到的数据必须以0x0d 0x0a结尾)
  6.                 {
  7.                 Res =USART_ReceiveData(USART1);        //读取接收到的数据
  8.                
  9.                 if((USART_RX_STA&0x8000)==0)//接收未完成
  10.                         {
  11.                         if(USART_RX_STA&0x4000)//接收到了0x0d
  12.                                 {
  13.                                 if(Res!=0x0a)USART_RX_STA=0;//接收错误重新开始
  14.                                 else USART_RX_STA|=0x8000;        //接收完成了
  15.                                 }
  16.                         else //还没有接受到0x0D
  17.                                 {       
  18.                                         if(Res==0x0d)USART_RX_STA|=0x4000;
  19.                                         else
  20.                                         {
  21.                                                 USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
  22.                                                 USART_RX_STA++;
  23.                                                 if(USART_RX_STA>(USART_REC_LEN-1))
  24.                         USART_RX_STA=0;//接收数据错误,重新开始接收          
  25.                                         }                 
  26.                                 }
  27.                         }
  28. }
 楼主| 斧王FUWANG 发表于 2023-7-31 14:53 | 显示全部楼层
4.2 原因分析
由上可知,

死机应为,未及时清除RXNE接收中断与ORE溢出中断标志位所致。
 楼主| 斧王FUWANG 发表于 2023-7-31 14:53 | 显示全部楼层
4.3 解决方案:
1.清除RXNE标志位与中断标志位

2.用USART_GetFlagStatus()函数检查是否发生ORE溢出中断,清除ORE中断标志位,抛弃所接受到的数据。
  1. void USART1_IRQHandler(void)           //UART1中断服务函数
  2.         {
  3.         u8 Res;
  4.         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
  5.            //接收中断(接收到的数据必须以0x0d 0x0a结尾)
  6.                 {
  7.                 Res =USART_ReceiveData(USART1);        //读取接收到的数据
  8.                
  9.                 if((USART_RX_STA&0x8000)==0)//接收未完成
  10.                         {
  11.                         if(USART_RX_STA&0x4000)//接收到了0x0d
  12.                                 {
  13.                                 if(Res!=0x0a)USART_RX_STA=0;//接收错误重新开始
  14.                                 else USART_RX_STA|=0x8000;        //接收完成了
  15.                                 }
  16.                         else //还没有接受到0x0D
  17.                                 {       
  18.                                         if(Res==0x0d)USART_RX_STA|=0x4000;
  19.                                         else
  20.                                         {
  21.                                                 USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
  22.                                                 USART_RX_STA++;
  23.                                                 if(USART_RX_STA>(USART_REC_LEN-1))
  24.                         USART_RX_STA=0;//接收数据错误,重新开始接收          
  25.                                         }                 
  26.                                 }
  27.                         }
  28.                        
  29.                         //***************代码添加部分*************//
  30.                         USART_ClearFlag(USART1,USART_FLAG_RXNE);//清除RXNE标志位
  31.                         USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);
  32.                                                     //清除RXNE中断标志
  33.      }
  34.                
  35.                          if(USART_GetFlagStatus(USART1, USART_IT_ORE) != RESET)  
  36.                     //需要用USART_GetFlagStatus函数来检查ORE溢出中断
  37.                 {
  38.                         USART_ClearFlag(USART1,USART_FLAG_ORE);//清除ORE标志位
  39.                         USART_ReceiveData(USART1);                   //抛弃接收到的数据                       
  40.          }
  41.                   //****************代码添加结束****************//
  42. }
 楼主| 斧王FUWANG 发表于 2023-7-31 14:53 | 显示全部楼层
五、结果:
单片机收发正常,再无卡死现象。
sheflynn 发表于 2023-8-4 13:40 | 显示全部楼层
不知是哪设置错了               
minzisc 发表于 2023-8-4 13:58 | 显示全部楼层
在发送数据时,可以设置一个超时时间,如果在超时时间内没有收到数据,则可以释放中断或者停止发送数据,避免程序卡死。
linfelix 发表于 2023-8-4 14:23 | 显示全部楼层
多看看初始化的流程图,是否完全一致
plsbackup 发表于 2023-8-4 14:55 | 显示全部楼层
如果数据的处理速度较慢或外设需要更多时间来处理数据,可以在串口读写操作之间添加适当的延时
iyoum 发表于 2023-8-4 15:05 | 显示全部楼层
使用串口超时控制可以避免程序卡死。
lzmm 发表于 2023-8-4 15:28 | 显示全部楼层
UART状态标志位获取不正确              
fengm 发表于 2023-8-4 15:36 | 显示全部楼层
拿示波器查下rx管脚是不是一直有信号过来。
chenci2013 发表于 2023-8-4 16:03 | 显示全部楼层
较小的缓冲区可能无法处理高速传输,导致数据丢失或堵塞。
alvpeg 发表于 2023-8-4 16:25 | 显示全部楼层
优化串口代码可以提高程序的执行效率,减少程序卡死的可能性。
tabmone 发表于 2023-8-4 16:37 | 显示全部楼层
及时处理接收到的数据可以避免串口缓冲区溢出或数据丢失的问题。
janewood 发表于 2023-8-4 17:02 | 显示全部楼层
可以考虑使用DMA来处理串口数据。
ulystronglll 发表于 2023-8-4 18:03 | 显示全部楼层
串口在通信过程中不会因为电源问题导致故障。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

39

主题

277

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部