熟悉STM32的都知道ST官方提供了非常方便好用的庫函數供用戶使用,多數人都使用過STM32標準外設庫,STM32Cube庫(即HAL庫),這個LL庫是什么鬼,卻從來沒聽說過。 好吧,我承認這個名字是我自己XJB取的。。。。。。。。
一、 初識LL 庫最近論壇發的STM32L476RGNucleo開發板到手了,準備學習玩耍,當然第一步就是下載資料,于是我下載STM32L4Cube 1.1.0版本,打開逐個查看,
184850p3m22imp2jn2w82x.png (53.21 KB, 下載次數: 115)
下載附件
2016-6-17 16:13 上傳
好像和以前一樣的,沒什么特別嘛,于是準備開始開發。。。 等等,好像還真發現了有點不一樣:
184852hroo3zi0q7e3pj0r.png (78.59 KB, 下載次數: 125)
下載附件
2016-6-17 16:13 上傳
熟悉HAL庫的都知道,該庫的文件幾乎都是以stm32xxx_hal_xxx.h/.c命名的,為了和以前的標準庫有個區分,上圖中那些是什么鬼????? 前輩說,遇到問題趕緊查手冊,于是我果斷打開STM32L4Cube庫的說明手冊(UM1884):
184853krnqnwwno8ogyg00.png (95.88 KB, 下載次數: 128)
下載附件
2016-6-17 16:13 上傳
原來這個東西叫做LowLayer APIs,作為英文渣渣表示實在不習慣洋里洋氣的高大上名字,于是擅自把他叫做【STM32LL庫】了(不服的你咬我啊)。 從這里看好像是說這個東東比HAL庫更接近硬件,到底什么鬼,還不清楚。但是以前好像沒見過這個東西啊,就算是STM32L4Cube的1.0.0版本中都沒有。看看Cube發行歷史:
184854txsqlcqsnscjjvx6.png (42.87 KB, 下載次數: 146)
下載附件
2016-6-17 16:13 上傳
原來LL庫是在1.1.0版本才加上的,大概意思就是: 1. LL APIs是寄存器級的編程,嗯,也就是我們常說的直接操作寄存器吧。 2. LL APIs適用于xxx等一大堆外設 3. LL APIs函數全部定義為staticinline函數,放在對應的頭文件中,用戶使用需要包含相關頭文件 4. 參考這兩個文檔 看看LL庫文件在Cube庫中的位置,有20多個文件,全部以stm32l4xx_ll_xxx.h命名: STM32Cube_FW_L4_V1.1.0DriversSTM32L4xx_HAL_DriverInc
184917y2dqkkksedyy5xkk.png (51.15 KB, 下載次數: 131)
下載附件
2016-6-17 16:13 上傳
STM32L4是面向低功耗市場的,同時不失高性能,功耗和性能往往是兩個矛盾的東西,ST在硬件設計上想了各種辦法來實現兼顧低功耗高性能(例如各種低功耗模式,LP外設等),而在軟件層面,程序也講求效率, LL庫全是直接操作寄存器,直接操作寄存器往往效率較高,而且函數定義為內聯函數,調用函數時不是堆棧調用,而是直接把函數的代碼嵌入到調用的地方,利于提高代碼相率,我想這也是ST在STM32L4系列中推出這個直接操作寄存器的LL庫的原因之一吧。
二、 怎么使用LL庫
185442fuagdxeeipygxfzx.png (78.23 KB, 下載次數: 149)
下載附件
2016-6-17 16:13 上傳
英文渣渣就不翻譯了,反正大概就是說 LL庫更接近硬件層,對需要復雜上層協議棧的外設不適用,直接操作寄存器等等一大堆,到這里,可以看到它的使用方法: 1. 獨立使用,該庫完全獨立實現,可以完全拋開HAL庫,只用LL庫編程完成。 2. 混合使用,和HAL庫結合使用。 本人就常在編程的時候庫函數和寄存器操作混合,所以覺得混合使用應該是不錯的方式。 最后一段還說到該庫不需要額外的內存資源來存儲程序狀態,數據指針等東西,所有的操作都通過直接修改外設的寄存器來完成。 下面是手冊中對各個LL文件的描述:
185450py5atc65ttbyib7p.png (72.21 KB, 下載次數: 136)
下載附件
2016-6-17 16:13 上傳
就是講LL庫由5部分組成:每個外設對應一個頭文件組成一部分,以及系統相關的bus,cortex,utils,system四個部分。
前面提到,要使用LL庫,需要包含對應頭文件,各頭文件之間有如下關系:
185454hexwg4x4zl6nzyqe.png (124.82 KB, 下載次數: 120)
下載附件
2016-6-17 16:13 上傳
看來,我們編程的時候只需要#include某外設的頭文件,就可以使用LL庫了,但是同時,系統啟動文件,初始化文件等一系列不能少,具體講就是: stm32l4xx.h stm32l476xx.h system_stm32l4xx.h system_stm32l4xx.c startup_stm32l476xx.s
這幾個文件,這在標準庫,Cube庫都不曾變過的鐵律。
順便分享一下STM32L4Cube 庫 1.1.0版本和1.1.1版本的Pack 百度網盤下載地址:http://pan.baidu.com/s/1c0wjL5m
一樓二樓是具體使用方法。
已完,上傳文檔和工程模板: 三、 開發環境搭建—— 新建STM32LL庫工程模板要開發首先要搭建開發環境,也就是簡歷所謂的工程模板。由于獨立使用LL庫的情況下不能使用Cube來建立工程,所以需要手動建立,這里的建工程方法和以前使用標準庫建工程模板比較類似: 1. 準備相關文件: 新建一個文件夾用來放所有的文件 把需要用到的相關文件全部復制過來: 首先是上一節說到的幾個必不可少的文件 stm32l4xx.h,stm32l476xx.h, system_stm32l4xx.h,system_stm32l4xx.c, startup_stm32l476xx.s 這些文件都在STM32Cube_FW_L4_V1.1.0DriversCMSISDeviceSTSTM32L4xx文件夾下,為了方便查找,我保持了和庫文件中相同的文件夾結構。如果閑麻煩,可以把STM32Cube_FW_L4_V1.1.0DriversCMSIS整個文件夾復制過來,該文件夾下的其他文件如Include文件夾里面的也需要用到。 然后把所有LL庫的文件復制過來, STM32Cube_FW_L4_V1.1.0DriversSTM32L4xx_HAL_DriverInc文件夾下面所有stm32l4xx_ll_xxx.h命名的文件,也可以整個文件夾復制。
125005b8ank8aag2ag6kyl.png (35.33 KB, 下載次數: 140)
下載附件
2016-6-17 16:13 上傳
其實主要就是這兩個文件夾下面相關的一些文件復制過來就好。當然一股腦全部粘貼過去也沒什么影響,就是工程大一點(henduo)。 最后建立Inc,Src,MDK-ARM文件夾放頭文件、源文件和工程文件,,stm32l4xx_it.h/.c這兩個文件其實也可以不要,因為我們可以把中斷函數處理函數放在任何地方都可以,main.c/main.h自己新建或者復制個模板。 所有文件,文件夾名字都可以隨便取,這里只是為了保持和庫、Cube建立的工程文件結構保持一致,所以取這些名字。
125006f7grrhgqhsprjz5k.png (16.24 KB, 下載次數: 115)
下載附件
2016-6-17 16:13 上傳
2. 好了,準備工作做好了,開始建工程 打開Keil MDK,新建一個工程選擇型號STM32L4RG,在此之前需要確保已經安裝了Keil STM32L4的Pack,不然新建工程的時候找不到對應的型號。
125007m5sammzzx1svpekn.png (1.7 KB, 下載次數: 143)
下載附件
2016-6-17 16:13 上傳
然后往工程里添加剛剛準備好的相關文件:
125009lemmlqbr1nz0rz50.png (46.15 KB, 下載次數: 121)
下載附件
2016-6-17 16:13 上傳
只需添加*.c和*.s文件,*.h文件設置頭文件包含路徑就行,也可以加到工程中方便查看。 接下來就是最重要的部分,工程設置: 有幾個主要地方需要設置, 1. 定義使用的芯片型號 STM32L4xx
125009w8mc6nn0959fnv5w.png (46.96 KB, 下載次數: 121)
下載附件
2016-6-17 16:13 上傳
2. 設置文件包含路徑 ..Inc //自己寫的頭文件路徑 ..DriversCMSISInclude //關于Cortex的一些頭文件 ..DriversCMSISDeviceSTSTM32L4xxInclude // stm32l4xx.h,stm32l476xx.h等文件 ..DriversSTM32L4xx_HAL_DriverInc //LL庫文件的路徑
125010goz4zocz2ttbafzx.png (23.1 KB, 下載次數: 138)
下載附件
2016-6-17 16:13 上傳
3. 設置所用調試仿真器,使用Nucleo板載ST-Link 4.
125015h0yklfeyy40ffy8l.png (61.13 KB, 下載次數: 134)
下載附件
2016-6-17 16:13 上傳
差不多就這些了,如果芯片型號選擇正確,pack安裝正確,其他的工程已經默認設置好,編譯一下無錯誤無警告,下面就是真正的開發,寫代碼了。
趁中午休息把開發環境搭建好,晚上回去寫兩個簡單例子,這篇帖子就算是完結了!
四、 LL庫 第一個程序——點亮LED
首先點亮LED來驗證下工程設置,代碼編寫是否正確。
1. 包含頭文件 在main.c中 #include "main.h"
在main.h中 - #include "stm32l4xx_ll_bus.h"
- #include "stm32l4xx_ll_rcc.h"
- #include "stm32l4xx_ll_system.h"
- #include "stm32l4xx_ll_utils.h"
- #include "stm32l4xx_ll_gpio.h"
- #include "stm32l4xx_ll_exti.h"
復制代碼
包含需要使用的相關模塊,要用那些就包含哪些,不知道用哪幾個就全部包含進去。
2. 配置時鐘 用這個LL庫開發STM32跟用標準外設庫很像,很類似,只不過封裝層次更低。首先第一步要配置時鐘,因為啟動文件里沒有默認配置,這和STM32F1早期的標準外設庫一樣,不過較高版本和后來的系列就可以不用了(如果使用默認配置的話),啟動文件里默認配置了時鐘。怎么配置這里就不細說了,看代碼應該都能懂。 - __STATIC_INLINE void SystemClock_Config(void)
- {
- LL_FLASH_SetLatency(LL_FLASH_LATENCY_4);
-
- LL_RCC_HSI_Enable();
- while(LL_RCC_HSI_IsReady() != 1)
- {
- };
- LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_1, 10, LL_RCC_PLLR_DIV_2);
- LL_RCC_PLL_Enable();
- LL_RCC_PLL_EnableDomain_SYS();
- while(LL_RCC_PLL_IsReady() != 1) ;
- LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
- LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
- while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) ;
-
- LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
- LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
- LL_Init1msTick(80000000);
- LL_SetSystemCoreClock(80000000);
- }
復制代碼
函數聲明為__STATIC_INLINE(即staticinline)是因為該庫所有函數都是__STATIC_INLINE,前面提到這樣做不需要額外的內存,因此這樣最是為了保持這一點。
3. 將LED對應引腳PA5配置為推挽輸出模式 - __STATIC_INLINE void Configure_GPIO(void)
- {
- LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
- LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);
- LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5, LL_GPIO_OUTPUT_PUSHPULL);
- LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_LOW);
- LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_5, LL_GPIO_PULL_NO);
- }
復制代碼
4. PA5輸出高電平,點亮LED LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_5); 5. 最后需要在主函數中依次調用上訴函數,編譯下載運行即可看到Nulceo上的綠色LED被成功點亮了。 - int main(void)
- {
- SystemClock_Config();
- Configure_GPIO();
- LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_5);
- while (1)
- { ;
- }
- }
復制代碼
/*碎碎念:雖然已經不知道這是第幾百還是第幾千次做點燈實驗,依然還是不厭其煩啊,LED不愧是被稱為單片機屆的”Hello World!”*/
五、 添加其他程序功能
會了第一個程序,其他的就按照手冊講的寫就行了,再舉個簡單的例子,利用按鍵中斷模式來控制LED的閃爍頻率。 只說下大概步奏,不詳細說明:將按鍵連接的引腳配置為中斷輸入模式,開啟中斷,配置中斷線,寫中斷服務函數來處理中斷。 - __STATIC_INLINE void Configure_EXTI(void)
- {
- LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);
- LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
- LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_INPUT);
- LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_13, LL_GPIO_PULL_NO);
- NVIC_EnableIRQ(EXTI15_10_IRQn);
- NVIC_SetPriority(EXTI15_10_IRQn, 0);
- LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTC, LL_SYSCFG_EXTI_LINE13 );
- LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_13);
- LL_EXTI_EnableFallingTrig_0_31(LL_EXTI_LINE_13);
- }
復制代碼
在主函數調用Configure_EXTI()并添加代碼: - while (1)
- {
- LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
- if(i == 0)
- {
- LL_mDelay(100);
- }
- else if(i == 1)
- {
- LL_mDelay(500);
- }
- else
- {
- LL_mDelay(1000);
- }
- }
復制代碼
實現功能:每按一次按鍵,LED改變一次閃爍頻率,間隔0.1s,0.5s,1s三種不同頻率循環閃爍。
最后,這個LL庫總體給人感覺是使用方法跟標準外設庫很像,但也有不同,前面也有提到,它全是直接操作寄存器,程序效率一定程度上會比較高,但使用起來有時候不一定那么方便,可移植性也不好,所以把它和HAL庫結合起來使用是最好的方式,在程序要求效率的地方就可以使用這些函數,而其他地方使用HAL庫,這也是我們常常使用的方法,只不過以前是使用HAL庫,需要的地方我們自己直接寫操作寄存器,而現在可以換成使用這個【LL庫】了。
上個IAR工程模板:
stm32L476.7z
(2.24 MB, 下載次數: 27)
2021-8-12 16:58 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|