博客專欄

        EEPW首頁 > 博客 > hal庫操作架構

        hal庫操作架構

        發布人:chh650319 時間:2019-06-11 來源:工程師 發布文章
        • stm32f2xx.h主要包含STM32同系列芯片的不同具體型號的定義,是否使用HAL庫等的定義,接著,其會根據定義的芯片信號包含具體的芯片型號的頭文件:

        #if defined(STM32F205xx)

          #include "stm32f205xx.h"

        #elif defined(STM32F215xx)

          #include "stm32f215xx.h"

        #elif defined(STM32F207xx)

          #include "stm32f207xx.h"

        #elif defined(STM32F217xx)

          #include "stm32f217xx.h"

        #else

         #error "Please select first the target STM32F2xx device used in your application (in stm32f2xx.h file)"

        #endif

        緊接著,其會包含stm32f2xx_hal.h

        • stm32f2xx_hal.hstm32f2xx_hal.c/h 主要實現HAL庫的初始化、系統滴答相關函數、及CPU的調試模式配置

        • stm32f2xx_hal_conf.h :該文件是一個用戶級別的配置文件,用來實現對HAL庫的裁剪,其位于用戶文件目錄,不要放在庫目錄中。

        ??接下來對于HAL庫的源碼文件進行一下說明,HAL庫文件名均以stm32f2xx_hal開頭,后面加上_外設或者模塊名(如:stm32f2xx_hal_adc.c):

        庫文件:

            stm32f2xx_hal_ppp.c/.h          // 主要的外設或者模塊的驅動源文件,包含了該外設的通用API

            stm32f2xx_hal_ppp_ex.c/.h       // 外圍設備或模塊驅動程序的擴展文件。這組文件中包含特定型號或者系列的芯片的特殊API。以及如果該特定的芯片內部有不同的實現方式,則該文件中的特殊API將覆蓋_ppp中的通用API

            stm32f2xx_hal.c/.h              // 此文件用于HAL初始化,并且包含DBGMCU、重映射和基于systick的時間延遲等相關的API

            其他庫文件

        用戶級別文件:

            stm32f2xx_hal_msp_template.c    // 只有.c沒有.h。它包含用戶應用程序中使用的外設的MSP初始化和反初始化(主程序和回調函數)。使用者復制到自己目錄下使用模板。

            stm32f2xx_hal_conf_template.h   // 用戶級別的庫配置文件模板。使用者復制到自己目錄下使用

            system_stm32f2xx.c              // 此文件主要包含SystemInit()函數,該函數在剛復位及跳到main之前的啟動過程中被調用。 **它不在啟動時配置系統時鐘(與標準庫相反)** 時鐘的配置在用戶文件中使用HAL API來完成。

            startup_stm32f2xx.s             // 芯片啟動文件,主要包含堆棧定義,終端向量表等

            stm32f2xx_it.c/.h               // 中斷處理函數的相關實現

            main.c/.h                       //

         

        ??根據HAL庫的命名規則,其API可以分為以下三大類:

        • 初始化/反初始化函數: HAL_PPP_Init(), HAL_PPP_DeInit()

        • IO 操作函數: HAL_PPP_Read(),      HAL_PPP_Write(),HAL_PPP_Transmit(), HAL_PPP_Receive()

        • 控制函數: HAL_PPP_Set (),      HAL_PPP_Get ().

        • 狀態和錯誤HAL_PPP_GetState      (), HAL_PPP_GetError ().

        注意: 
        1. 目前LL庫是和HAL庫捆綁發布的,所以在HAL庫源碼中,還有一些名為 stm32f2xx_ll_ppp的源碼文件,這些文件就是新增的LL庫文件。 
        2. 使用CubeMX生產項目時,可以選擇LL

        ??HAL庫最大的特點就是對底層進行了抽象。在此結構下,用戶代碼的處理主要分為三部分:

        • 處理外設句柄(實現用戶功能)

        • 處理MSP

        • 處理各種回調函數

        外設句柄定義

        ??用戶代碼的第一大部分:對于外設句柄的處理。 HAL庫在結構上,對每個外設抽象成了一個稱為ppp_HandleTypeDef的結構體,其中ppp就是每個外設的名字。*所有的函數都是工作在ppp_HandleTypeDef指針之下。 
        ??1. 多實例支持:每個外設/模塊實例都有自己的句柄。 因此,實例資源是獨立的 
        ??2. 外圍進程相互通信:該句柄用于管理進程例程之間的共享數據資源。 
        下面,以ADC為例

        /**

         * @brief  ADC handle Structure definition

         */

        typedef struct

        {

            ADC_TypeDef                   *Instance;                   /*!< Register base address */

            ADC_InitTypeDef               Init;                        /*!< ADC required parameters */

          __IO uint32_t                 NbrOfCurrentConversionRank;  /*!< ADC number of current conversion rank */

            DMA_HandleTypeDef             *DMA_Handle;                 /*!< Pointer DMA Handler */

            HAL_LockTypeDef               Lock;                        /*!< ADC locking object */

            __IO uint32_t                 State;                       /*!< ADC communication state */

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

        }ADC_HandleTypeDef;

        ??從上面的定義可以看出,ADC_HandleTypeDef中包含了ADC可能出現的所有定義,對于用戶想要使用ADC只要定義一個ADC_HandleTypeDef的變量,給每個變量賦好值,對應的外設就抽象完了。接下來就是具體使用了。 
        ??當然,對于那些共享型外設或者說系統外設來說,他們不需要進行以上這樣的抽象,這些部分與原來的標準外設庫函數基本一樣。例如以下外設: 
        ??- GPIO 
        ??- SYSTICK 
        ??- NVIC 
        ??- RCC 
        ??- FLASH 
        GPIO為例,對于HAL_GPIO_Init() 函數,其只需要GPIO 地址以及其初始化參數即可。

        三種編程方式

        ??HAL庫對所有的函數模型也進行了統一。在HAL庫中,支持三種編程模式:輪詢模式、中斷模式、DMA模式(如果外設支持)。其分別對應如下三種類型的函數(以ADC為例):

        HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc);

        HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc);

         

        HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc);

        HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);

         

        HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);

        HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc);

        ??其中,帶_IT的表示工作在中斷模式下;帶_DMA的工作在DMA模式下(注意:DMA模式下也是開中斷的);什么都沒帶的就是輪詢模式(沒有開啟中斷的)。至于使用者使用何種方式,就看自己的選擇了。 
        ??此外,新的HAL庫架構下統一采用宏的形式對各種中斷等進行配置(原來標準外設庫一般都是各種函數)。針對每種外設主要由以下宏:

        • __HAL_PPP_ENABLE_IT(__HANDLE__,      __INTERRUPT__) 使能一個指定的外設中斷

        • __HAL_PPP_DISABLE_IT(__HANDLE__, __INTERRUPT__):失能一個指定的外設中斷

        • __HAL_PPP_GET_IT (__HANDLE__, __      INTERRUPT __):獲得一個指定的外設中斷狀態

        • __HAL_PPP_CLEAR_IT (__HANDLE__,      __ INTERRUPT __):清除一個指定的外設的中斷狀態

        • __HAL_PPP_GET_FLAG (__HANDLE__,      __FLAG__):獲取一個指定的外設的標志狀態

        • __HAL_PPP_CLEAR_FLAG (__HANDLE__,      __FLAG__):清除一個指定的外設的標志狀態

        • __HAL_PPP_ENABLE(__HANDLE__) :使能外設

        • __HAL_PPP_DISABLE(__HANDLE__) :失能外設

        • __HAL_PPP_XXXX (__HANDLE__,      __PARAM__) :指定外設的宏定義

        • __HAL_PPP_GET_ IT_SOURCE      (__HANDLE__, __ INTERRUPT __):檢查中斷源

        三大回調函數

        ??HAL庫的源碼中,到處可見一些以__weak開頭的函數,而且這些函數,有些已經被實現了,比如:

        __weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)

        {

            /*Configure the SysTick to have interrupt in 1ms time basis*/

            HAL_SYSTICK_Config(SystemCoreClock/1000U);

            /*Configure the SysTick IRQ priority */

            HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,0U);

            /* Return function status */

            return HAL_OK;

        }

        有些則沒有被實現,例如:

        __weak void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)

        {

          /* Prevent unused argument(s) compilation warning */

          UNUSED(hspi);

          /* NOTE : This function should not be modified, when the callback is needed,the HAL_SPI_TxCpltCallback should be implemented in the user file

          */

        }

        所有帶有__weak關鍵字的函數表示,就可以由用戶自己來實現。如果出現了同名函數,且不帶__weak關鍵字,那么連接器就會采用外部實現的同名函數。通常來說,HAL庫負責整個處理和MCU外設的處理邏輯,并將必要部分以回調函數的形式給出到用戶,用戶只需要在對應的回調函數中做修改即可。 HAL庫包含如下三種用戶級別回調函數(PPP為外設名): 
        ??1. 外設系統級初始化/解除初始化回調函數(用戶代碼的第二大部分:對于MSP的處理):HAL_PPP_MspInit() HAL_PPP_MspDeInit**。例如:__weak void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)。在HAL_PPP_Init() 函數中被調用,用來初始化底層相關的設備(GPIOs, clock, DMA, interrupt

        ??2. 處理完成回調函數:HAL_PPP_ProcessCpltCallback*Process指具體某種處理,如UARTTx),例如:__weak void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)。當外設或者DMA工作完成后時,觸發中斷,該回調函數會在外設中斷處理函數或者DMA的中斷處理函數中被調用

        ??3. 錯誤處理回調函數:HAL_PPP_ErrorCallback例如:__weak void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)**。當外設或者DMA出現錯誤時,觸發終端,該回調函數會在外設中斷處理函數或者DMA的中斷處理函數中被調用

        1. 絕大多數用戶代碼均在以上三大回調函數中實現。

        2. HAL庫結構中,在每次初始化前(尤其是在多次調用初始化前),先調用對應的反初始化(DeInit)函數是非常有必要的。某些外設多次初始化時不調用返回會導致初始化失敗。

        3. 完成回調函數有多中,例如串口的完成回調函數有HAL_UART_TxCpltCallback HAL_UART_TxHalfCpltCallback

        4. (用戶代碼的第三大部分:對于上面第二點和第三點的各種回調函數的處理)

        5. 在實際使用中,發現HAL仍有不少問題,例如在使用USB時,其庫配置存在問題

        HAL庫移植使用

        基本步驟

        1. 復制stm32f2xx_hal_msp_template.c,參照該模板,依次實現用到的外設的HAL_PPP_MspInit() HAL_PPP_MspDeInit

        2. 復制stm32f2xx_hal_conf_template.h,用戶可以在此文件中自由裁剪,配置HAL庫。

        3. 在使用HAL庫時,必須先調用函數:HAL_StatusTypeDef      HAL_Init(void)(該函數在stm32f2xx_hal.c中定義,也就意味著第一點中,必須首先實現HAL_MspInit(void)HAL_MspDeInit(void)

        4. HAL庫與STD庫不同,HAL庫使用RCC中的函數來配置系統時鐘,用戶需要單獨寫時鐘配置函數(STD庫默認在system_stm32f2xx.c中)

        5. 關于中斷,HAL提供了中斷處理函數,只需要調用HAL提供的中斷處理函數。用戶自己的代碼,不建議先寫到中斷中,而應該寫到HAL提供的回調函數中。

        6. 對于每一個外設,HAL都提供了回調函數,回調函數用來實現用戶自己的代碼。整個調用結構由HAL庫自己完成。例如:Uart中,HAL提供了void      HAL_UART_IRQHandler(UART_HandleTypeDef *huart);函數,用戶只需要觸發中斷后,用戶只需要調用該函數即可,同時,自己的代碼寫在對應的回調函數中即可!如下:

        void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);

        void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);

        void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);

        void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);

        void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);

        使用了哪種就用哪個回調函數即可!

        基本結構

        ??綜上所述,使用HAL庫編寫程序(針對某個外設)的基本結構(以串口為例)如下: 
        1. 配置外設句柄。例如,建立UartConfig.c,在其中定義串口句柄 UART_HandleTypeDef huart;,接著使用初始化句柄(HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)) 
        2. 編寫Msp 例如,建立UartMsp.c,在其中實現void HAL_UART_MspInit(UART_HandleTypeDef* huart) void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) 
        3. 實現對應的回調函數。例如,建立UartCallBack.c,在其中實現上文所說明的三大回調函數中的完成回調函數錯誤回調函數


        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



        關鍵詞:

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 敦煌市| 三明市| 江西省| 凌海市| 楚雄市| 朝阳市| 泰安市| 江永县| 娱乐| 浦江县| 江门市| 达孜县| 班玛县| 青河县| 东乌珠穆沁旗| 佛教| 塔城市| 盐池县| 碌曲县| 开阳县| 肇庆市| 金山区| 屏南县| 阿拉尔市| 山东| 利川市| 衡山县| 南澳县| 沙河市| 东兰县| 新乐市| 鄂州市| 喀什市| 阿城市| 扶风县| 塔城市| 庆安县| 界首市| 涪陵区| 社会| 朔州市|