STM32F4 HAL庫 UART相關操作API介紹


STM32F4 HAL庫 UART相關操作API介紹

本文絕大部分翻譯自ST的官方用戶手冊 Description of STM32F4 HAL and LL drivers

USART 與 UART 的區別在於有沒有同步通信的功能。
USART: 通用同步異步收發器 ; UART: 通用異步收發器。

當進行異步通信時,這兩者是沒有區別的。
這個同步通信功能可以把USART當做SPI來用,比如用USART來驅動SPI設備。

同步(阻塞模式)是指:發送方發出數據后,等接收方發回響應以后才發下一個數據包的通訊方式。
異步(非阻塞模式)是指:發送方發出數據后,不等接收方發回響應,接着發送下個數據包的通訊方式。

其中SPI IIC為同步通信 UART為異步通信, usart為同步&異步通信。

參考:https://blog.csdn.net/anbaixiu/article/details/78635913



硬件相關知識

STM32F427/STM32F429 共有4個USART與4個UART,如下表

序號 U(S)ART_RX引腳 U(S)ART_TX引腳 U(S)ART_CK引腳 USART_ CTS引腳 USART_ RTS引腳
USART1 PA10 PA9 PA8 PA11 PA12
USART2 PA3/PD6 PA2/PD5 PA4/PD7 PA0/PD3 PA1/PD4
USART3 PB11/PC11/PD9 PB10/PC10/PD8 PB12/PC12/PD10 PB13/PD11 PB14/PD12
UART4 PA1/PC11 PA0/PC10
UART5 PD2 PC12
USART6 PC7/PG9 PC6/PG14 PC8/PG7 PG13/PG15 PG8/PG12
UART7 PE7 PE8
UART8 PE0 PE1

RT: Receive Data 接收數據
TX: Transmit Data 發送數據
CK: Clock (同步)時鍾

硬件流控制

RTS: Request To Send 請求發送數據
CTS: Clear To Send 允許發送數據

參見: UART通信中流控RTS和CTS的理解 https://blog.csdn.net/u013797023/article/details/77935535

相關結構體變量

USRT_InitTypeDef

  • 該結構體定義了用於初始化UART的一些相關參數
typedef struct
{
  uint32_t BaudRate;  //波特率
  uint32_t WordLength;//字長 取值參考 UART_Word_Length 宏定義              
  uint32_t StopBits;  //停止位 取值參考 UART_Stop_Bits 宏定義         
  uint32_t Parity;    //奇偶校驗模式 取值參考 UART_Parity 宏定義 
  uint32_t Mode;      //收發模式 取值參考 UART_Mode 宏定義                
  uint32_t HwFlowCtl; //是否打開硬件流控制 取值參考 UART_Hardware_Flow_Control 宏定義                 
  uint32_t OverSampling;//是否打開過采樣模式 取值參考 UART_Over_Sampling 宏定義            .
}UART_InitTypeDef;

UART_HandleTypeDef

  • 該結構體定義的則是UART句柄(個人理解為用於操作UART)的一些參數

  • 該結構體中只有*InstanceInit兩個成員變量是需要我們配置的

typedef struct
{
  USART_TypeDef                 *Instance;        /*!< UART registers base address        */
    											  // UART/USART相關寄存器的地址 已經在HAL庫中定義完 參數為 U(S)ARTx x=1...8 
  UART_InitTypeDef              Init;             /*!< UART communication parameters      */
    											  // UART初始化參數結構體
  uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */
    											  // 緩存指針
  uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */
    											  // 緩存指針指向的數據的大小(字節)
  uint16_t                      TxXferCount;      /*!< UART Tx Transfer Counter           */
    											  // 緩存指針指向的數據的的數量(字節)
  uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */
  uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */
  uint16_t                      RxXferCount;      /*!< UART Rx Transfer Counter           */  
  DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      *
  												  // DMA句柄
  DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */
  HAL_LockTypeDef               Lock;             /*!< Locking object                     */
    											  // 鎖對象
  __IO HAL_UART_StateTypeDef    State;            /*!< UART communication state           */
    											  // UART通信狀態
  __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */
    											  // 錯誤碼
}UART_HandleTypeDef;
  • HAL Locked The HAL lock is used by all HAL APIs to prevent accessing by accident shared resources.
    HAL庫中的API通過該參數來判斷某個API是否正在執行,如__HAL_LOCK(__HANDLE__)__HAL_UNLOCK(__HANDLE__)所實現的

    typedef enum { 
        HAL_UNLOCKED = 0x00, /*!<Resources unlocked*/ 
        HAL_LOCKED = 0x01 /*!< Resources locked */ 
    }HAL_LockTypeDef;
    #define __HAL_LOCK(__HANDLE__)                                           \
                                    do{                                        \
                                        if((__HANDLE__)->Lock == HAL_LOCKED)   \
                                        {                                      \
                                           return HAL_BUSY;                    \
                                        }                                      \
                                        else                                   \
                                        {                                      \
                                           (__HANDLE__)->Lock = HAL_LOCKED;    \
                                        }                                      \
                                      }while (0)
    #define __HAL_UNLOCK(__HANDLE__)                                          \
                                      do{                                       \
                                          (__HANDLE__)->Lock = HAL_UNLOCKED;    \
                                        }while (0)
    

