詳解STM32CubeIDE 中 HAL庫的串口中斷接收函數 HAL_UART_Receive_IT

MX串口配置方法見:CubeIDE 利用自帶HAL庫 串口收發

 

一、代碼自動生成以後的項目及代碼結構:

main.c中,調用了串口初始化

 

串口初始化函數賦值了串口的參數

 

相當於底層的初始化,配置引腳、並開啓中斷。

至此串口1配置完畢

二、庫文件stm32f1xx_hal_uart.c內的祕密

2.1 初始化

1.usart.c中,MX_USART1_UART_Init 調用了庫的HAL_UART_Init,將結構體傳遞進該函數中

2.HAL_UART_Init幹了些什麼事?

 if (huart->gState == HAL_UART_STATE_RESET)
  {
    huart->Lock = HAL_UNLOCKED;
    HAL_UART_MspInit(huart);
  }
huart->gState = HAL_UART_STATE_BUSY; 
  __HAL_UART_DISABLE(huart);  /* Disable the peripheral */
  UART_SetConfig(huart);/* Set the UART Communication parameters */

  /* In asynchronous mode, the following bits must be kept cleared:
     - LINEN and CLKEN bits in the USART_CR2 register,
     - SCEN, HDSEL and IREN  bits in the USART_CR3 register.*/
  CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
  CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
  __HAL_UART_ENABLE(huart);  /* Enable the peripheral */
  huart->ErrorCode = HAL_UART_ERROR_NONE;
  huart->gState = HAL_UART_STATE_READY;
  huart->RxState = HAL_UART_STATE_READY;

調用MspInit-->修改狀態忙-->配置寄存器-->清楚標誌位 

2.2 先理解HAL_UART_Receive函數

uint32_t tickstart = 0U;

if (huart->RxState == HAL_UART_STATE_READY)  /* Check that a Rx process is not already ongoing */
  {
    __HAL_LOCK(huart);    /* Process Locked */

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;

    tickstart = HAL_GetTick();

    huart->RxXferSize = Size;
    huart->RxXferCount = Size;


    while (huart->RxXferCount > 0U)
    {
      huart->RxXferCount--;
      if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
            return HAL_TIMEOUT;
      *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
      }
}

    huart->RxState = HAL_UART_STATE_READY;
    __HAL_UNLOCK(huart);

判斷是否忙-->鎖住-->標記接收忙-->獲取tick計數

-->賦值RxXferCount有多少數據要接收-->每次從DR內獲取一個Byte存在pData指向的空間

2.3 HAL_UART_Receive_IT只是配置了一下參數,並沒有做任何處理

/* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    __HAL_LOCK(huart);    /* Process Locked */
    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    huart->RxXferCount = Size;
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;
    __HAL_UNLOCK(huart);    /* Process Unlocked */

    /*Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);

    /* Enable the UART Data Register not empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

    return HAL_OK;
    }

存儲在pData指向位置、空間大小RxXferSize 、接收計數RxXferCount ; 接收狀態忙;使能接收中斷

那麼當有數據來的時候,就需要依靠中斷函數來處理了。

2.4再看看中斷函數在做什麼

stm32f1xx_it.c內有定義USART1_IRQHandler,只調用了HAL_UART_IRQHandler函數,下面是

HAL_UART_IRQHandler具體內容

errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if (errorflags == RESET)
  {
    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }

  /* If some errors occur */
  if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
//略過錯誤處理
    /* Call UART Error Call back function if need be --------------------------*/
    if (huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
      /* UART in mode Receiver -----------------------------------------------*/
      if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
        UART_Receive_IT(huart);
//略過錯誤處理
        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }
    }
    return;
  } /* End if some error occurs */

  /* UART in mode Transmitter ------------------------------------------------*/
  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  {    UART_Transmit_IT(huart);    return;  }

  /* UART in mode Transmitter end --------------------------------------------*/
  if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  {    UART_EndTransmit_IT(huart);    return;  }

無非是三件事,判斷是由什麼中斷響應的,有錯誤則處理,響應要調用的接收或者發送。

注意區別 UART_Receive_IT 和 HAL_UART_Receive_IT。

HAL_UART_Receive_IT是用戶調用的需要接收多少數據存在何處。

UART_Receive_IT是中斷調用的有數據收到該如何處理。

2.5 UART_Receive_IT 真正在接收數據的函數,但在最後會關閉中斷

  uint16_t *tmp;

  /* Check that a Rx process is ongoing */
  if (huart->RxState == HAL_UART_STATE_BUSY_RX)
  {
    *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
    if (--huart->RxXferCount == 0U)
    {
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
      __HAL_UART_DISABLE_IT(huart, UART_IT_PE);
      __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

      huart->RxState = HAL_UART_STATE_READY;

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
      /*Call registered Rx complete callback*/
      huart->RxCpltCallback(huart);
#else
      /*Call legacy weak Rx complete callback*/
      HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

      return HAL_OK;
    }
    return HAL_OK;
  }

如果是接收狀態忙,則從DR中讀取1Byte數據。

如果接收計數歸零,則使中斷失效,並調用回調函數(用戶定義則調用用戶的,否則調用系統的)

至此,所有用到的代碼分析完畢

三、總結

1、HAL_UART_Receive_IT和HAL_UART_Receive的區別就是:中斷接收是有數據到了纔去讀;直接接收是直接讀取,如果超時就返回

2、HAL_UART_Receive_IT配置後,有數據來,計數會在調用中斷函數之後自動減1。只有到計數爲0時,纔會關閉中斷調用回調函數。至此有數據來不再調用中斷函數,因爲中斷已經失效。

3、HAL_UART_Receive_IT在計數未至0之前,應該可以讀取之前接收到的數據,但這樣做應該比較危險。

4、在開源電子的例程中,使用 HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, 1);  即Size設置爲1,只接收1Byte數據,在每次中斷結束後重新配置來使能中斷。

四、還有必要再看一眼uart的結構體定義

/**
  * @brief  UART handle Structure definition
  */
typedef struct __UART_HandleTypeDef
{
  USART_TypeDef                 *Instance;        /*!< UART registers base address        */

  UART_InitTypeDef              Init;             /*!< UART communication parameters      */

  uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */

  uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */

  __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter           */

  uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */

  uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */

  __IO uint16_t                 RxXferCount;      /*!< UART Rx Transfer Counter           */

  DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      */

  DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */

  HAL_LockTypeDef               Lock;             /*!< Locking object                     */

  __IO HAL_UART_StateTypeDef    gState;           /*!< UART state information related to global Handle management
                                                       and also related to Tx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO HAL_UART_StateTypeDef    RxState;          /*!< UART state information related to Rx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Tx Half Complete Callback        */
  void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Tx Complete Callback             */
  void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Rx Half Complete Callback        */
  void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Rx Complete Callback             */
  void (* ErrorCallback)(struct __UART_HandleTypeDef *huart);             /*!< UART Error Callback                   */
  void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Abort Complete Callback          */
  void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
  void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart);  /*!< UART Abort Receive Complete Callback  */
  void (* WakeupCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Wakeup Callback                  */

  void (* MspInitCallback)(struct __UART_HandleTypeDef *huart);           /*!< UART Msp Init callback                */
  void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Msp DeInit callback              */
#endif  /* USE_HAL_UART_REGISTER_CALLBACKS */

} UART_HandleTypeDef;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章