深入淺出理解STM32 HAL庫的底層邏輯
共 18214字,需瀏覽 37分鐘
·
2024-07-13 12:15
前言
STM32三種開發(fā)方式
1、直接配置寄存器
2、標準庫
3、HAL庫
HAL庫固件庫安裝與用戶手冊
1、首先設置讓Cube可以自動聯(lián)網下載相關固件庫選擇updater Settings
2、根據芯片選擇所需固件
3、尋找用戶幫助手冊
STM32 HAL庫與標準庫的區(qū)別
1、句柄
-
第一種解釋:句柄是一種特殊的智能指針 。當一個應用程序要引用其他系統(tǒng)(如數(shù)據庫、操作系統(tǒng))所管理的內存塊或對象時,就要使用句柄。
-
第二種解釋:整個Windows編程的基礎。一個句柄是指使用的一個唯一的整數(shù)值,即一個4字節(jié)(64位程序中為8字節(jié))長的數(shù)值,來標識應用程序中的不同對象和同類中的不同的實例,諸如,一個窗口,按鈕,圖標,滾動條,輸出設備,控件或者文件等。應用程序能夠通過句柄訪問相應的對象的信息,但是句柄不是指針,程序不能利用句柄來直接閱讀文件中的信息。如果句柄不在I/O文件中,它是毫無用處的。句柄是Windows用來標志應用程序中建立的或是使用的唯一整數(shù),Windows大量使用了句柄來標識對象。
USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = bound;//串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數(shù)據格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數(shù)據流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式USART_Init(USART3, &USART_InitStructure); //初始化串口1
-
1、對六個位置進行賦值 -
2、然后引用Init函數(shù)
UART_HandleTypeDef UART1_Handler;
typedef struct{USART_TypeDef *Instance; /*!< UART registers base address */UART_InitTypeDef Init; /*!< UART communication parameters */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_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */HAL_LockTypeDef Lock; /*!< Locking object */__IO HAL_UART_StateTypeDef State; /*!< UART communication state */__IO uint32_t ErrorCode; /*!< UART Error code */}UART_HandleTypeDef;
-
1、包含了之前標準庫就有的六個成員(波特率,數(shù)據格式等),
-
2、還包含過采樣、(發(fā)送或接收的)數(shù)據緩存、數(shù)據指針、串口 DMA 相關的變量、各種標志位等等要在整個項目流程中都要設置的各個成員。
該 UART1_Handler就被稱為串口的句柄,它被貫穿整個USART收發(fā)的流程,比如開啟中斷:
HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);
比如后面要講到的MSP與Callback回調函數(shù):
void HAL_UART_MspInit(UART_HandleTypeDef *huart);void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
在這些函數(shù)中,只需要調用初始化時定義的句柄UART1_Handler就好。
2、MSP函數(shù)
-
HAL_USART_Init()—>HAL_USART_MspInit() ,先初始化與 MCU無關的串口協(xié)議,再初始化與 MCU 相關的串口引腳。
-
在 STM32 的 HAL 驅動中HAL_PPP_MspInit()作為回調,被 HAL_PPP_Init()函數(shù)所調用。當我們需要移植程序到 STM32F1平臺的時候,我們只需要修改 HAL_PPP_MspInit 函數(shù)內容而不需要修改 HAL_PPP_Init 入口參數(shù)內容。
void HAL_UART_MspInit(UART_HandleTypeDef *huart);
void USART3_IRQHandler(void) //串口1中斷服務程序{u8 Res;if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收中斷(接收到的數(shù)據必須是0x0d 0x0a結尾){Res =USART_ReceiveData(USART3); //讀取接收到的數(shù)據/*數(shù)據處理區(qū)*/}}}
void USART1_IRQHandler(void){HAL_UART_IRQHandler(&UART1_Handler); //調用HAL庫中斷處理公用函數(shù)/***************省略無關代碼****************/}
/*HAL庫使用的串口接收緩沖,處理邏輯由HAL庫控制,接收完這個數(shù)組就會調用HAL_UART_RxCpltCallback進行處理這個數(shù)組*//*RXBUFFERSIZE=5*/u8 aRxBuffer[RXBUFFERSIZE];
/*該代碼在HAL_UART_Receive_IT函數(shù)中,初始化時會引用*/huart->pRxBuffPtr = pData;//aRxBufferhuart->RxXferSize = Size;//RXBUFFERSIZEhuart->RxXferCount = Size;//RXBUFFERSIZE
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
STM32 HAL庫結構
-
1、stm32f4xx.h主要包含STM32同系列芯片的不同具體型號的定義,是否使用HAL庫等的定義,接著,其會根據定義的芯片信號包含具體的芯片型號的頭文件:
-
2、stm32f4xx_hal.h:stm32f4xx_hal.c/h 主要實現(xiàn)HAL庫的初始化、系統(tǒng)滴答相關函數(shù)、及CPU的調試模式配置
-
3、stm32f4xx_hal_conf.h :該文件是一個用戶級別的配置文件,用來實現(xiàn)對HAL庫的裁剪,其位于用戶文件目錄,不要放在庫目錄中。
-
4、庫文件:stm32f4xx_hal_ppp.c/.h // 主要的外設或者模塊的驅動源文件,包含了該外設的通用API
stm32f4xx_hal_ppp_ex.c/.h // 外圍設備或模塊驅動程序的擴展文件。這組文件中包含特定型號或者系列的芯片的特殊API。以及如果該特定的芯片內部有不同的實現(xiàn)方式,則該文件中的特殊API將覆蓋_ppp中的通用API。
stm32f4xx_hal.c/.h // 此文件用于HAL初始化,并且包含DBGMCU、重映射和基于systick的時間延遲等相關的API
-
5、其他庫文件
用戶級別文件:
stm32f4xx_hal_msp_template.c // 只有.c沒有.h。它包含用戶應用程序中使用的外設的MSP初始化和反初始化(主程序和回調函數(shù))。使用者復制到自己目錄下使用模板。
stm32f4xx_hal_conf_template.h // 用戶級別的庫配置文件模板。使用者復制到自己目錄下使用
system_stm32f4xx.c // 此文件主要包含SystemInit()函數(shù),該函數(shù)在剛復位及跳到main之前的啟動過程中被調用。它不在啟動時配置系統(tǒng)時鐘(與標準庫相反)。時鐘的配置在用戶文件中使用HAL API來完成。startup_stm32f4xx.s // 芯片啟動文件,主要包含堆棧定義,終端向量表等 stm32f4xx_it.c/.h // 中斷處理函數(shù)的相關實現(xiàn)
-
6 main.c/.h //
-
初始化/反初始化函數(shù):
HAL_PPP_Init(), HAL_PPP_DeInit()
-
IO 操作函數(shù):
HAL_PPP_Read(),HAL_PPP_Write(),HAL_PPP_Transmit(),HAL_PPP_Receive()
-
控制函數(shù):
HAL_PPP_Set (),HAL_PPP_Get ().
-
狀態(tài)和錯誤:
** HAL_PPP_GetState (),HAL_PPP_GetError ().
-
注意:
-
處理外設句柄(實現(xiàn)用戶功能) -
處理MSP -
處理各種回調函數(shù)
1、外設句柄定義
-
多實例支持:每個外設/模塊實例都有自己的句柄。因此,實例資源是獨立的下面,以ADC為例,外圍進程相互通信:該句柄用于管理進程例程之間的共享數(shù)據資源。
/*** @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;
-
GPIO
-
SYSTICK
-
NVIC
-
RCC
-
FLASH
2、 三種編程方式
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);
__HAL_PPP_ENABLE_IT(HANDLE, INTERRUPT):使能一個指定的外設中斷__HAL_PPP_DISABLE_IT(HANDLE, INTERRUPT):失能一個指定的外設中斷__HAL_PPP_GET_IT (HANDLE, __ INTERRUPT __):獲得一個指定的外設中斷狀態(tài)__HAL_PPP_CLEAR_IT (HANDLE, __ INTERRUPT __):清除一個指定的外設的中斷狀態(tài)__HAL_PPP_GET_FLAG (HANDLE, FLAG):獲取一個指定的外設的標志狀態(tài)__HAL_PPP_CLEAR_FLAG (HANDLE, FLAG):清除一個指定的外設的標志狀態(tài)__HAL_PPP_ENABLE(HANDLE) :使能外設__HAL_PPP_DISABLE(HANDLE) :失能外設__HAL_PPP_XXXX (HANDLE, PARAM) :指定外設的宏定義_HAL_PPP_GET IT_SOURCE (HANDLE, __ INTERRUPT __):檢查中斷源
3、 三大回調函數(shù)
__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*/}
-
1、外設系統(tǒng)級初始化/解除初始化回調函數(shù)(用戶代碼的第二大部分:對于MSP的處理):
-
2、處理完成回調函數(shù):HAL_PPP_ProcessCpltCallback*(Process指具體某種處理,如UART的Tx),
__weak void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
HAL_PPP_ErrorCallback
__weak void HAL_SPI_ErrorCallback(SPI_HandleTypeDef hspi)*
-
3、當外設或者DMA出現(xiàn)錯誤時,觸發(fā)終端,該回調函數(shù)會在外設中斷處理函數(shù)或者DMA的中斷處理函數(shù)中被調用
HAL_PPP_ErrorCallback
__weak void HAL_SPI_ErrorCallback(SPI_HandleTypeDef hspi)*
HAL_UART_TxCpltCallbackHAL_UART_TxHalfCpltCallback
HAL庫移植使用
-
1、復制stm32f2xx_hal_msp_template.c,參照該模板,依次實現(xiàn)用到的外設的HAL_PPP_MspInit()和 HAL_PPP_MspDeInit。
-
2、復制stm32f2xx_hal_conf_template.h,用戶可以在此文件中自由裁剪,配置HAL庫。
-
3、在使用HAL庫時,必須先調用函數(shù):HAL_StatusTypeDef HAL_Init(void)(該函數(shù)在stm32f2xx_hal.c中定義,也就意味著第一點中,必須首先實現(xiàn)HAL_MspInit(void)和HAL_MspDeInit(void))
-
4、HAL庫與STD庫不同,HAL庫使用RCC中的函數(shù)來配置系統(tǒng)時鐘,用戶需要單獨寫時鐘配置函數(shù)(STD庫默認在system_stm32f2xx.c中)
-
5、關于中斷,HAL提供了中斷處理函數(shù),只需要調用HAL提供的中斷處理函數(shù)。用戶自己的代碼,不建議先寫到中斷中,而應該寫到HAL提供的回調函數(shù)中。
-
6、對于每一個外設,HAL都提供了回調函數(shù),回調函數(shù)用來實現(xiàn)用戶自己的代碼。整個調用結構由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);
-
1、 配置外設句柄 例如,建立UartConfig.c,在其中定義串口句柄 UART_HandleTypeDef huart;接著使用初始化句柄(HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef huart))
-
2、編寫Msp 例如,建立UartMsp.c,在其中實現(xiàn)void HAL_UART_MspInit(UART_HandleTypeDef huart) 和 void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
-
3、實現(xiàn)對應的回調函數(shù) 例如,建立UartCallBack.c,在其中實現(xiàn)上文所說明的三大回調函數(shù)中的完成回調函數(shù)和錯誤回調函數(shù)
參考文檔及網文鏈接
深度長文:STM32是如何軟硬件結合,編譯后怎么樣一步步運行起來的
一份很棒的外設驅動庫!基于STM32F4
STM32奪命100問,收藏夾吃灰走起~
干貨 | 一文講透STM32串口DMA收發(fā)機制