使用方法

  1. 聲明 UART_HandleTyperDef 句柄結構體
  2. 使用HAL_UART_MspInit()初始化 UART 的底層資源
    1. 打開 USARTx 接口的時鍾
    2. 配置 UART 引腳
      1. 開啟 GPIO 時鍾
      2. 配置引腳模式為 復用上拉
    3. 如果使用了中斷需要配合 NVIC 中斷優先級
      1. 配置優先級
      2. 啟動 NVIC USART IRQ 句柄
    4. 如果使用了DMA處理需要配置DMA
      1. 為 輸入流 或 輸出流 聲明DMA句柄
      2. 開啟DMAx接口的時鍾
      3. 配置DMA句柄結構體的參數
      4. 配置DMA的輸入輸出流
      5. 將DMA句柄與UART DMA Tx/Rx句柄關聯
      6. 配置並啟用 NVIC
  3. 配置 UART 通信的上層參數,包括波特率、字長、停止位等
  4. 根據不同的工作模式調用不同的初始化函數HAL_UART_Init() 異步通信 HAL_HalfDuplex_Init() 半雙工通信HAL_LIN_Init() LIN總線通信HAL_MultiProcessor_Init() 多處理器通信

相關函數API介紹

初始化類函數

  1. HAL_StatusTypeDef HAL_UART_Init (UART_HandleTypeDef * huart)
  2. HAL_StatusTypeDef HAL_HalfDuplex_Init (UART_HandleTypeDef * huart)
  3. HAL_StatusTypeDef HAL_LIN_Init (UART_HandleTypeDef * huart, uint32_t BreakDetectLength)
  4. HAL_StatusTypeDef HAL_MultiProcessor_Init (UART_HandleTypeDef * huart, uint8_t Address, uint32_t WakeUpMethod)
  5. HAL_StatusTypeDef HAL_UART_DeInit (UART_HandleTypeDef * huart)
  • UART上層參數的初始化/注銷函數,根據工作模式選用相應的初始化函數

  • 需要配置的參數包括 波特率、字長、停止位、奇偶校驗模式、是否開啟硬件流控制、收發模式、過采樣模式

  • 參數說明:

    • *huart UART句柄結構體的指針
  • 返回API的執行情況,調用時注意檢查

  1. void HAL_UART_MspInit (UART_HandleTypeDef * huart)
  2. void HAL_UART_MspDeInit (UART_HandleTypeDef * huart)
  • UART底層參數的初始化/注銷函數,具體配置內容見使用方法說明
  • 在代碼移植時修改該配置初始化函數即可

輪詢(Polling)模式的IO操作

  1. HAL_StatusTypeDef HAL_UART_Transmit (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size, uint32_t Timeout)

  2. HAL_StatusTypeDef HAL_UART_Receive (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size, uint32_t Timeout)

  • 用於接收與發送數據

  • 阻塞模式,在接收、發送數據時無法進行其他操作

  • 參數說明:

    • *huart: UART句柄,用於操作UART
    • *pData: 緩沖區指針
    • Size: 緩沖區大小(以字節為單位)
    • Timeout: 超時時間,不可能讓程序一直等待數據接收或發送,超過這個時間之后將放棄發送或接收
  • 返回該API的執行狀態

中斷模式的IO操作

  1. HAL_StatusTypeDef HAL_UART_Transmit_IT (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)

  2. HAL_StatusTypeDef HAL_UART_Receive_IT (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)

  • 用於開啟UART接收/發送中斷,這兩個函數會設置發送/接收的緩沖區地址,大小,數量並且開啟相應的中斷

  • 參數說明:

    • *huart: UART句柄,用於操作UART
    • *pData: 緩沖區指針
    • Size: 緩沖區大小(以字節為單位)
  • 返回該API的執行狀態,調用時注意檢查

