STM32 HAL UART 框架初體驗

背景

STM32開發平臺,時至今日發展的已經相當成熟了,尤其對於外圍硬件接口的抽象封裝庫,即HAL。好多基於STM32開發的工程師,習慣於直接操作外圍接口相關的寄存器來完成所謂的驅動開發,其實,ST公司早就爲大家準備好了對於這些外圍接口的驅動框架,我們只需要直接拿來就可以使用。

可是以前,基於STM32平臺開發時,存在一個問題就是,變換MCU型號時,需要在新老MCU之間移植驅動程序,移植過程中可能出現很多莫名其妙的問題,導致浪費了很多寶貴的開發時間,如何避免這種問題呢?其實,ST早就爲大家考慮到了這一點,其開發了STM32CubeMX工具,基於該工具,我們可以輕鬆的完成各種外圍接口的配置工作,而且最爲神奇的就是,配置完成之後,該工具會自動生成工程代碼,我們基於此,就可以直接進行開發了,免去了很多不必要的硬件寄存器配置工作。當然,對於特殊需求,我們還是需要去手動配置一些硬件寄存器,但是,這項工作大部分時間是不需要的。

既然,ST公司爲我們提供了這麼好用的工具,我們爲什麼不用起來呢?下面就基於UART的配置過程,來逐步的講解一下,如何基於STM32CubeMX、Kiel和STM32 HAL來配置生成一個可用的開發環境。

開發步驟

配置環境

工欲善其事,必先利其器。首先第一步就是安裝STM32CubeMX環境,關於STM32CubeMX環境的安裝,網上有好多寫的特別棒的文中,這裏引用一篇
ybhuangfugui的博客,在此感謝ybhuangfugui的無私貢獻。大家可以閱讀該文章完成STM32CubeMX環境的安裝。

在這裏說一句,STM32CubeMX提供所有STM32家族的MCU芯片的初始配置抽象,並提供了HAL,封裝、抽象了關於底層硬件的配置、使用過程,這是一把雙刃劍,有利有弊:利是它增強了STM32不同MCU之間的兼容性,大大加快了初始開發進度,其提供的HAL爲開發者提供了統一的開發接口,這樣節省了寶貴開發時間。同時,基於其提供的配套的中間件(RTOS、TCP/IP、FS等),開發者可以快速的完成更高級需求的環境定製,這對於開發者來說是不小的福音;弊是,STM32 MCU畢竟是比較低級的硬件開發平臺,其開發過程中涉及到大量的底層硬件操作,如果我們想徹底理解這些基礎的硬件操作原理的話,可能還是需要從最爲原始的硬件寄存器配置開始。

不過,個人感覺STM32CubeMX利大於弊,就像通用操作系統,其屏蔽了所有的硬件相關的操作,爲開發者抽象出了進程、內存管理、文件系統、網絡等等,易於開發、理解的開發接口,也是正是操作系統的逐步成熟,才最終促使了後來的計算機一次又一次的革命。我想,對於MCU來說,其過程是類似的。如今,已經進入了物聯網時代,各種各樣的的硬件開發平臺層出不窮,各種層次的開發者都涌入到了這一開發領域。試想對於一個原來從事於Web開發的人員來說,其不可能從頭去理解底層的硬件知識,其需要的就是一個快速、高效的配置工具,完成原始開發環境的搭建。這時,STM32CubeMX就可以提供很大的幫助。

相信,STM32CubeMX未來肯定會發展的更爲智能,任何一個有志於基於該平臺開發的開發者,都會被其強度的功能所折服的,零基礎的開發人員也能夠快速上手該平臺。我想,這可能也是STM32CubeMX未來的目標吧。

最後說明一下,本文所使用的STM32CubeMX的版本是:5.5.0。溫馨提示,不同版本的操作步驟也能不太一樣,所以建議使用相同的版本進行配置。

開始配置

首先,我們需要確定我們所使用的STM32的MCU具體型號,然後,打開STM32CubeMX,創建一個新的工程。

