• 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
  • 相关阅读:
    Java并发编程:synchronized
    对一致性Hash算法,Java代码实现的深入研究
    在Xcode中使用Git进行源码版本控制
    这些 Git 技能够你用一年了
    简明 Git 命令速查表
    Git 分支管理是一门艺术
    2016年Web前端面试题目汇总
    iOS 面试基础题目
    Json数据交互格式介绍和比较
    SpringBoot端口和访问路径
  • 原文地址:https://www.cnblogs.com/birdBull/p/15593848.html
Copyright © 2020-2023  润新知