应用原理
STM32单片机与传感器通过串口通信,单片机串口采用中断方式接收传感器数据,同时单片机控制传感器上电。
问题描述
在一批设备中,有些设备开机能够正常读取传感器数据,有一小部分读取不到传感器的数据,出现了异常情况。
问题排查
1.确定传感器是否正常发数据
示波器测量传感器的TX,波形正常。
2.在线调试
在线调试模式下,在串口接收中断中打断点,发现异常的设备无法进入串口中断。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint8_t res;
if(huart->Instance == USART4)//
{
USART4_RX_Buff[Usart4_RX_Cnt] = RX4_Buffer;
if(USART4_RX_Buff[0]==0xff)
{
Usart4_RX_Cnt++;
if(Usart4_RX_Cnt>8)
{
Usart4_RX_Cnt = 0;
Usart4_RX_Flag = 1;
}
}
else
{
Usart4_RX_Cnt = 0;
Usart4_RX_Flag = 0;
}
HAL_UART_Receive_IT(&huart4,&RX4_Buffer,1);//再次开启接收中断
}
}
这个时候查看串口相关参数,ErrorCode的值是8.
在stm32g0xx_hal_uart.h文件中,ErrorCode值为8表示Overrun error(溢出错误)。
/** @defgroup UART_Error_Definition UART Error Definition
* @{
*/
#define HAL_UART_ERROR_NONE ((uint32_t)0x00000000U) /*!< No error */
#define HAL_UART_ERROR_PE ((uint32_t)0x00000001U) /*!< Parity error */
#define HAL_UART_ERROR_NE ((uint32_t)0x00000002U) /*!< Noise error */
#define HAL_UART_ERROR_FE ((uint32_t)0x00000004U) /*!< Frame error */
#define HAL_UART_ERROR_ORE ((uint32_t)0x00000008U) /*!< Overrun error */
#define HAL_UART_ERROR_DMA ((uint32_t)0x00000010U) /*!< DMA transfer error */
#define HAL_UART_ERROR_RTO ((uint32_t)0x00000020U) /*!< Receiver Timeout error */
查看程序,发现使用STM32CubeMX配置软件时USART4的溢出中断配置为enable(默认配置,没有动),下面是窗口中断代码。
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->ISR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags;
uint32_t errorcode;
/* If no error occurs */
errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE | USART_ISR_RTOF));
if (errorflags == 0U)
{
/* UART in mode Receiver ---------------------------------------------------*/
if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
&& (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
|| ((cr3its & USART_CR3_RXFTIE) != 0U)))
{
if (huart->RxISR != NULL)
{
huart->RxISR(huart);
}
return;
}
}
/* If some errors occur */
if ((errorflags != 0U)
&& ((((cr3its & (USART_CR3_RXFTIE | USART_CR3_EIE)) != 0U)
|| ((cr1its & (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE | USART_CR1_RTOIE)) != 0U))))
{
/* UART parity error interrupt occurred -------------------------------------*/
if (((isrflags & USART_ISR_PE) != 0U) && ((cr1its & USART_CR1_PEIE) != 0U))
{
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_PEF);
huart->ErrorCode |= HAL_UART_ERROR_PE;
}
/* UART frame error interrupt occurred --------------------------------------*/
if (((isrflags & USART_ISR_FE) != 0U) && ((cr3its & USART_CR3_EIE) != 0U))
{
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_FEF);
huart->ErrorCode |= HAL_UART_ERROR_FE;
}
/* UART noise error interrupt occurred --------------------------------------*/
if (((isrflags & USART_ISR_NE) != 0U) && ((cr3its & USART_CR3_EIE) != 0U))
{
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_NEF);
huart->ErrorCode |= HAL_UART_ERROR_NE;
}
/* UART Over-Run interrupt occurred -----------------------------------------*/
if (((isrflags & USART_ISR_ORE) != 0U)
&& (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U) ||
((cr3its & (USART_CR3_RXFTIE | USART_CR3_EIE)) != 0U)))
{
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF);
huart->ErrorCode |= HAL_UART_ERROR_ORE;
}
/* UART Receiver Timeout interrupt occurred ---------------------------------*/
if (((isrflags & USART_ISR_RTOF) != 0U) && ((cr1its & USART_CR1_RTOIE) != 0U))
{
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_RTOF);
huart->ErrorCode |= HAL_UART_ERROR_RTO;
}
/*省略若干代码*/
errorcode = huart->ErrorCode;
if ((HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) ||
((errorcode & (HAL_UART_ERROR_RTO | HAL_UART_ERROR_ORE)) != 0U))
{
/* Blocking error : transfer is aborted
Set the UART state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
UART_EndRxTransfer(huart);
/*省略若干代码*/
}
}
从上述代码可以看出如果串口一切正常,是能够进入中断接收函数的,进入中断后会先关闭中断,接收中断执行完成后再次打开中断。
if (errorflags == 0U)
{
/* UART in mode Receiver ---------------------------------------------------*/
if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
&& (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
|| ((cr3its & USART_CR3_RXFTIE) != 0U)))
{
if (huart->RxISR != NULL)
{
huart->RxISR(huart);//进入串口接收中断,进入回调函数
}
return;
}
}
但是一旦出现溢出错误,在溢出错误中断中关闭的RX中断,因为代码是在正常的串口中断回调函数中再次打开接收中断,所以当溢出错误中断关闭了RX接收中断后,就再也无法进入接收中断了。
出现溢出中断的原因
示波器测量传感器电源和单片机RX波形,发现RX在上电之初有一个下降沿,此时单片机的中断还没打开。
实际测量串口初始化与打开串口中断之间大约有40ms的间隔。文章来源:https://www.toymoban.com/news/detail-730431.html
MX_USART4_UART_Init();
MX_RTC_Init();
MX_IWDG_Init();//实际上是这一个操作耗时大约40ms
/* Initialize interrupts */
MX_NVIC_Init();
HAL_UART_Receive_IT(&huart4,&RX4_Buffer,1);//开启接收中断
出现溢出中断的原因就是串口初始化之后单片机的RX引脚出现了一个下降沿,单片机认为是一个起始位,开始接收数据,但是这个时候串口中断还没打开,所以造成了溢出中断。
STM32的数据手册是这样描述的:
文章来源地址https://www.toymoban.com/news/detail-730431.html
解决方法(软件处理)
- 配置串口时,溢出中断配置为disenable,也就是说关闭溢出中断。
- 串口的RX引脚配置为上拉模式。
- 串口初始化之后立即打开中断。
以上任意一种方式都可以解决,为了防止出现其他不可控问题,3条处理方式我都使用。
到了这里,关于STM32串口溢出中断问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!