我們選擇第一個“ACCESSTO MCU SELECTOR”,開始創建一個工程。我們選擇的MCU是STM32L010K8,安裝如下圖的步驟創建工程。

  1. 選擇MCU型號
  2. 查看MCU型號信息
  3. 創建項目

然後,選擇Project Manager項目,配置本項目的一些信息。

接下來,我們進行Pinout & Configuration配置,這裏面會涉及到MCU提供的所有外圍硬件的相關配置。本文主要關注的是UART的配置過程,STM32L010K8提供一個UART2和LPUART,我們選擇的配置項爲UART2。

UART2的基本配置步驟如下,

  1. 選擇UART2配置項。

  2. 選擇UART2的工作模式,這裏選擇的是Asynchronous。

  3. 配置UART2的參數,參數分爲Basic Parameters、Advanced Paramters、Advanced Features幾類。

    • 基本參數配置就是波特率、字長、校驗方式、停止位;
    • 高級參數配置就是數據傳輸方向、採集相關的配置;
    • 高級特性配置:就是UART2提供的一些比較高級的功能,比如,自適應波特率、Overrun等。

我們選擇UART2的中斷方式處理數據的傳輸模式,所以,需要進一步配置NVIC。配置步驟如下:

  1. 點擊System Core中的NVIC配置。
  2. 使能USART2中斷,並配置中斷搶佔優先級爲0。

還有就是需要確定UART2使用GPIO引腳,配置方式如下:

這裏使用的是PA2和PA3。

最後,配置SysClock,我們最終選擇的系統主時鐘頻率爲16MHz。

完成上述配置之後,點擊GENERATE CODE完成項目代碼的生成。

HAL

項目代碼生成之後,我們使用Kiel打開,如下圖:

下面是main中的芯片初始化代碼:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */
 
 

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

我們看到,STM32CubeMX自動生成了關於HAL、系統時鐘、UART2的初始化代碼。下面看一下UART2的初始化代碼:

static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */
}

stm32l0xx_it.c中定義了UART2的中斷處理函數,代碼如下:

void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

該中斷處理函數用來處理所有與UART2相關的中斷事件。那如何才能開啓UART2的數據發送和接收呢?這就需要HAL中關於UART2數據發送接收的接口函數:

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

當我們需要已中斷的方式接收數據時,就調用HAL_UART_Receive_IT函數,其中第一個參數是UART的描述符,pData保存數據的緩存區,Size是緩存區的大小。注意,調用完該接口之後,UART2開始已中斷的方式接收數據,數據的大小爲Size,當接收了Size個字節的數據之後,UART2就不會再接收數據。若想再次接收數據,需要再一次調用HAL_UART_Receive_IT函數。一個比較好的實現就是,在重新覆蓋實現下面的函數,

`__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)`

該函數會在數據接收完之後被調用,然後我們在函數中,可以將數據拷貝走,然後再次調用HAL_UART_Receive_IT。

對於數據的發送,處理過程與接收類似,所不同的就是發送的接口函數爲:HAL_UART_Transmit_IT,該發送完成之後的回調函數是:

__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)

好了,至此我們基本完成了基於STM32CubeMX的UART的配置過程,可以看到基於此種方式,我們基本上不會觸碰到硬件寄存器的配置過程,所要做的就是基於HAL框架提供的接口完成APP的開發。這也許就是STM32CubeMX的魅力所在吧,簡單,高效,可移植性強。
UART_TxCpltCallback(UART_HandleTypeDef *huart)

好了,至此我們基本完成了基於STM32CubeMX的UART的配置過程,可以看到基於此種方式,我們基本上不會觸碰到硬件寄存器的配置過程,所要做的就是基於HAL框架提供的接口完成APP的開發。這也許就是STM32CubeMX的魅力所在吧,簡單,高效,可移植性強。

發佈了122 篇原創文章 · 獲贊 132 · 訪問量 46萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章