zoukankan      html  css  js  c++  java
  • 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 宏定义 为空

    Talk is cheap, show me the code
  • 相关阅读:
    手机号码正则表达式
    POJ 3233 Matrix Power Series 矩阵快速幂
    UVA 11468
    UVA 1449
    HDU 2896 病毒侵袭 AC自动机
    HDU 3065 病毒侵袭持续中 AC自动机
    HDU 2222 Keywords Search AC自动机
    POJ 3461 Oulipo KMP模板题
    POJ 1226 Substrings KMP
    UVA 1455 Kingdom 线段树+并查集
  • 原文地址:https://www.cnblogs.com/birdBull/p/15593848.html
Copyright © 2011-2022 走看看