stm32-hal庫開發(fā)入門

很久之前就聽說st出了一個(gè)新版本的庫韵吨,用于代替原來的標(biāo)準(zhǔn)庫迹冤,非常好奇玖绿,但是一直沒有機(jī)會去體驗(yàn)。這次借著做畢設(shè)的機(jī)會叁巨,嘗試著切換到新庫斑匪。

官網(wǎng)介紹說,hal(hardware abstract layer)是一層硬件的抽象锋勺,看到這里蚀瘸,我非常激動(dòng),看來st終于意識到原來標(biāo)準(zhǔn)庫的問題了庶橱,原來的標(biāo)準(zhǔn)庫非常依賴于具體硬件細(xì)節(jié)贮勃,很難體現(xiàn)出使用庫的優(yōu)勢,而且很難移植苏章。同時(shí)我也非常好奇寂嘉,st到底是如何把不同系列mcu的操作給封裝起來的奏瞬,是不是足夠抽象,方便移植泉孩。

話不多說硼端,直接上官網(wǎng)下下來再說。

Paste_Image.png

上圖就是hal庫的全部內(nèi)容寓搬,其中STM32F1xx_HAL_Driver中屬于hal庫的內(nèi)容珍昨。

拿到庫第一步需要做的就是配置一個(gè)簡單的hello world,我在配置的時(shí)候句喷,出現(xiàn)了非常多的問題镣典。最開始非常自信,只從文件夾里挑選自認(rèn)為有用的文件加入到工程中唾琼,結(jié)果出現(xiàn)了各種問題兄春,里面各種庫的依賴關(guān)系比較復(fù)雜,如果不是很熟悉整個(gè)架構(gòu)的話锡溯,還是老老實(shí)實(shí)拷貝整個(gè)文件夾吧赶舆。

配置之前,首先要了解一下整個(gè)庫的框架趾唱,官方給的框架圖如下:

捕獲.PNG

個(gè)人認(rèn)為這幅圖和我理解的有些許出入,故重新畫了一張:

Paste_Image.png

有幾點(diǎn)區(qū)別:

  • cmsis我放在了驅(qū)動(dòng)層的最底層蜻懦,因?yàn)閏msis庫中包含的內(nèi)容都是和具體cpu內(nèi)核相關(guān)的東西甜癞,還有一些地址定義,這些都是非常底層的東西了宛乃,而且hal層確實(shí)是依賴于cmsis悠咱。
  • hal底層我增加了一層msp,類似于bsp征炼,全稱是mcu support package析既,這一層相當(dāng)于hal的驅(qū)動(dòng)層,與硬件相關(guān)的部分比如最終的時(shí)鐘配置谆奥,gpio配置等等提取出來眼坏,交給用戶配置。

了解了架構(gòu)酸些,下面我們就來配置一個(gè)簡單的工程吧宰译。

  1. 首先拷貝整個(gè)Driver目錄到工程中。
  2. 新建user文件夾魄懂,新建main.c文件沿侈。
    找到stm32f1xx_hal_conf_template.h,stm32f1xx_hal_msp_template.c,去掉"_template"放入user文件夾市栗。
    找到stm32f1xx_it.c和stm32f1xx_it.h放入user文件夾缀拭。
  3. 新建工程
    添加源文件:
Paste_Image.png

配置工程:

  • 勾選Use MicroLib咳短,因?yàn)閔al使用了c標(biāo)準(zhǔn)庫。
  • 添加全局宏定義:USE_HAL_DRIVER,STM32F103xB蛛淋。關(guān)于芯片選擇咙好,有如下表格:


    捕獲1.PNG
  • 勾選c99支持,因?yàn)閔al采用的是c99標(biāo)準(zhǔn)編寫铣鹏,不勾選的話敷扫,會出現(xiàn)類似于uint32_t等類型不存在的編譯錯(cuò)誤。
  • 添加包含目錄诚卸,如下圖:
Paste_Image.png

4.編寫代碼:

配置stm32f1xx_hal_conf.h:
這里面有許多用于配置的宏葵第,比如用于精準(zhǔn)延時(shí)的晶振頻率,還有各個(gè)外設(shè)模塊的開關(guān)等等合溺。

main.c

