stm32 HAL库 串口无法接收数据的问题

 

最近在测试串口收发的时候,发现串口会出现无法接收数据的情况,后来在网上查找资料,发现是库的问题

发送用的 HAL_UART_Transmit,接收数据使用的是中断方式 HAL_UART_Receive_IT

 HAL_UART_Transmit在发送的过程中,如果这时候来了接收中断,就有可能会出现挂掉的情况了,为什么呢?来看一下 HAL_UART_Transmit函数内部实现

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint8_t  *pdata8bits;
  uint16_t *pdata16bits;
  uint32_t tickstart = 0U;

  /* Check that a Tx process is not already ongoing */
  if (huart->gState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return  HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;

    /* Init tickstart for timeout management */
    tickstart = HAL_GetTick();

    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    /* In case of 9bits/No Parity transfer, pData needs to be handled as a uint16_t pointer */
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
      pdata8bits  = NULL;
      pdata16bits = (uint16_t *) pData;
    }
    else
    {
      pdata8bits  = pData;
      pdata16bits = NULL;
    }

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    while (huart->TxXferCount > 0U)
    {
      if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }
      if (pdata8bits == NULL)
      {
        huart->Instance->DR = (uint16_t)(*pdata16bits & 0x01FFU);
        pdata16bits++;
      }
      else
      {
        huart->Instance->DR = (uint8_t)(*pdata8bits & 0xFFU);
        pdata8bits++;
      }
      huart->TxXferCount--;
    }

    if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
    {
      return HAL_TIMEOUT;
    }

    /* At end of Tx process, restore huart->gState to Ready */
    huart->gState = HAL_UART_STATE_READY;

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

我们注意到 __HAL_LOCK(huart); 函数,这是对串口资源的上锁,然后调用__HAL_UNLOCK(huart);进行解锁

再跟踪一下 __HAL_LOCK函数 ,这是一个宏定义

#if (USE_RTOS == 1U)
  /* Reserved for future use */
  #error "USE_RTOS should be 0 in the current HAL release"
#else
  #define __HAL_LOCK(__HANDLE__)                                           \
                                do{                                        \
                                    if((__HANDLE__)->Lock == HAL_LOCKED)   \
                                    {                                      \
                                       return HAL_BUSY;                    \
                                    }                                      \
                                    else                                   \
                                    {                                      \
                                       (__HANDLE__)->Lock = HAL_LOCKED;    \
                                    }                                      \
                                  }while (0U)

  #define __HAL_UNLOCK(__HANDLE__)                                          \
                                  do{                                       \
                                      (__HANDLE__)->Lock = HAL_UNLOCKED;    \
                                    }while (0U)
#endif /* USE_RTOS */

 

这里, 如果资源已上锁,调用 __HAL_LOCK 会直接返回 HAL_BUSY,这很关键。

我们再来看一下 HAL_UART_Receive_IT函数 

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)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    /* Set Reception type to Standard reception */
    huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;

    return(UART_Start_Receive_IT(huart, pData, Size));
  }
  else
  {
    return HAL_BUSY;
  }
}

这里 我们看到 打开中断的函数里面,也调用了__HAL_LOCK(huart);  如果这时候串口已经上锁了,就直接返回 HAL_BUSY,打开中断的 UART_Start_Receive_IT就没有调用,因此就无法打开串口接收中断了,也就出现了接收不到数据的情况了

 

解决办法:

    屏蔽 __HAL_LOCK ,这种方法暴力直接

还有其他办法, 比如  USE_RTOS 赋值 1, 把 __HAL_LOCK 宏定义 为空

或者自己写中断函数  https://blog.csdn.net/m0_47132384/article/details/105597097?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-105597097-blog-101616136.pc_relevant_antiscanv3&spm=1001.2101.3001.4242.1&utm_relevant_index=3

 

posted @ 2021-11-23 16:31  小小小p鱼  阅读(4180)  评论(0编辑  收藏  举报