STM32串口通信过载溢出问题

本文描述了在STM32G070中使用多个串口通信时遇到的问题,定位到overrun导致的接收中断异常。作者提供了三种解决方法,包括在串口故障回调函数中处理overrun、关闭串口配置中的overrun检测以及定时检测并清除ORE。最终通过测试验证了第三种方法的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、发现问题

  用STMG070的4个串口中两个串口实时通信时,偶发某个串口通信挂掉,进入不了接收中断函数,但是能进入接收回调函数,另一个串口通信正常,其他程序正常运行?

二、分析定位问题

  起初,以为是多串口通信,导致抢占资源,频繁访问中断,导致通信冲突;

  于是,在接收回调函数中,各接收中断函数加入if, else if条件,同一时间只能进入一个串口接收中断,但是还是会偶发串口通信挂掉;

  然后,网上查资料,看到HAL库的接收中断里面有加锁、解锁操作,数据量大会导致串口锁死,进入串口接收中断函数,STM32Cube_FW_G0_V1.6.0版本里面没有加锁;

  然后,看到有说overrun导致过载溢出错误,串口接收死掉,仿真检测当串口通信挂掉时,果然overrun被置位,这里终于定位到了问题。

三、解决问题

  overrun标志,就是状态寄存器ISR寄存器的bit3:ORE,如下图

  提示:可以通过OVRDIS关闭ORE检测,如下图

  三种解决方案:(推荐第3种)

  1.在串口故障回调函数中检测ORE标志,如果被置位,则清除,重新打开串口接收中断,代码如下:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_ORE) != RESET)
	{
		__HAL_UART_CLEAR_OREFLAG(&huart2);
		//__HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);
		HAL_UART_Receive_IT(&huart2,(uint8_t*)&rx, sizeof(rx));
		su16Uart2OreCnt++;
		if(su16Uart2OreCnt >= 60000)
		{
			su16Uart2OreCnt= 0;
		}
	}
	
	if(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_ORE) != RESET)
	{
		__HAL_UART_CLEAR_OREFLAG(&huart3);
		//__HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);
		HAL_UART_Receive_IT(&huart3,(uint8_t*)&rx, sizeof(rx));
		su16Uart3OreCnt++;
		if(su16Uart3OreCnt >= 60000)
		{
			su16Uart3OreCnt= 0;
		}
	}
}

    通过检测进入串口故障回调函数中,串口ORE置位清除的次数,发现进入几次之后,后边就进不来了,不知什么原因?

2.STM32CubeMX串口配置中默认overrun默认使能,关闭该使能,但是,有丢包的风险。该方法未尝试。

3.定时500ms,检测几个串口的ORE是否置位,置位则清除ORE标志,重新打开中断,这个比较稳定靠谱一些,即使串口接收回调函数异常,也不影响清除ORE标志。代码如下:

//定时检测ORE
//static uint16_t su16INVUart1OreCnt = 0;
//static uint16_t su16APPUart2OreCnt = 0;
//static uint16_t su16BMSUart3OreCnt = 0;
//static uint16_t su16MPPTUart4OreCnt = 0;
void PS_Modules_Uart_Clear_ORE(void)
{
	static uint16_t su16OreCnt = 0;
//	static uint16_t su16PrintfOreCnt = 0;
	
//	su16PrintfOreCnt++;
//	if(su16PrintfOreCnt > 3000)
//	{
//		su16PrintfOreCnt = 0;
//		printf("INV ORE cnt(USART1) = %d\r\n",su16INVUart1OreCnt);
//		printf("APP ORE cnt(USART2) = %d\r\n",su16APPUart2OreCnt);
//		printf("BMS ORE cnt(USART3) = %d\r\n",su16BMSUart3OreCnt);
//		printf("MPPT ORE cnt(USART4) = %d\r\n",su16MPPTUart4OreCnt);
//	}
	
	su16OreCnt++;
	if(su16OreCnt > 500)
	{
		su16OreCnt = 0;
		if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE) != RESET)
		{
			__HAL_UART_CLEAR_OREFLAG(&huart1);
			HAL_UART_Receive_IT(&huart1,(uint8_t*)&rx, sizeof(rx));
//			su16INVUart1OreCnt++;
		}
		
		if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_ORE) != RESET)
		{
			__HAL_UART_CLEAR_OREFLAG(&huart2);
			HAL_UART_Receive_IT(&huart2,(uint8_t*)&rx, sizeof(rx));
//			su16APPUart2OreCnt++;
		}
		
		if(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_ORE) != RESET)
		{
			__HAL_UART_CLEAR_OREFLAG(&huart3);
			HAL_UART_Receive_IT(&huart3,(uint8_t*)&rx, sizeof(rx));
//			su16BMSUart3OreCnt++;
		}
		
		if(__HAL_UART_GET_FLAG(&huart4, UART_FLAG_ORE) != RESET)
		{
			__HAL_UART_CLEAR_OREFLAG(&huart4);
			HAL_UART_Receive_IT(&huart4,(uint8_t*)&rx, sizeof(rx));
//			su16MPPTUart4OreCnt++;
		}
	}
}

    串口2和串口3通信压力测试2小时,通信均正常。

    通过打印清除次数,发现串口3清除了3次,串口2清除了4次。

四、为什么会出现overrun?

  还是要看这个ORE位

    当RXFF = 1时,当移位寄存器中正在被接收到的数据转移到USART_RDR寄存器,该位由硬件设置。当RXFF = 1数据被转移到USART_RDR寄存器未完成时,又来一个数据,则发生过载溢出,ORE置位。

  STM32F1中这样解释:

软件序列先读SR,再读CR,可将其清零。

STM32G070也可通过串口中断标志位清除寄存器,将ORE标志清除,如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值