#include "stm32f1xx_hal.h"
int main()
{
    HAL_Init();
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    
    GPIO_InitTypeDef gpio_initstruct;
    gpio_initstruct.Mode=GPIO_MODE_OUTPUT_PP;
    gpio_initstruct.Speed=GPIO_SPEED_FREQ_HIGH;
    gpio_initstruct.Pull=GPIO_NOPULL;
    gpio_initstruct.Pin=GPIO_PIN_13;
    HAL_GPIO_Init(GPIOC,&gpio_initstruct);

    while(1)
    {
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,0);
        HAL_Delay(150);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);
        HAL_Delay(150);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,0);
        HAL_Delay(150);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);
        HAL_Delay(1000);
    }
    return 0;
}

stm32f1xx_hal_msp.c

#include "stm32f1xx_hal.h"
void SystemClock_Config(void);
void HAL_MspInit(void)
{
    SystemClock_Config();
}
void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef clkinitstruct = {0};
  RCC_OscInitTypeDef oscinitstruct = {0};
  
  /* Configure PLL ------------------------------------------------------*/
  /* PLL configuration: PLLCLK = (HSI / 2) * PLLMUL = (8 / 2) * 16 = 64 MHz */
  /* PREDIV1 configuration: PREDIV1CLK = PLLCLK / HSEPredivValue = 64 / 1 = 64 MHz */
  /* Enable HSI and activate PLL with HSi_DIV2 as source */
  oscinitstruct.OscillatorType  = RCC_OSCILLATORTYPE_HSE;//RCC_OSCILLATORTYPE_HSI;
  oscinitstruct.HSEState        = RCC_HSE_ON;//RCC_HSE_OFF;
  oscinitstruct.LSEState        = RCC_LSE_OFF;
  oscinitstruct.HSIState        = RCC_HSI_OFF;//RCC_HSI_ON;
  oscinitstruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  oscinitstruct.HSEPredivValue    = RCC_HSE_PREDIV_DIV1;
  oscinitstruct.PLL.PLLState    = RCC_PLL_ON;
  oscinitstruct.PLL.PLLSource   = RCC_PLLSOURCE_HSE;//RCC_PLLSOURCE_HSI_DIV2;
  oscinitstruct.PLL.PLLMUL      = RCC_PLL_MUL9;//RCC_PLL_MUL16;
  if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK)
  {
    /* Initialization Error */
    while(1); 
  }

  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 
     clocks dividers */
  clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
  clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;  
  if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK)
  {
    /* Initialization Error */
    while(1); 
  }
}

整個(gè)編程步驟就是卒密,hal庫初始化->開外設(shè)時(shí)鐘->外設(shè)初始化->用戶程序,然后在msp.c文件里實(shí)現(xiàn)其他平臺相關(guān)的雜七雜八的操作棠赛,需要調(diào)用的時(shí)候會自動(dòng)調(diào)用哮奇,我這里只實(shí)現(xiàn)了一個(gè)點(diǎn)亮led的功能,故只實(shí)現(xiàn)了HAL_MspInit()函數(shù)睛约。如果我們要使用uart鼎俘、adc等其他更復(fù)雜的外設(shè),我們需要在msp.c文件里重寫HAL_UART_MspInit()辩涝、HAL_ADC_MspInit()等函數(shù)贸伐,當(dāng)我們調(diào)用HAL_PPP_Init()時(shí),他們都會自動(dòng)被調(diào)用怔揩。

說到這里捉邢,我要說一下這里其實(shí)使用了一個(gè)c語言的技巧,實(shí)現(xiàn)了類似于c++的重載功能商膊。比如我們來看UART的源文件:

/**
  * @brief  USART MSP Init.
  * @param  husart: Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval None
  */
 __weak void HAL_USART_MspInit(USART_HandleTypeDef *husart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(husart);
  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_MspInit can be implemented in the user file
   */ 
}

函數(shù)被__weak修飾了伏伐,意思就是,如果別處沒定義晕拆,這個(gè)函數(shù)就是他藐翎,如果別處重定義了,就用新的函數(shù)实幕,這樣就實(shí)現(xiàn)了重載阱高。這有一個(gè)很大的好處,就是實(shí)現(xiàn)oo思想中的差異化編程茬缩,hal實(shí)現(xiàn)所有硬件通用的功能赤惊,而把不通用的部分通過可重載的函數(shù)開放給用戶修改。

