stm32HAL库串口接收中断HAL_UART_Receive_IT函数问题描述与分析
main.c中
while (1)
{
HAL_Delay(1000);
HAL_UART_Receive_IT(&huart1,string3,5);
recog=0;while(!recog);
stm32f4xx_it.c中
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart==&huart1)/
{
temp++;
recog=1;
HAL_UART_Transmit_IT(&huart1,string3,5);
}
}
问题:若接收数据超过5个时,单片机便卡死,无法继续接收。经调试,发现它会将第6个字符接收至string3[0]中,然后卡死。
分析 首先是HAL_UART_Receive_IT函数,
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
__HAL_LOCK(huart);
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return (UART_Start_Receive_IT(huart, pData, Size));
}
else
{
return HAL_BUSY;
}
}
再到UART_Start_Receive_IT函数
HAL_StatusTypeDef UART_Start_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
__HAL_UNLOCK(huart);
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
return HAL_OK;
}
该函数打开了UART_IT_RXNE中断;
接下来看中断里做了什么:
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
HAL_UART_IRQHandler函数:
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
}
无错误,则进入UART_Receive_IT函数:
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
uint8_t *pdata8bits;
uint16_t *pdata16bits;
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
pdata8bits = (uint8_t *) huart->pRxBuffPtr;
pdata16bits = NULL;
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE)))
{
*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
huart->pRxBuffPtr += 1U;
if (--huart->RxXferCount == 0U)
{
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);
huart->RxState = HAL_UART_STATE_READY;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
huart->RxCpltCallback(huart);
#else
HAL_UART_RxCpltCallback(huart);
#endif
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
可见若接收字符数为5,则USART1_IRQHandler函数开始会连续进行5次中断,然后在最底层函数UART_Receive_IT中disable RXNE中断.
打开receive_IT,有字符传入,RXNE寄存器硬件置1,数据保存至DR寄存器. 程序进入中断,
经调试,开头的问题程序在多一个字符后huart1 始终处于HAL_ready,errorcode为8 看到这篇文章,讲的挺有道理 STM32 之 HAL 库串口 USART 丢数据及ORE卡死的解决方案_luoyu510183的博客-CSDN博客 https://blog.csdn.net/luoyu510183/article/details/86515644 但我添加如下错误回调函数,并未解决问题。
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart){
if(huart->ErrorCode&HAL_UART_ERROR_ORE){
__HAL_UART_CLEAR_OREFLAG(huart);
}
}
想到可以接收完后disable串口
while (1)
{
HAL_Delay(1000);
__HAL_UART_ENABLE(&huart1);
HAL_UART_Receive_IT(&huart1,string3,5);
recog=0;while(!recog);
__HAL_UART_DISABLE(&huart1);
}
}
调试后发现,问题终于解决。
补充: 在hal库函数发现这条语句,因此不进接收中断。
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
{
UART_EndRxTransfer(huart);
|