打印
[其他ST产品]

STM32串口频繁收发至其卡死的解决方案

[复制链接]
1541|53
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一、项目描述:
需要STM32单片机与上位机使用串口频繁收发数据,收发频率为50Hz,即单片机每秒发送50帧数据,每秒接收50帧数据,每帧数据大概14字节。

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

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

3.1 知识点一



表180源自P538

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


使用特权

评论回复
沙发
斧王FUWANG|  楼主 | 2023-7-31 14:52 | 只看该作者
3.2 知识点二


源自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标准库编写。

使用特权

评论回复
5
斧王FUWANG|  楼主 | 2023-7-31 14:53 | 只看该作者
4.1 源代码:
void USART1_IRQHandler(void)           //UART1中断服务函数
        {
        u8 Res;
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
           //接收中断(接收到的数据必须以0x0d 0x0a结尾)
                {
                Res =USART_ReceiveData(USART1);        //读取接收到的数据
               
                if((USART_RX_STA&0x8000)==0)//接收未完成
                        {
                        if(USART_RX_STA&0x4000)//接收到了0x0d
                                {
                                if(Res!=0x0a)USART_RX_STA=0;//接收错误重新开始
                                else USART_RX_STA|=0x8000;        //接收完成了
                                }
                        else //还没有接受到0x0D
                                {       
                                        if(Res==0x0d)USART_RX_STA|=0x4000;
                                        else
                                        {
                                                USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
                                                USART_RX_STA++;
                                                if(USART_RX_STA>(USART_REC_LEN-1))
                        USART_RX_STA=0;//接收数据错误,重新开始接收          
                                        }                 
                                }
                        }
}

使用特权

评论回复
6
斧王FUWANG|  楼主 | 2023-7-31 14:53 | 只看该作者
4.2 原因分析
由上可知,

死机应为,未及时清除RXNE接收中断与ORE溢出中断标志位所致。

使用特权

评论回复
7
斧王FUWANG|  楼主 | 2023-7-31 14:53 | 只看该作者
4.3 解决方案:
1.清除RXNE标志位与中断标志位

2.用USART_GetFlagStatus()函数检查是否发生ORE溢出中断,清除ORE中断标志位,抛弃所接受到的数据。
void USART1_IRQHandler(void)           //UART1中断服务函数
        {
        u8 Res;
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
           //接收中断(接收到的数据必须以0x0d 0x0a结尾)
                {
                Res =USART_ReceiveData(USART1);        //读取接收到的数据
               
                if((USART_RX_STA&0x8000)==0)//接收未完成
                        {
                        if(USART_RX_STA&0x4000)//接收到了0x0d
                                {
                                if(Res!=0x0a)USART_RX_STA=0;//接收错误重新开始
                                else USART_RX_STA|=0x8000;        //接收完成了
                                }
                        else //还没有接受到0x0D
                                {       
                                        if(Res==0x0d)USART_RX_STA|=0x4000;
                                        else
                                        {
                                                USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
                                                USART_RX_STA++;
                                                if(USART_RX_STA>(USART_REC_LEN-1))
                        USART_RX_STA=0;//接收数据错误,重新开始接收          
                                        }                 
                                }
                        }
                       
                        //***************代码添加部分*************//
                        USART_ClearFlag(USART1,USART_FLAG_RXNE);//清除RXNE标志位
                        USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);
                                                    //清除RXNE中断标志
     }
               
                         if(USART_GetFlagStatus(USART1, USART_IT_ORE) != RESET)  
                    //需要用USART_GetFlagStatus函数来检查ORE溢出中断
                {
                        USART_ClearFlag(USART1,USART_FLAG_ORE);//清除ORE标志位
                        USART_ReceiveData(USART1);                   //抛弃接收到的数据                       
         }
                  //****************代码添加结束****************//
}

使用特权

评论回复
8
斧王FUWANG|  楼主 | 2023-7-31 14:53 | 只看该作者
五、结果:
单片机收发正常,再无卡死现象。

使用特权

评论回复
9
sheflynn| | 2023-8-4 13:40 | 只看该作者
不知是哪设置错了               

使用特权

评论回复
10
minzisc| | 2023-8-4 13:58 | 只看该作者
在发送数据时,可以设置一个超时时间,如果在超时时间内没有收到数据,则可以释放中断或者停止发送数据,避免程序卡死。

使用特权

评论回复
11
linfelix| | 2023-8-4 14:23 | 只看该作者
多看看初始化的流程图,是否完全一致

使用特权

评论回复
12
plsbackup| | 2023-8-4 14:55 | 只看该作者
如果数据的处理速度较慢或外设需要更多时间来处理数据,可以在串口读写操作之间添加适当的延时

使用特权

评论回复
13
iyoum| | 2023-8-4 15:05 | 只看该作者
使用串口超时控制可以避免程序卡死。

使用特权

评论回复
14
lzmm| | 2023-8-4 15:28 | 只看该作者
UART状态标志位获取不正确              

使用特权

评论回复
15
fengm| | 2023-8-4 15:36 | 只看该作者
拿示波器查下rx管脚是不是一直有信号过来。

使用特权

评论回复
16
chenci2013| | 2023-8-4 16:03 | 只看该作者
较小的缓冲区可能无法处理高速传输,导致数据丢失或堵塞。

使用特权

评论回复
17
alvpeg| | 2023-8-4 16:25 | 只看该作者
优化串口代码可以提高程序的执行效率,减少程序卡死的可能性。

使用特权

评论回复
18
tabmone| | 2023-8-4 16:37 | 只看该作者
及时处理接收到的数据可以避免串口缓冲区溢出或数据丢失的问题。

使用特权

评论回复
19
janewood| | 2023-8-4 17:02 | 只看该作者
可以考虑使用DMA来处理串口数据。

使用特权

评论回复
20
ulystronglll| | 2023-8-4 18:03 | 只看该作者
串口在通信过程中不会因为电源问题导致故障。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

34

主题

260

帖子

0

粉丝