STM32串口通信过载溢出问题

一、发现问题

  用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标志清除,如下:

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32串口阻塞模式下的溢出是指当接收到的数据超过了串口缓冲区的容量时发生的现象。在串口阻塞模式下,当接收到数据时,程序会暂停执行,直到完成数据的接收,然后才会继续执行后续的代码。 如果串口接收到的数据量超过了缓冲区的容量,就会发生溢出。这种情况可能导致一些问题出现。首先,溢出会导致丢失接收到的数据。因为串口缓冲区无法容纳所有的数据,超出缓冲区容量的部分数据会被丢弃。其次,溢出也会引起通信错误。当缓冲区溢出时,接收到的数据无法及时处理,可能会导致数据处理错误或错误的解析。最后,溢出也可能导致系统死锁。当缓冲区溢出发生时,程序会一直等待直到接收到足够的空间,如果没有及时处理溢出,可能会导致系统无法继续正常运行。 为了解决串口阻塞模式下的溢出问题,可以采取以下措施。首先,增加串口缓冲区的容量,以适应更多的数据接收。其次,可以使用中断来接收数据,以避免程序阻塞。通过配置中断,当接收到数据时可以立即进行处理,提高了接收数据的效率。最后,还可以采用硬件流控制的方式,当缓冲区即将溢出时,通过发送控制信号告知发送方暂停发送,以缓解串口接收压力。 综上所述,串口阻塞模式下的溢出问题对于STM32应用来说是一个需要关注的重要问题。适当的优化串口缓冲区的容量,并结合中断和流控制等技术手段,可以有效地解决串口溢出问题,确保串口通信的稳定性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值