體現(xiàn)oo的還有個(gè)地方凰锡,每個(gè)函數(shù)中未舟,都會接收到一個(gè)handle指針圈暗,這其實(shí)和this指針非常類似,每個(gè)函數(shù)都不用知道自己到底是在操作某一個(gè)具體的對象裕膀,只需要根據(jù)handle的指向來操作就可以了员串。

回到上面的重載。在hal庫中有一點(diǎn)比較大的改變是昼扛,中斷都是通過回調(diào)函數(shù)來開放給用戶的寸齐,具體使用方式也是重載相關(guān)回調(diào)函數(shù),不像標(biāo)準(zhǔn)庫是直接在stm32fxxx_it.c里填寫相關(guān)中斷處理函數(shù)抄谐。這樣做的好處是渺鹦,hal幫我們處理了一些中斷來臨時(shí)的雜務(wù),只把我們感興趣的事件開放給用戶蛹含。

但是個(gè)人覺得這個(gè)改變需要再徹底一點(diǎn)毅厚,因?yàn)檫@并沒有解決代碼耦合性的痛點(diǎn),每一次我們需要寫中斷函數(shù)的時(shí)候浦箱,總是要去改底層代碼吸耿,而如果st給我們實(shí)現(xiàn)一個(gè)注冊回調(diào)的接口,那么上層和下層之前就完全分離了酷窥,應(yīng)用層各個(gè)模塊之間也不會產(chǎn)生耦合咽安。

總結(jié):
總體而言,hal相比于標(biāo)準(zhǔn)庫蓬推,層次架構(gòu)更加清晰了妆棒,對平臺更加抽象,但是還遠(yuǎn)遠(yuǎn)不夠拳氢,依然非常依賴于具體的硬件募逞,如果能實(shí)現(xiàn)Qt的那種抽象就完美了蛋铆。用戶使用的時(shí)候馋评,只用包含hal.h而不用去管是hal_f1還是hal_f2或是什么其他系列的頭文件,所有系列的代碼打包在一起刺啦,通過條件編譯來實(shí)現(xiàn)真正的跨平臺留特,而如果需要使用某款mcu的特色功能時(shí),就再包含一個(gè)hal_f1extend.h玛瘸。如果這些st都實(shí)現(xiàn)了蜕青,那么單片機(jī)編程將會變得和應(yīng)用編程一樣簡單方便!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糊渊,一起剝皮案震驚了整個(gè)濱河市右核,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渺绒,老刑警劉巖贺喝,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菱鸥,死亡現(xiàn)場離奇詭異,居然都是意外死亡躏鱼,警方通過查閱死者的電腦和手機(jī)氮采,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來染苛,“玉大人鹊漠,你說我怎么就攤上這事〔栊校” “怎么了躯概?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拢军。 經(jīng)常有香客問我楞陷,道長,這世上最難降的妖魔是什么茉唉? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任固蛾,我火速辦了婚禮,結(jié)果婚禮上度陆,老公的妹妹穿的比我還像新娘艾凯。我一直安慰自己,他們只是感情好懂傀,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布趾诗。 她就那樣靜靜地躺著,像睡著了一般蹬蚁。 火紅的嫁衣襯著肌膚如雪恃泪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天犀斋,我揣著相機(jī)與錄音贝乎,去河邊找鬼。 笑死叽粹,一個(gè)胖子當(dāng)著我的面吹牛览效,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播虫几,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼锤灿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辆脸?” 一聲冷哼從身側(cè)響起但校,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啡氢,沒想到半個(gè)月后状囱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體州刽,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年浪箭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了穗椅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奶栖,死狀恐怖匹表,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宣鄙,我是刑警寧澤袍镀,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布冻晤,位于F島的核電站,受9級特大地震影響鼻弧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜攘轩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一叉存、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧度帮,春花似錦、人聲如沸笨篷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽练俐。三九已至,卻和暖如春安聘,著一層夾襖步出監(jiān)牢的瞬間痰洒,已是汗流浹背瓢棒。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留念颈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓榴芳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窟感。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容