HAL_UART_Receive_IT()為例

/**
  * @brief  Receives an amount of data in non blocking mode 
  * @param  huart: pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @param  pData: Pointer to data buffer
  * @param  Size: Amount of data to be received
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t tmp = 0;
  tmp = huart->State;  
  if((tmp == HAL_UART_STATE_READY) || (tmp == HAL_UART_STATE_BUSY_TX))
  {
    if((pData == NULL ) || (Size == 0)) 
    {
      return HAL_ERROR;
    }
    /* Process Locked */
    __HAL_LOCK(huart);
    
    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    huart->RxXferCount = Size;
    
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    /* Check if a transmit process is ongoing or not */
    if(huart->State == HAL_UART_STATE_BUSY_TX) 
    {
      huart->State = HAL_UART_STATE_BUSY_TX_RX;
    }
    else
    {
      huart->State = HAL_UART_STATE_BUSY_RX;
    }
    
    /* Enable the UART Parity Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
    
    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
    
    /* Process Unlocked */
    __HAL_UNLOCK(huart);
    
    /* Enable the UART Data Register not empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
    
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}
  1. void HAL_UART_IRQHandler (UART_HandleTypeDef * huart)
  • UART中斷處理的公共函數,需要用戶在中斷處理函數void USARTx_IRQHandler()中調用該函數,或者可以由STM32CubeMX程序自動生成。
  • 該函數會遍歷所有與UART有關的中斷類型並判斷是否發生錯誤(設置錯誤代碼),若沒有發生錯誤則進行發送/接收操作
  • 若發生錯誤會調用 回調函數HAL_UART_ErrorCallback()
  • 發送完成將調用 回掉函數HAL_UART_TxCpltCallback()
  • 接收完成(接收緩沖區滿)將調用會 回調函數HAL_UART_RxCpltCallback() ,若不想關閉接收需要在該回調函數中重新開啟接收中斷HAL_UART_Receive_IT()

/**
  * @brief  This function handles UART interrupt request.
  * @param  huart: pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t tmp1 = 0, tmp2 = 0;

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  
  /* UART parity error interrupt occurred ------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_PEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_PE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART frame error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_FEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_FE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART noise error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_NEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_NE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART Over-Run interrupt occurred ----------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_OREFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_ORE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
  /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    UART_Receive_IT(huart);
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);
  /* UART in mode Transmitter ------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_Transmit_IT(huart);
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC);
  /* UART in mode Transmitter end --------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_EndTransmit_IT(huart);
  }

  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
    
    HAL_UART_ErrorCallback(huart);
  }  
}

總結一下中斷模式下HAL庫實現UART通信的流程

  1. 調用HAL_UART_Init()初始化UART(該函數會調用HAL_UART_MspInit()來初始化底層服務)

  2. 調用HAL_UART_Receive/Transmit_IT()准備開始接收或者發送數據

  3. 每接收/發送一個字節的數據時便會觸發中斷服務函數USARTx_IRQHandler()

  4. 中斷服務函數中調用中斷公共函數HAL_UART_IRQHandler()

  5. 檢查沒有錯誤后按照條件調用UART_Receive_IT() UART_Transmit_IT() UART_EndTransmit_IT()三個函數中的一個,當發送/接收完成后調用相應的回調函數(根據HAL_UART_Receive/Transmit_IT()的size參數來判斷是否完成發送/接收)

  6. 若發生錯誤則調用處理錯誤的回調函數。

  • 其中需要用戶實現的函數只有UARTx的中斷服務函數與相應的回調函數

如要提高程序執行的效率可以重寫USARTx的中斷服務函數,無需調用UART中斷的公共接口而自行更具相應的標識來處理接收或發送的流程。

DMA模式的IO操作

  1. HAL_StatusTypeDef HAL_UART_Transmit_DMA (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)
  2. HAL_StatusTypeDef HAL_UART_Receive_DMA (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)6
  • DMA模式下的發送/接收API
  • 非阻塞模式

UART外設狀態函數

  1. HAL_UART_StateTypeDef HAL_UART_GetState (UART_HandleTypeDef * huart)
  2. uint32_t HAL_UART_GetError (UART_HandleTypeDef * huart)
  • 分別獲取UART的狀態與錯誤代碼(宏定義)

宏定義介紹

具體參見stm32f4xx_hal.h頭文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM