【STM32H7教程】第65章 STM32H7的低功耗串口LPUART基礎知識和HAL庫API

完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

第65章       STM32H7的低功耗串口LPUART基礎知識和HAL庫API

本章節爲大家講解LPUART(Low power universal asynchronous receiver transmitter,低功耗通用異步收發器)的基礎知識和對應的HAL庫API。相比第29章的通用串口,增加了低功耗特性。

目錄

第65章       STM32H7的低功耗串口LPUART基礎知識和HAL庫API

65.1 初學者重要提示

65.2 低功耗串口基礎知識

65.2.1 低功耗串口的硬件框圖

65.2.2 低功耗串口的基本功能

65.2.3 低功耗串口的高級特性

65.2.4 低功耗串口的數據幀格式

65.2.5 低功耗串口的支持的時鐘和波特率

65.2.6 低功耗串口的支持喚醒方式

65.2.7 低功耗串口發送時序圖

65.2.8 單工,半雙工和全雙工通訊

65.3 低功耗串口的HAL庫用法

65.3.1 低功耗串口寄存器結構體USART_TypeDef

65.3.2 低功耗串口句柄結構體UART_HandleTypeDef

65.3.3 低功耗串口的底層配置(GPIO、時鐘、中斷等)

65.3.4 低功耗串口的狀態標誌清除問題

65.3.5 低功耗串口初始化流程總結

65.4 低功耗源文件stm32h7xx_hal_uart.c

65.4.1 函數HAL_UART_Init

65.4.2 函數HAL_UART_Transmit

65.4.3 函數HAL_UART_Receive

65.4.4 函數HAL_UART_Transmit_IT

65.4.5 函數HAL_UART_Receive_IT

65.4.6 函數HAL_UART_Transmit_DMA

65.4.7 函數HAL_UART_Receive_DMA

65.5 總結


 

65.1 初學者重要提示

  1.   特別注意,LPUART沒有自己的HAL庫驅動文件,是跟通用串口公用的驅動文件。
  2.   學習串口外設推薦從硬件框圖開始瞭解基本的功能特性,然後逐步深入瞭解各種特性,這種方式方便記憶和以後查閱。而串口的通信學習,推薦看時序圖。

65.2 低功耗串口基礎知識

LPUART的全稱是Low power universal synchronous asynchronous receiver transmitter,中文意思是低功耗通用異步收發器,簡稱LPUART。

65.2.1 低功耗串口的硬件框圖

認識一個外設,最好的方式就是看它的框圖,方便我們快速的瞭解串口的基本功能,然後再看手冊瞭解細節。

通過這個框圖,我們可以得到如下信息:

  •   IRQ Interface中斷接口

用於實現中斷方式的串口喚醒lpusart_wkup和串口的相關中斷lpusart_it。

  •   DMA Interface DMA接口

實現串口發送lpuart_tx_dma和接收lpuart_rx_dma的DMA方式。

  •   COM Contronller串口控制器

串口相關的寄存器基本都在這部分。

  •   TxFIFO和RxFIFO

串口的發送和接收都支持了硬件FIFO功能。

  •   TX和RX引腳的互換功能

發送偏移寄存器(TX Shift Reg)和接收偏移寄存器(RX Shift Reg)與TX引腳,RX引腳之間弄了個交叉連接,這裏的意思是支持了引腳互換功能,這樣大家在設計PCB的時候就可以比較隨性了,接反了也沒有關係。

  •   發送過程經過的寄存器

依次是LPUART_TDR -> TxFIFO ->Tx Shift Reg偏移寄存器 –> TX或者RX引腳。

  •   接收經過的寄存器

依次是TX或者RX引腳-> Rx Shift Reg偏移寄存器->RxFIFO –>LPUART_RDR。

  •   兩個時鐘lpuart_pclk和lpuart_ker_ck

這兩個時鐘是獨立的,作用如下:

    •   lpuart_pclk

用於爲外設總線提供時鐘。

    •   lpuart_ker_ck

串口外設的時鐘源。

65.2.2 低功耗串口的基本功能

STM32的串口功能很強大,支持太多的模式。我們只需關心我們最常用的特性即可。我們的串口驅動使用的串口中斷+FIFO結構,沒有使用DMA。因此我們只討論和串口中斷、串口常規參數有關的知識。

STM32串口的優越特性:(只列了舉常用的)

  •   各種波特率。硬件採用分數波特率發生器系統,可以設置各種需要的波特率
  •   可編程數據字長度,支持7bit,8bit和9bit。
  •   可配置的停止位。支持1或2個停止位。
  •   發送器和接收器可以單獨使能。比如GPS應用只需要串口接收,那麼發送的GPIO就可以節省出來用作其他功能。
  •   檢測標誌和中斷:
    •  接收緩衝器滿,可產生中斷。串口中斷服務程序據此判斷是否接收到數據。
    •  發送緩衝器空,可產生中斷。串口中斷服務程序據此啓動發送下一個數據。
    •  傳輸結束標誌,可產生中斷。用於RS485通信,等最後一個字節發送完畢後,需要控制RS485收發器芯片切換爲接收模式。

 

其它中斷不常用,包括:CTS改變、LIN斷開符檢測、檢測到總線爲空閒(在DMA不定長接收方式會用到)、溢出錯誤、幀錯誤、噪音錯誤、校驗錯誤。

65.2.3 低功耗串口的高級特性

H7系列的串口支持了一些高級特性,比如:

  •   數據邏輯電平翻轉。
  •   低功耗特性。
  •   RX和TX引腳交換。
  •   MSB位先發送。
  •   外接485的PHY芯片時,硬件支持收發切換,無需用戶手動控制DE引腳。

 

相比第29章的通用串口,低功耗串口不支持超時接收和自適應波特率。

65.2.4 低功耗串口的數據幀格式

串口支持的幀格式如下(M和PCE都是LPUART_CR1寄存器的位,其中M位用於控制幀長度,PCE用於使能奇偶校驗位):

 

這裏特別注意奇偶校驗位,用戶在配置的時候可以選擇奇校驗和偶校驗,校驗位是佔據的最高位。比如選擇M=00,PCE=1,即7bit的數據位。

  •   串口發送數據:

如果發送的7bit數據是111 0011,這個裏面有奇數個1,那麼選擇偶校驗的情況下,校驗位 = 1,湊夠偶數個1,而選擇奇校驗的情況下,校驗位 = 0,因爲已經是奇數個1。校驗位不需要用戶去計算,是硬件自動生成的。

  •   串口接收數據:

根據用戶設置的奇校驗或者偶校驗類型,串口硬件會對接收到的數據做校驗,如果失敗,LPUART_ISR寄存器的PE位會被置1。如果使能了對應的中斷PEIE,那麼失敗的時候還會產生中斷。

 

瞭解到幀格式後,再來看一下實際數據發送時,數據位的先後順序:

 

65.2.5 低功耗串口的支持的時鐘和波特率

低功耗定時器支持如下幾種時鐘:

這裏我們重點關注PCLK3(D3PCLK1),HSI和LSE。

  •   LPUART時鐘選擇LSE(32768Hz)

最高速度是10922bps,最低8bps(計算方法3x < 32768 < 4096x,x表示波特率)。

  •   LPUART時鐘選擇HSI(64MHz)

最高值是21MHz,最小值15625bps(計算方法3x < 64MHz < 4096x,x表示波特率)。

  •   LPUART時鐘選擇D3PCLK1(100MHz)

最大值33Mbps,最小值24414bps(計算方法3x < 100MHz < 4096x,x表示波特率)。

65.2.6 低功耗串口的支持喚醒方式

低功耗串口的喚醒主要是通過接收數據來喚醒,具體喚醒的方如下:

  •   檢測到起始位喚醒。
  •   檢測到RXNE標誌喚醒,即接收到數據。
  •   檢測到匹配地址時喚醒。

匹配地址支持7bit和4bit匹配兩種方式,比如我們採用7bit匹配,設置地址是0x19,那麼用戶喚醒的時候要將最高bit設置爲1,即發送地址0x99(0b1001 1001)纔可以喚醒。

喚醒成功時的時序效果如下,特別注意喚醒信號位置:

 

喚醒失敗時的時序效果:

 

65.2.7 低功耗串口發送時序圖

這個時序圖非常具有代表性,可以幫助大家很好的理解TC發送完成中斷和TXE空中斷。

 

65.2.8 單工,半雙工和全雙工通訊

單工:在一個單工的串行通訊系統中,一般至少有兩根線(信號線和地線),數據傳送只有一個方向,例如可以使用單工數據傳送將數據從一個簡單的數據監測系統傳送到PC上。

半雙工:在半雙工串行通信系統中,一般同樣要求至少有兩根線。這裏的數據傳送是雙向的。然而,同一個時刻只能爲一個方向。在上面的數據監測的例子中做了一些變化,可以使用半雙工通訊機制發送信息到嵌入式模塊(來設置參數,比如採樣率)。此外,在其他時候,可以使用這個種連接將嵌入式裝置上的數據下載到PC中。

全雙工:在一個全雙工的串行通信系統中,一般要求至少有三根線(信號線A,信號線B和地線)。信號線A將傳輸一個方向上的數據,同時信號線B傳送另一個方向上的數據。

65.3 低功耗串口的HAL庫用法

串口的HAL庫用法其實就是幾個結構體變量成員的配置和使用,然後配置GPIO、時鐘,並根據需要配置NVIC、中斷和DMA。下面我們逐一展開爲大家做個說明。

65.3.1 低功耗串口寄存器結構體USART_TypeDef

USART相關的寄存器是通過HAL庫中的結構體USART_TypeDef定義的,在stm32h743xx.h中可以找到這個類型定義:

typedef struct
{
  __IO uint32_t CR1;    /*!< USART Control register 1,                 Address offset: 0x00 */
  __IO uint32_t CR2;    /*!< USART Control register 2,                 Address offset: 0x04 */
  __IO uint32_t CR3;    /*!< USART Control register 3,                 Address offset: 0x08 */
  __IO uint32_t BRR;    /*!< USART Baud rate register,                 Address offset: 0x0C */
  __IO uint16_t GTPR;   /*!< USART Guard time and prescaler register,  Address offset: 0x10 */
  uint16_t  RESERVED2;  /*!< Reserved, 0x12                                                 */
  __IO uint32_t RTOR;   /*!< USART Receiver Time Out register,         Address offset: 0x14 */
  __IO uint16_t RQR;    /*!< USART Request register,                   Address offset: 0x18 */
  uint16_t  RESERVED3;  /*!< Reserved, 0x1A                                                 */
  __IO uint32_t ISR;    /*!< USART Interrupt and status register,      Address offset: 0x1C */
  __IO uint32_t ICR;    /*!< USART Interrupt flag Clear register,      Address offset: 0x20 */
  __IO uint16_t RDR;    /*!< USART Receive Data register,              Address offset: 0x24 */
  uint16_t  RESERVED4;  /*!< Reserved, 0x26                                                 */
  __IO uint16_t TDR;    /*!< USART Transmit Data register,             Address offset: 0x28 */
  uint16_t  RESERVED5;  /*!< Reserved, 0x2A                                                 */
  __IO uint32_t PRESC;  /*!< USART clock Prescaler register,           Address offset: 0x2C */
} USART_TypeDef;

 

這個結構體的成員名稱和排列次序和CPU的USART寄存器是一 一對應的。

__IO表示volatile, 這是標準C語言中的一個修飾字,表示這個變量是非易失性的,編譯器不要將其優化掉。core_m7.h 文件定義了這個宏:

#define     __O     volatile             /*!< Defines 'write only' permissions */
#define     __IO    volatile             /*!< Defines 'read / write' permissions */

 

下面我們看下LPUART的定義,在stm32h743xx.h文件。

#define PERIPH_BASE         (0x40000000UL) 
#define D3_APB1PERIPH_BASE  (PERIPH_BASE + 0x18000000UL)
#define LPUART1_BASE        (D3_APB1PERIPH_BASE + 0x0C00UL)
#define LPUART1             ((USART_TypeDef *) LPUART1_BASE) <----- 展開這個宏,(USART_TypeDef *) 0x58000C00

 

我們訪問LPUART1的CR1寄存器可以採用這種形式:LPUART1->CR1 = 0。

65.3.2 低功耗串口句柄結構體UART_HandleTypeDef

HAL庫在USART_TypeDef的基礎上封裝了一個結構體UART_HandleTypeDef,定義如下:

typedef struct __UART_HandleTypeDef
{
  USART_TypeDef            *Instance;                
  UART_InitTypeDef         Init;                   
  UART_AdvFeatureInitTypeDef AdvancedInit;         
  uint8_t                  *pTxBuffPtr;             
  uint16_t                 TxXferSize;             
  __IO uint16_t            TxXferCount;            
  uint8_t                  *pRxBuffPtr;            
  uint16_t                 RxXferSize;             
  __IO uint16_t            RxXferCount;           
  uint16_t                 Mask;                    
  uint32_t                 FifoMode;                 
  uint16_t                 NbRxDataToProcess;        
  uint16_t                 NbTxDataToProcess;        
  void (*RxISR)(struct __UART_HandleTypeDef *huart);
  void (*TxISR)(struct __UART_HandleTypeDef *huart); 
  DMA_HandleTypeDef        *hdmatx;                 
  DMA_HandleTypeDef        *hdmarx;               
  HAL_LockTypeDef           Lock;                    /
  __IO HAL_UART_StateTypeDef    gState;              
  __IO HAL_UART_StateTypeDef    RxState;            
  __IO uint32_t                 ErrorCode;           

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        
  void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart);            
  void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        
  void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart);          
  void (* ErrorCallback)(struct __UART_HandleTypeDef *huart);             
  void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart);         
  void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); 
  void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart);  
  void (* WakeupCallback)(struct __UART_HandleTypeDef *huart);            
  void (* RxFifoFullCallback)(struct __UART_HandleTypeDef *huart);       
  void (* TxFifoEmptyCallback)(struct __UART_HandleTypeDef *huart);       
  void (* MspInitCallback)(struct __UART_HandleTypeDef *huart);         
  void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart);        
#endif  
} UART_HandleTypeDef;

 

注意事項:

條件編譯USE_HAL_HRTIM_REGISTER_CALLBACKS用來設置使用自定義回調還是使用默認回調,此定義一般放在stm32h7xx_hal_conf.h文件裏面設置:

  #define   USE_HAL_UAR_REGISTER_CALLBACKS   1

通過函數HAL_UART_RegisterCallback註冊回調,取消註冊使用函數HAL_UART_UnRegisterCallback。

這裏重點介紹前三個參數,其它參數主要是HAL庫內部使用和自定義回調函數。

  •   USART_TypeDef  *Instance

這個參數是寄存器的例化,方便操作寄存器,比如使能串口的發送空中斷。

SET_BIT(huart->Instance->CR1,  USART_CR1_TXEIE)。

  •   UART_InitTypeDef  Init

這個參數是用戶接觸最多的,用於配置串口的基本參數,像波特率、奇偶校驗、停止位等。UART_InitTypeDef結構體的定義如下:

typedef struct
{
  uint32_t BaudRate;       /* 波特率 */
  uint32_t WordLength;     /* 數據位長度 */
  uint32_t StopBits;       /* 停止位 */          
  uint32_t Parity;         /* 奇偶校驗位 */          
  uint32_t Mode;           /* 發送模式和接收模式使能 */         
  uint32_t HwFlowCtl;      /* 硬件流控制 */          
  uint32_t OverSampling;   /* 過採樣,可以選擇8倍和16倍過採樣 */        
  uint32_t Prescaler;      /* 串口分頻 */            
  uint32_t FIFOMode;         /* 串口FIFO使能 */         
  uint32_t TXFIFOThreshold;  /* 發送FIFO的閥值 */         
  uint32_t RXFIFOThreshold;  /* 接收FIFO的閥值 */         
}UART_InitTypeDef;

 

  •   UART_AdvFeatureInitTypeDef AdvancedInit

這個參數用於配置串口的高級特性。具體支持的功能參數如下:

typedef struct
{
  uint32_t AdvFeatureInit;       /* 初始化的高級特性類別 */
  uint32_t TxPinLevelInvert;     /* Tx引腳電平翻轉 */
  uint32_t RxPinLevelInvert;     /* Rx引腳電平翻轉 */
  uint32_t DataInvert;           /* 數據邏輯電平翻轉 */
  uint32_t Swap;                 /* Tx和Rx引腳交換 */
  uint32_t OverrunDisable;       /* 接收超時檢測禁止 */
  uint32_t DMADisableonRxError;  /* 接收出錯,禁止DMA */
  uint32_t AutoBaudRateEnable;   /* 自適應波特率使能 */
  uint32_t AutoBaudRateMode;     /* 自適應波特率的四種檢測模式選擇 */
  uint32_t MSBFirst;             /* 發送或者接收數據時,高位在前 */
} UART_AdvFeatureInitTypeDef;

 

配置串口參數,其實就是配置結構體UART_HandleTypeDef的成員。比如下面配置爲波特率115200,8個數據位,無奇偶校驗,1個停止位。

UART_HandleTypeDef UartHandle;

/* 配置如下:
  - 數據位 = 8 Bits
  - 停止位 = 1 bit
  - 奇偶校驗位 = 無
  - 波特率 = 115200bsp
  - 硬件流控制 (RTS 和 CTS 信號) */
UartHandle.Instance        = LPUART1;

UartHandle.Init.BaudRate     = 115200;
UartHandle.Init.WordLength   = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits     = UART_STOPBITS_1;
UartHandle.Init.Parity       = UART_PARITY_NONE;
UartHandle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
UartHandle.Init.Mode         = UART_MODE_TX_RX;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

if(HAL_UART_Init(&UartHandle) != HAL_OK)
{
    Error_Handler();
}

 

65.3.3 低功耗串口的底層配置(GPIO、時鐘、中斷等)

串口外設的基本參數配置完畢後還不能使用,還需要配置GPIO、時鐘、中斷等參數,比如下面配置使用引腳PA9和PA10。

/* LPUART1的GPIO  PA9, PA10 */
#define LPUART1_CLK_ENABLE()              __HAL_RCC_LPUART1_CLK_ENABLE()

#define LPUART1_TX_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOA_CLK_ENABLE()
#define LPUART1_TX_GPIO_PORT              GPIOA
#define LPUART1_TX_PIN                    GPIO_PIN_9
#define LPUART1_TX_AF                     GPIO_AF3_LPUART

#define LPUART1_RX_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOA_CLK_ENABLE()
#define LPUART1_RX_GPIO_PORT              GPIOA
#define LPUART1_RX_PIN                    GPIO_PIN_10
#define LPUART1_RX_AF                     GPIO_AF3_LPUART

/*
*********************************************************************************************************
*    函 數 名: InitHardUart
*    功能說明: 配置串口的硬件參數和底層
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
static void InitHardUart(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;

#if LPUART1_FIFO_EN == 1        
    /* 使能 GPIO TX/RX 時鐘 */
    LPUART1_TX_GPIO_CLK_ENABLE();
    LPUART1_RX_GPIO_CLK_ENABLE();
    
    /* 使能 USARTx 時鐘 */
    LPUART1_CLK_ENABLE();    

    /* 配置TX引腳 */
    GPIO_InitStruct.Pin       = LPUART1_TX_PIN;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = LPUART1_TX_AF;
    HAL_GPIO_Init(LPUART1_TX_GPIO_PORT, &GPIO_InitStruct);    
    
    /* 配置RX引腳 */
    GPIO_InitStruct.Pin = LPUART1_RX_PIN;
    GPIO_InitStruct.Alternate = LPUART1_RX_AF;
    HAL_GPIO_Init(LPUART1_RX_GPIO_PORT, &GPIO_InitStruct);

    /* 配置NVIC the NVIC for UART */   
    HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(LPUART1_IRQn);
  
    /* 配置波特率、奇偶校驗 */
    bsp_SetLPUartParam(LPUART1,  LPUART1_BAUD, UART_PARITY_NONE, UART_MODE_TX_RX);

    SET_BIT(LPUART1->ICR, USART_ICR_TCCF);   /* 清除TC發送完成標誌 */
    SET_BIT(LPUART1->RQR, USART_RQR_RXFRQ);  /* 清除RXNE接收標誌 */
    SET_BIT(LPUART1->CR1, USART_CR1_RXNEIE); /* 使能PE. RX接受中斷 */
#endif
}

 

總結下來就是以下幾點:

  •   配置GPIO引腳時鐘。
  •   配置LPUART時鐘。
  •   配置LPUART的發送和接收引腳。
  •   通過NVIC配置中斷。
  •   配置波特率,奇偶校驗等,在上一小節有講。
  •   清除TC和RXNE標誌,使能接收中斷。

 

關於這個底層配置有以下幾點要着重說明下:

  •   串口發送和接收引腳的複用模式選擇已經被HAL庫定義好,放在了stm32h7xx_hal_gpio_ex.h文件裏面。比如串口1有兩個複用
#define GPIO_AF3_LPUART    ((uint8_t)0x03) /* LPUART Alternate Function mapping */
#define GPIO_AF8_LPUART    ((uint8_t)0x08) /* LPUART Alternate Function mapping */

 

具體使用那個,要看數據手冊,比如我們這裏使用引腳PA9和PA10,對應的複用如下:

那麼使用GPIO_AF3_LPUART1即可。

  •   根據情況要清除TC發送完成標誌和RXNE接收數據標誌,因爲這兩個標誌位在使能了串口後就已經置位,所以當用戶使用了TC或者RX中斷後,就會進入一次中斷服務程序,這點要特別注意。
  •   HAL庫有個自己的底層初始化回調函數HAL_UART_MspInit,是弱定義的,用戶可以在其它的C文件裏面實現,並將相對的底層初始化在裏面實現。當用戶調用HAL_UART_Init後,會在此函數裏面調用HAL_UART_MspInit,對應的底層復位函數HAL_UART_MspDeInit是在函數HAL_UART_DeInit裏面被調用的。

當然,用戶也可以自己初始化,不限制必須在兩個函數裏面實現。

  •   上面舉的例子裏面沒有用到DMA,如果用到了DMA,也是要初始化的。

65.3.4 低功耗串口的狀態標誌清除問題

注,早前使用F1和F4時候,經常會有網友諮詢爲什麼串口中斷服務程序裏面沒有做清除標誌。

下面我們介紹__HAL_USART_GET_FLAG函數。這個函數用來檢查LPUART/USART標誌位是否被設置。

/** @brief  Check whether the specified USART flag is set or not.
  * @param  __HANDLE__: specifies the USART Handle
  * @param  __FLAG__: specifies the flag to check.
  *        This parameter can be one of the following values:
  *            @arg USART_FLAG_TXFT: TXFIFO threshold flag
  *            @arg USART_FLAG_RXFT: RXFIFO threshold flag
  *            @arg USART_FLAG_RXFF:  RXFIFO Full flag
  *            @arg USART_FLAG_TXFE:  TXFIFO Empty flag
  *            @arg USART_FLAG_REACK: Receive enable ackowledge flag
  *            @arg USART_FLAG_TEACK: Transmit enable ackowledge flag
  *            @arg USART_FLAG_BUSY:  Busy flag
  *            @arg USART_FLAG_TXE:   Transmit data register empty flag
  *            @arg USART_FLAG_TC:    Transmission Complete flag
  *            @arg USART_FLAG_RXNE:  Receive data register not empty flag
  *            @arg USART_FLAG_IDLE:  Idle Line detection flag
  *            @arg USART_FLAG_ORE:   OverRun Error flag
  *            @arg USART_FLAG_UDR:   UnderRun Error flag
  *            @arg USART_FLAG_NE:    Noise Error flag
  *            @arg USART_FLAG_FE:    Framing Error flag
  *            @arg USART_FLAG_PE:    Parity Error flag
  * @retval The new state of __FLAG__ (TRUE or FALSE).
  */
#define __HAL_USART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->ISR & (__FLAG__)) == (__FLAG__))

 

USART_FLAG有如下幾種取值:

請大家重點關注上表中紅字部分,LPUART/USART標誌是需要軟件主動清零的。清零有兩種方式:一種是調用__HAL_USART_CLEAR_FLAG函數,另一種是操作相關寄存器後自動清零。

/** @brief  Clear the specified USART pending flag.
  * @param  __HANDLE__: specifies the USART Handle.
  * @param  __FLAG__: specifies the flag to check.
  *          This parameter can be any combination of the following values:
  *            @arg USART_FLAG_TXFT:  TXFIFO threshold flag
  *            @arg USART_FLAG_RXFT:  RXFIFO threshold flag
  *            @arg USART_FLAG_RXFF:  RXFIFO Full flag
  *            @arg USART_FLAG_TXFE:  TXFIFO Empty flag
  *            @arg USART_FLAG_REACK: Receive enable ackowledge flag
  *            @arg USART_FLAG_TEACK: Transmit enable ackowledge flag
  *            @arg USART_FLAG_WUF:   Wake up from stop mode flag
  *            @arg USART_FLAG_RWU:   Receiver wake up flag (is the USART in mute mode)
  *            @arg USART_FLAG_SBKF:  Send Break flag
  *            @arg USART_FLAG_CMF:   Character match flag
  *            @arg USART_FLAG_BUSY:  Busy flag
  *            @arg USART_FLAG_ABRF:  Auto Baud rate detection flag
  *            @arg USART_FLAG_ABRE:  Auto Baud rate detection error flag
  *            @arg USART_FLAG_RTOF:  Receiver timeout flag
  *            @arg USART_FLAG_LBD:   LIN Break detection flag
  *            @arg USART_FLAG_TXE:   Transmit data register empty flag
  *            @arg USART_FLAG_TC:    Transmission Complete flag
  *            @arg USART_FLAG_RXNE:  Receive data register not empty flag
  *            @arg USART_FLAG_IDLE:  Idle Line detection flag
  *            @arg USART_FLAG_ORE:   OverRun Error flag
  *            @arg USART_FLAG_NE:    Noise Error flag
  *            @arg USART_FLAG_FE:    Framing Error flag
  *            @arg USART_FLAG_PE:    Parity Error flag
  * @retval The new state of __FLAG__ (TRUE or FALSE).
  */
#define __HAL_USART_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->ICR = (__FLAG__))

 

上面介紹的USART標誌大部分能夠設置爲產生中斷,也就是有對應的USART中斷標誌。我們只介紹幾個串口驅動要用到的中斷標誌:

USART_IT_TXETXE:發送數據寄存器空(此時數據可能正在發送)。

USART_IT_TC發送完成 。

USART_IT_RXNE接收數據寄存器非空。

中斷缺省都是關閉的,通過__HAL_USART_ENABLE_IT函數可以使能相應的中斷標誌。函數定義如下:

/** @brief  Enable the specified USART interrupt.
  * @param  __HANDLE__: specifies the USART Handle.
  * @param  __INTERRUPT__: specifies the USART interrupt source to enable.
  *          This parameter can be one of the following values:
  *            @arg USART_IT_RXFF: RXFIFO Full interrupt
  *            @arg USART_IT_TXFE: TXFIFO Empty interrupt
  *            @arg USART_IT_RXFT: RXFIFO threshold interrupt
  *            @arg USART_IT_TXFT: TXFIFO threshold interrupt
  *            @arg USART_IT_TXE : Transmit Data Register empty interrupt
  *            @arg USART_IT_TC  : Transmission complete interrupt
  *            @arg USART_IT_RXNE: Receive Data register not empty interrupt
  *            @arg USART_IT_IDLE: Idle line detection interrupt
  *            @arg USART_IT_PE  : Parity Error interrupt
  *            @arg USART_IT_ERR : Error interrupt(Frame error, noise error, overrun error)
  * @retval None
  */
#define __HAL_USART_ENABLE_IT(__HANDLE__, __INTERRUPT__)   (((((uint8_t)(__INTERRUPT__)) >> 5U) == 1)? ((__HANDLE__)->Instance->CR1 |= (1U << ((__INTERRUPT__) & USART_IT_MASK))): \
                                                            ((((uint8_t)(__INTERRUPT__)) >> 5U) == 2)? ((__HANDLE__)->Instance->CR2 |= (1U << ((__INTERRUPT__) & USART_IT_MASK))): \
                          ((__HANDLE__)->Instance->CR3 |= (1U << ((__INTERRUPT__) & USART_IT_MASK))))

 

STM32一個串口的中斷服務程序入口地址只有一個,進入中斷服務程序後,我們需要判斷是什麼原因進入的中斷,因此需要調用一個函數來檢測中斷標誌。函數原型如下:

#define __HAL_USART_GET_IT(__HANDLE__, __IT__) ((__HANDLE__)->Instance->ISR & ((uint32_t)1 << ((__IT__)>> 0x08)))

 

中斷處理完畢後,必須軟件清除中斷標誌,否則中斷返回後,會重入中斷。清中斷標誌位的函數爲:

#define __HAL_USART_CLEAR_IT(__HANDLE__, __IT_CLEAR__) ((__HANDLE__)->Instance->ICR = (uint32_t)(__IT_CLEAR__)) 

 

正如前面介紹的,不是所有的標誌都需要用這個函數清零。

 

注意:操作串口的寄存器不限制必須要用HAL庫提供的API,比如要操作寄存器CR1,直接調用LPUART1->CR1操作即可。

65.3.5 低功耗串口初始化流程總結

使用方法由HAL庫提供:

  第1步:定義UART_HandleTypeDef類型串口結構體變量,比如UART_HandleTypeDef huart。

  第2步:使用函數HAL_UART_MspInit初始化串口底層,不限制一定要用此函數裏面初始化,用戶也可以自己實現。

  •  使能串口時鐘。
  •  引腳配置。

        a、使能串口所使用的GPIO時鐘。

        b、配置GPIO的複用模式。

  •  如果使用中斷方式函數HAL_UART_Transmit_IT和HAL_UART_Receive_IT需要做如下配置。

        a、配置串口中斷優先級。

        b、使能串口中斷。

  •  串口中斷的開關是通過函數__HAL_UART_ENABLE_IT() 和 __HAL_UART_DISABLE_IT()來實現,這兩個函數被嵌套到串口的發送和接收函數中調用。
  •  如果使用DMA方式函數HAL_UART_Transmit_DMA和HAL_UART_Receive_DMA需要做如下配置。

        a、聲明串口的發送和接收DMA結構體變量,注意發送和接收是獨立的,如果都使用,那就都需要配置。

        b、使能DMA接口時鐘。

        c、配置串口的發送和接收DMA結構體變量。

        d、配置DMA發送和接收通道。

        e、關聯DMA和串口的句柄。

        f、配置發送DMA和接收DMA的傳輸完成中斷和中斷優先級。

  第3步:配置串口的波特率,位長,停止位,奇偶校驗位,流控制和發送接收模式。

  第4步:如果需要,可以編程高級特性,比如TX/RX交換引腳,自動波特率檢測。通過第1步串口結構體變量huart的結構體成員AdvancedInit來設置。

  第5步:串口初始化調用的函數HAL_UART_Init初始化。

  第6步:根據需要可以做動態註冊回調。

首先使能宏定義USE_HAL_UART_REGISTER_CALLBACKS。

然後調用函數HAL_UART_RegisterCallback() 就可以註冊如下回調函數:

(+) TxHalfCpltCallback      

(+) TxCpltCallback         

(+) RxHalfCpltCallback      

(+) RxCpltCallback         

(+) ErrorCallback         

(+) AbortCpltCallback      

(+) AbortTransmitCpltCallback

(+) AbortReceiveCpltCallback

(+) WakeupCallback           

(+) RxFifoFullCallback     

(+) TxFifoEmptyCallback     

(+) MspInitCallback          

(+) MspDeInitCallback         

函數HAL_UART_UnRegisterCallback允許取消註冊的回調函數如下:

(+) TxHalfCpltCallback      

(+) TxCpltCallback         

(+) RxHalfCpltCallback      

(+) RxCpltCallback         

(+) ErrorCallback         

(+) AbortCpltCallback      

(+) AbortTransmitCpltCallback

(+) AbortReceiveCpltCallback

(+) WakeupCallback          

(+) RxFifoFullCallback     

(+) TxFifoEmptyCallback     

(+) MspInitCallback          

(+) MspDeInitCallback    

 

關於動態註冊回調函數注意以下幾點:

  •   默認情況下,HAL_UART_Init調用後將使用默認的弱定義回調,如果用戶註冊了回調,將使用用戶設置的。
  •   回調函數只能在HAL_UART_STATE_READY狀態下纔可以註冊/註銷。
    • 回調函數MspInit和MspDeInit除外,這兩個函數可以在HAL_HRTIM_STATE_READY 或 HAL_HRTIM_STATE_RESET狀態下注冊,這樣的話,用戶調用函數HAL_HRTIM_DeInit()或者HAL_HRTIM_Init()時,就可以在其函數內運行MspInit/DeInit。
    • 用戶可以在調用HAL_HRTIM_DeInit()或者HAL_HRTIM_Init()之前調用HAL_HRTIM_RegisterCallback()爲MspInit/MspDeInit註冊回調。

65.4 低功耗源文件stm32h7xx_hal_uart.c

此文件涉及到的函數較多,這裏把幾個常用的函數做個說明:

  •   HAL_UART_Init
  •   HAL_UART_Transmit
  •   HAL_UART_Receive
  •   HAL_UART_Transmit_IT
  •   HAL_UART_Receive_IT
  •   HAL_UART_Transmit_DMA
  •   HAL_UART_Receive_DMA

 

其實V7開發板設計的低功耗串口FIFO驅動文件bsp_lpuart_fifo.c僅用到了函數HAL_UART_Init,其它函數都沒有用到,不過這裏也爲大家做個說明。

65.4.1 函數HAL_UART_Init

函數原型:

HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{

   /* 省略 */

  if(huart->gState == HAL_UART_STATE_RESET)
  {
    huart->Lock = HAL_UNLOCKED;

    /* 初始化硬件: GPIO, CLOCK */
    HAL_UART_MspInit(huart);
  }

  huart->gState = HAL_UART_STATE_BUSY;

  /* 禁止串口 */
  __HAL_UART_DISABLE(huart);

  /* 配置串口參數 */
  if (UART_SetConfig(huart) == HAL_ERROR)
  {
    return HAL_ERROR;
  }

   /* 配置串口高級特性 */
  if (huart->AdvancedInit.AdvFeatureInit != UART_ADVFEATURE_NO_INIT)
  {
    UART_AdvFeatureConfig(huart);
  }

  /* 清寄存器的一些標誌位 */
  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);

  return (UART_CheckIdleState(huart));
}

 

函數描述:

此函數用於初始化串口的基礎特性和高級特性。

函數參數:

  •   第1個參數是UART_HandleTypeDef類型結構體指針變量,用於配置要初始化的參數。
  •   返回值,返回HAL_TIMEOUT表示超時,HAL_ERROR表示參數錯誤,HAL_OK表示發送成功,HAL_BUSY表示串口忙,正在使用中。

注意事項:

1、函數HAL_UART_MspInit用於初始化USART的底層時鐘、引腳等功能。需要用戶自己在此函數裏面實現具體的功能。由於這個函數是弱定義的,允許用戶在工程其它源文件裏面重新實現此函數。當然,不限制一定要在此函數裏面實現,也可以像早期的標準庫那樣,用戶自己初始化即可,更靈活些。

2、如果形參huart的結構體成員gState沒有做初始狀態,這個地方就是個坑。特別是用戶搞了一個局部變量UART_HandleTypeDef UartHandle。

對於局部變量來說,這個參數就是一個隨機值,如果是全局變量還好,一般MDK和IAR都會將全部變量初始化爲0,而恰好這個 HAL_UART_STATE_RESET  = 0x00U。

解決辦法有三

方法1:用戶自己初始串口和涉及到的GPIO等。

方法2:定義UART_HandleTypeDef UartHandle爲全局變量。

方法3:下面的方法

if(HAL_UART_DeInit(&UartHandle) != HAL_OK)
{
    Error_Handler();
}  
if(HAL_UART_Init(&UartHandle) != HAL_OK)
{
    Error_Handler();
}

 

3、注意串口的中斷狀態寄存器USART_ISR復位後,TC發送完成狀態和RXNE接收狀態都被置1,如果用戶使能這兩個中斷前,最好優先清除中斷標誌。

使用舉例:

UART_HandleTypeDef UartHandle;

/* USART3工作在UART模式 */
/* 配置如下:
  - 數據位 = 8 Bits
  - 停止位 = 1 bit
  - 奇偶校驗位 = 無
  - 波特率 = 115200bsp
  - 硬件流控制 (RTS 和 CTS 信號) */
UartHandle.Instance        = USART3;

UartHandle.Init.BaudRate     = 115200;
UartHandle.Init.WordLength   = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits     = UART_STOPBITS_1;
UartHandle.Init.Parity       = UART_PARITY_NONE;
UartHandle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
UartHandle.Init.Mode         = UART_MODE_TX_RX;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

if(HAL_UART_Init(&UartHandle) != HAL_OK)
{
    Error_Handler();
}

 

65.4.2 函數HAL_UART_Transmit

函數原型:

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
   /* 省略 */

  if(huart->gState == HAL_UART_STATE_READY)
  {
     /* 省略 */

    while(huart->TxXferCount > 0U)
    {
      huart->TxXferCount--;
      /* 等待發送空中斷標誌 */
      if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }
}
/* 等待發送完成中斷 */
    if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
    {
      return HAL_TIMEOUT;
    }

    /* 省略 */
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

 

函數描述:

此函數以查詢的方式發送指定字節。看源碼的話,程序裏面最重要的就是上面代碼中置紅的兩個標誌,發送空標誌和發送完成標誌。發送空標誌表示發送數據寄存器爲空,數據還在移位寄存器裏面,而發送完成標誌表示數據已經從移位寄存器發送出去。

函數參數:

  •   第1個參數是UART_HandleTypeDef類型結構體指針變量。
  •   第2個參數是要發送的數據地址。
  •   第3個參數是要發送的數據大小,單位字節。
  •   第4個參數是溢出時間,單位ms。
  •   返回值,返回HAL_TIMEOUT表示超時,HAL_ERROR表示參數錯誤,HAL_OK表示發送成功,HAL_BUSY表示串口忙,正在使用中。

使用舉例:

/*
*********************************************************************************************************
*    函 數 名: fputc
*    功能說明: 重定義putc函數,這樣可以使用printf函數從串口1打印輸出
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&UartHandle, (uint8_t *)&ch, 1, HAL_MAX_DELAY);

    return ch;
}

 

65.4.3 函數HAL_UART_Receive

函數原型:

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
 
/* 省略 */
  if(huart->RxState == HAL_UART_STATE_READY)
  {
   
    /* 省略 */
    while(huart->RxXferCount > 0U)
    {
      huart->RxXferCount--;
      if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }


    }
    /* 省略 */
    return HAL_OK;
  }
  else
  {
    /* 省略 */
    return HAL_BUSY;
  }
}

 

函數描述:

此函數以查詢的方式接收指定字節。這個函數相對比較好理解,就是等待上面程序中的RXNE標誌,置位了表示接收數據寄存器已經存入數據。

函數參數:

  第1個參數是UART_HandleTypeDef類型結構體指針變量。

  第2個參數是要接收的數據地址。

  第3個參數是要接收的數據大小,單位字節。

  第4個參數是溢出時間,單位ms。

  返回值,返回HAL_TIMEOUT表示超時,HAL_ERROR表示參數錯誤,HAL_OK表示發送成功,HAL_BUSY表示串口忙,正在使用中。

使用舉例:

/*
*********************************************************************************************************
*    函 數 名: fgetc
*    功能說明: 重定義getc函數,這樣可以使用scanff函數從串口1輸入數據
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
int fgetc(FILE *f)
{
    int ret;
        
    HAL_UART_Receive(&UartHandle, (uint8_t *)&ret, 1, HAL_MAX_DELAY);

    return ret;
}

 

65.4.4 函數HAL_UART_Transmit_IT

函數原型:

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
 
  if(huart->gState == HAL_UART_STATE_READY)
  {
    if((pData == NULL ) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    __HAL_LOCK(huart);

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

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

   
    __HAL_UNLOCK(huart);

    if (READ_BIT(huart->Instance->CR1, USART_CR1_FIFOEN) != RESET)
{
  /* 使能FIFO發送中斷 */
      SET_BIT(huart->Instance->CR3, USART_CR3_TXFTIE);
    }
    else
{
  /* 使能發空中斷 */
      SET_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
    }

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

 

函數描述:

此函數以中斷的方式發送指定字節,可以選擇使能FIFO中斷方式或者發送空中斷方式。具體數據的發送是在中斷處理函數HAL_UART_IRQHandler裏面實現。

函數參數:

  •   第1個參數是UART_HandleTypeDef類型結構體指針變量。
  •   第2個參數是要發送的數據地址。
  •   第3個參數是要發送的數據大小,單位字節。
  •   返回值,返回HAL_ERROR表示參數錯誤,HAL_OK表示發送成功,HAL_BUSY表示串口忙,正在使用中。

使用舉例:

使用中斷方式要使能串口中斷,此貼有完整例子:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=86245

UART_HandleTypeDef UartHandle;
uint8_t s_ucBuf[5];

/* 數據發送 */
HAL_UART_Transmit_IT(&UartHandle, s_ucBuf, 1);
HAL_UART_Transmit_IT(&UartHandle, (uint8_t*)"KEY_DOWN_K1\r\n", 13);

 

65.4.5 函數HAL_UART_Receive_IT

函數原型:

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  
  if(huart->RxState == HAL_UART_STATE_READY)
  {
    if((pData == NULL ) || (Size == 0U))
    {
      return HAL_ERROR;
    }
    
    __HAL_LOCK(huart);

    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    huart->RxXferCount = Size;
   
    UART_MASK_COMPUTATION(huart);

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

    __HAL_UNLOCK(huart);

    /* 使能錯誤中斷: (Frame error, noise error, overrun error) */
    SET_BIT(huart->Instance->CR3, USART_CR3_EIE);

    if (READ_BIT(huart->Instance->CR1, USART_CR1_FIFOEN) != RESET)
{
  /* 使能奇偶校驗失敗中斷 */
      SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);
      /* 使能FIFO接收中斷 */
      SET_BIT(huart->Instance->CR3, USART_CR3_RXFTIE);
    }
    else
{
  /* 使能奇偶校驗失敗中斷和接收中斷 */
      SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
    }

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

 

函數描述:

此函數以中斷的方式接收指定字節,可以選擇使能FIFO中斷方式或者普通中斷方式,兩種方式使能了奇偶校驗中斷失敗和錯誤中斷。具體數據的接收是在中斷處理函數HAL_UART_IRQHandler裏面實現。

函數參數:

  •   第1個參數是UART_HandleTypeDef類型結構體指針變量。
  •   第2個參數是要接收的數據地址。
  •   第3個參數是要接收的數據大小,單位字節。
  •   返回值,返回HAL_ERROR表示參數錯誤,HAL_OK表示發送成功,HAL_BUSY表示串口忙,正在使用中。

使用舉例:

使用中斷方式要使能串口中斷,此貼有完整例子:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=86245

UART_HandleTypeDef UartHandle;
uint8_t s_ucBuf[5];

/* 數據接收*/
HAL_UART_Receive_IT(&UartHandle, s_ucBuf, 1);

 

65.4.6 函數HAL_UART_Transmit_DMA

函數原型:

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  if(huart->gState == HAL_UART_STATE_READY)
  {
    if((pData == NULL ) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    __HAL_LOCK(huart);

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

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

    /* 註冊各種DMA回調函數 */
    huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
    huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;
    huart->hdmatx->XferErrorCallback = UART_DMAError;
    huart->hdmatx->XferAbortCallback = NULL;

    /* 使能串口發送DMA通道 */
    HAL_DMA_Start_IT(huart->hdmatx, (uint32_t)huart->pTxBuffPtr, (uint32_t)&huart->Instance->TDR, Size);

    /* 清除傳輸TC完成標誌 */
    __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_TCF);

    __HAL_UNLOCK(huart);

    /* 使能串口發送DMA傳輸 */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

 

函數描述:

此函數以DMA的方式發送指定字節。這裏是用的DMA中斷方式HAL_DMA_Start_IT進行的發送。所以使用此函數的話,不要忘了寫DMA中斷服務程序。而且DMA的配置也是需要用戶實現的,可以直接在函數HAL_UART_MspInit裏面實現,也可以放在其它位置。

函數參數:

  •   第1個參數是UART_HandleTypeDef類型結構體指針變量。
  •   第2個參數是要發送的數據地址。
  •   第3個參數是要發送的數據大小,單位字節。
  •   返回值,返回HAL_ERROR表示參數錯誤,HAL_OK表示發送成功,HAL_BUSY表示串口忙,正在使用中。

使用舉例:

使用DMA方式,此貼有完整例子:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=86271

65.4.7 函數HAL_UART_Receive_DMA

函數原型:

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  if(huart->RxState == HAL_UART_STATE_READY)
  {
    if((pData == NULL ) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    __HAL_LOCK(huart);

    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;

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

    /* 註冊各種DMA回調函數 */
    huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;

    huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;
    huart->hdmarx->XferErrorCallback = UART_DMAError;
huart->hdmarx->XferAbortCallback = NULL;

/* 使能串口接收DMA通道 */
    HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, (uint32_t)huart->pRxBuffPtr, Size);

    __HAL_UNLOCK(huart);

    /* 使能串口校驗錯誤中斷 */
    SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);

    /* 使能串口錯誤中斷:(Frame error, noise error, overrun error) */
    SET_BIT(huart->Instance->CR3, USART_CR3_EIE);

    /* 使能串口接收DMA傳輸 */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

 

函數描述:

此函數以DMA的方式接收指定字節。這裏是用的DMA中斷方式HAL_DMA_Start_IT進行的接收。所以使用此函數的話,不要忘了寫DMA中斷服務程序。而且DMA的配置也是需要用戶實現的,可以直接在函數HAL_UART_MspInit裏面實現,也可以放在其它位置。

函數參數:

  •   第1個參數是UART_HandleTypeDef類型結構體指針變量。
  •   第2個參數是要接收的數據地址。
  •   第3個參數是要接收的數據大小,單位字節。
  •   返回值,返回HAL_ERROR表示參數錯誤,HAL_OK表示發送成功,HAL_BUSY表示串口忙,正在使用中。

使用舉例:

使用DMA方式,此貼有完整例子:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=86271

65.5 總結

本章節就爲大家講解這麼多,涉及到的知識點和API函數比較多,需要花點時間消化,後面用到的多了,就可以熟練掌握了。

 

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