目前串口死掉,有两种情况,其实都是不熟悉HAL库 造成的。
第1种:ORE错误问题。
第2种:全双工运行时,出现的互锁现象(__HAL_LOCK(huart))。
第1种串口死机分析:
先分析下 接收初始下化函数
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if(huart->RxState == HAL_UART_STATE_READY)
{
。。。。。。。。
huart->RxState = HAL_UART_STATE_BUSY_RX;//把接收状态改为忙,避免多次初始化
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(huart->Instance->CR3, USART_CR3_EIE);//这里开启了以上所有的错误检测中断
/* Enable the UART Parity Error and Data Register not empty Interrupts */
SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);//使能奇偶校验中断和接收非空中断。//从这里可以看出,错误中断的开关有两个,1个是奇偶校验,1个是Frame error, noise error, overrun error。
}
}
注意这里的huart->RxState ,值必须为HAL_UART_STATE_READY才能完成初始化。
收到数据后,进入中断服务函数void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
判断是有错误标志置位,如没有则执行UART_Receive_IT(huart)函数,解析此函数首先看 huart->RxState = HAL_UART_STATE_BUSY_RX;接收 数据,如果到最后一个字节了,则
if(--huart->RxXferCount == 0U)
{
/* Disable the UART Parity Error Interrupt and RXNE interrupt*/
CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Rx process is completed, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
HAL_UART_RxCpltCallback(huart);
return HAL_OK;
}
可以看出到了最后一个字节,将关闭以上3类中断(错误中断、奇偶校验中断。接收非空中断)。
如果检测到ORE错误标志,将调用UART_EndRxTransfer(huart);关闭 以上3类中断,造成串口假死的原因。
这样就接收不了后续的数据了。严格上说只能接收到1个数据,后面的数据会全部丢失。
}
解决方法:
发现错误后,进入错误回调函数重新打开串口接收非空中断,以下直接用的是串口接收函数初始化
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE)!=RESET)//可以不要
{
__HAL_UART_CLEAR_OREFLAG(&huart1);
}
HAL_UART_Receive_IT(&huart1, buf, 100);
}
有个没有搞清楚的问题,追踪发现,不管你是否清除ORE标志位都会再次进入overrun中断,最后ORE自动清0,这一点不知道为什么,后面调试再解决。
第2种串口死机分析:
此函数中可以看到HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout),
先上锁 __HAL_LOCK(huart),数据发送完之后,才会解锁 __HAL_UNLOCK(huart)。如果此过程中想要调用有上锁的 函数,都会返回HAL_BUSY,导致配置失败。举例:这类函数如下
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
解决方式1:强制解锁,就是在调用以上初始化函数时,强制 调用__HAL_UNLOCK(huart)进行解锁。
解决 方式2:检测串口的 空闲标志(可以中断处理),空闲时 调用以初始化上函数