目的
使用HAL庫開發STM32是目前ST官方主要推薦的方式,本篇文章對HAL做個基礎說明。下面文章中以STM32F4爲基礎進行介紹,其它系列的HAL庫在設計思路上也是差不多的。
HAL庫概述
STM32F4的HAL庫綜述在文檔《UM1725 - User Manual: Description of STM32F4 HAL and LL drivers》的第二篇章《Overview of HAL drivers》(文檔版本DocID025834 Rev 5 ),官方文檔本身寫得非常詳細,這裏做下簡單梳理。
下文中出現的。
文件說明
庫文件
上圖是HAL庫文件與引用包含關係,其中 ppp
用來指代外設,例如 gpio
uart
adc
等,箭頭起始文件引用包含了箭頭指向的文件,如user file引用了stm32f4xx_hal.h文件。主要文件描述如下:
文件 | 描述 |
---|---|
stm32f4xx_hal_ppp.c stm32f4xx_hal_ppp.h |
外設基本驅動文件 |
stm32f4xx_hal_ppp_ex.c stm32f4xx_hal_ppp_ex.h |
外設擴展驅動文件 |
stm32f4xx_hal.c stm32f4xx_hal.h |
包含HAL初始化、DBGMCU、系統時間相關內容 |
stm32f4xx_hal_def.h | 公共枚舉與宏定義等資源 |
用戶文件
這裏的用戶文件指的是使用stm32cube生成的項目所需的文件:
文件 | 描述 |
---|---|
system_stm32f4xx.c | 主要包含SystemInit(),用來初始化系統時鐘等 |
startup_stm32f4xx.s | 目標芯片啓動文件 |
stm32f4xx_hal_msp.c | 外設系統級初始化與反初始化 |
stm32f4xx_hal_conf.h | HAL庫配置,用以適配項目 |
stm32f4xx_it.c stm32f4xx_it.h |
包含項目涉及的中斷服務程序 |
main.c main.h |
包含各類初始化以及用戶程序主入口 |
API
分類與命名
HAL庫大多數功能的外設API可以分爲兩類,Generic和Extension,這點從文檔目錄和庫文件命名上就可以看出。
Generic APIs就是指普通的、通用的API,一般來說這部分API是兼容所有STM32系列芯片的,如果你的項目中只用到這部分API的話那就可以非常方便的更換MCU型號。很多時候我們也只用到這些API就可以完成項目開發了。
Extension APIs指擴展的API,這部分API涉及不同STM32系列MCU差異部分功能的操作,所以並不兼容所有STM32芯片。這部分API細分的話也可以分成兩類Family specific APIs(不同系列芯片差異,比如F0、F1、F4等)和Device part number specific APIs(具體不同型號芯片差異,比如F401、F405、F429等)
命名規則見下表:
HAL庫中命名還是挺統一與簡單易懂的,比如使用某個GPIO口輸出使用,一般就是設置輸出電平,就算沒有實際用過也能知道相關函數是 HAL_GPIO_xxxxx
,使用UART發送相關函數是 HAL_UART_xxxxx
,配合IDE的代碼補全功能開發起來就得心應手:
基本API說明
功能分類
單個外設的API大體上可以分爲四類:
類別 | 說明 | 舉例 |
---|---|---|
Initialization | 初始化與反初始化 | HAL_ADC_Init() |
IO operation | 啓動、停止、讀寫、回調函數等 | HAL_ADC_Start () HAL_ADC_ConvCpltCallback() |
Control | 相關參數設置 | HAL_ADC_ConfigChannel() |
State and Errors | 獲取狀態與錯誤信息 | HAL_ADC_GetState() HAL_ADC_GetError() |
操作模型
對於外設IO中很多耗時操作HAL庫提供了三種模型:輪詢、中斷、DMA。比如串口讀寫數據就有三類方式:
- 輪詢:HAL_UART_Transmit() & HAL_UART_Receive()
- 中斷:HAL_UART_Transmit_IT() & HAL_UART_Receive_IT()
- DMA:HAL_UART_Transmit_DMA() & HAL_UART_Receive_DMA()
輪詢是一種阻塞的方式、中斷和DMA是非阻塞方式(一般結合回調函數一起使用)。對於同一個外設使用時最好不要混用,不然可能會發生不可預知的問題。
回調函數
HAL庫對很對操作編寫了用 __weak
符號修飾的回調函數,用戶可以在自己的代碼中重新定義該回調函數實現具體功能,比如下面就是串口收發完成的回調函數:
HAL_UART_TxCpltCallback() & HAL_UART_RxCpltCallback()
公共資源
公共資源指全局的宏定義、枚舉、結構體等,主要定義在stm32fxxx_hal_def.h文件中。
這裏主要提一個HAL Status:
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
這個枚舉類型經常出現在操作設置等的返回值中,比如HAL_StatusTypeDef HAL_UART_Transmit(),寫代碼時可以通過該狀態知道操作是否成功等。
常用系統函數
STM32F4的HAL庫系統函數介紹在文檔《UM1725 - User Manual: Description of STM32F4 HAL and LL drivers》的第五篇章《HAL System Driver》(文檔版本DocID025834 Rev 5 )。這裏列出在STM32CubeMX生成代碼時不會用到的部分常用的函數:
__weak uint32_t HAL_GetTick(void)
返回從系統運行開始經過的時間,默認情況下單位爲ms;__weak void HAL_Delay(uint32_t Delay)
延時,該延時是阻塞的,默認情況下延時單位爲ms,該函數不能在等於或高於系統時鐘源優先級(默認情況下爲0)的中斷程序中使用,不然程序就阻塞在這裏不動了;__weak void HAL_SuspendTick(void)
暫停系統時間運行,記得與HAL_ResumeTick()成對使用;__weak void HAL_ResumeTick(void)
繼續系統時間運行;uint32_t HAL_GetUIDw0(void)
uint32_t HAL_GetUIDw1(void)
uint32_t HAL_GetUIDw2(void)
STM32芯片 96位全球唯一ID。
特殊函數
特殊操作一般用的不多,這裏列舉部分常用的:
全局中斷
使用下面函數關閉/開啓全局中斷:
__disable_irq(); //關閉全局中斷,等同於__set_PRIMASK(1);
__enable_irq(); //開啓全局中斷,等同於__set_PRIMASK(0);
__disable_irq()操作相當於把當前運行的代碼優先級調整至0,所有其它用戶中斷程序將不會運行,直至重新開啓全局中斷。
使用下面函數也可以關閉/開啓全局中斷(有些系列的芯片沒有該組函數):
__disable_fault_irq(); //關閉全局中斷,等同於__set_FAULTMASK(1);
__enable_fault_irq(); //開啓全局中斷,等同於__set_FAULTMASK(0);
__disable_fault_irq()操作相當於把當前運行的代碼優先級調整至-1,硬件錯誤也將被屏蔽;
軟復位系統
使用 NVIC_SystemReset()
函數可以軟復位系統,最好配合關閉全局中斷使用,以免出現意外操作。
總結
HAL整體功能組織、命名還是比較不錯的。剛從標準外設庫(STD)轉過來的開發者可能會不太習慣,主要是兩者的設計思路上有區別。瞭解HAL庫的功能組織和命名習慣對於理解HAL庫設計思路、使用HAL庫進行開發還是有促進作用的。