HAL串口死机原因分析及其解决方法

目前串口死掉,有两种情况,其实都是不熟悉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:检测串口的 空闲标志(可以中断处理),空闲时 调用以初始化上函数

猜你喜欢

转载自blog.csdn.net/tangjienihaoma/article/details/81627287