1. 第一個工程 翻轉引腳
上一篇文章我們詳細介紹了 STM32F030 從復位時取得復位向量,系統初始化,然后跳轉到 main( ) 函數的過程。下面我們結合一個最簡單的例子,對 Cube 庫的使用做一個簡單的介紹。我們用 Keil 打開下面這個工程:STM32Cube_FW_F0_V1.11.0ProjectsSTM32F030R8-NucleoExamplesGPIOGPIO_IOToggleMDK-ARMProject.uvprojx
編譯下載運行此代碼,會看到一個 LED燈(連至MCU的 PA5引腳)不停地閃爍。為了完成這個簡單的功能,我們看到這個工程里包含了不少文件:
如果是初次用這種庫的方式做開發,乍一看還真感覺有點亂。不過讓我們一個一個看一下這些文件,理清它們的關系后就會體會到這種方式的巨大優點。
2. 文件分類解釋
工程里的文件分為五大類:啟動代碼,M0內核初始化,驅動,板級支持包(BSP),用戶代碼。一般來說我們開發應用程序,主要關注用戶代碼文件就行了。如果硬件電路板做了改動,則修改BSP里的內容。在早期的單片機開發中,芯片內資源很少,通常的情況是一個工程師就從硬件到軟件編程都做了,是沒有 BSP(Board Support Package)這種概念的。BSP概念來源于較復雜的CPU系統的開發,一般是廠家設計主板,并提供 BSP(包含啟動代碼,驅動,Bootloader等)。我們這里的 BSP 概念稍有不同,它是指對某一塊兒以 MCU 為核心的電路板的支持代碼包。啟動代碼,內核初始化和驅動,沒有包含在內。BSP會調用驅動層的代碼。對于 STM32 Nucleo 這塊兒開發板來說,板上資源很少,所以BSP只提供了相應的按鍵(BUTTON)和指示燈(LED)支持代碼。里面的ADC,SPI,LCD等代碼是支持其它板子的,可以先忽略。
啟動代碼
為理解匯編代碼,我們先熟悉一下這些偽指令:
ALIGN 變量或代碼對齊。如:
ALIGN = 3 以8(2的3次方)字節對齊。
EQU 給標號賦值。如:
Stack_SizeEQU 0x400;
Data DCD 1,5,8; 定義3個字并賦值為 1,5 和 8。
AREA 定義一個代碼或數據段(section),命名并指定屬性。如:
AREA Func01, CODE, READONLY;
定義了一個名字為 Func01 的只讀代碼段。
SPACE 保留一段空間并初始化為 0。如:
Data SPACE 100; 為 Data 保留 100個字節初始化為 0 的內存空間。
IMPORT 導入其它文件中的標號,以在當前文件中引用。如:
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
從文件 system_stm32f0xx.c 中導入 SystemInit 這個函數并調用。
EXPORT 導出能被連接器(Linker)識別的標號。從ASM文件導出的標號可以在C中引用。
[WEAK] 如果在其它地方定義了相同的標號,則此處定義被覆蓋。
PROC 定義一個函數的起始地址。
ENDP 標志當前函數結束。
例子:
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B.
ENDP
導出 SysTick_Handler 這個中斷處理函數。如果在其它地方定義了一個新的 SysTick_Handler 函數,那么新函數將覆蓋此處定義的這個陷阱函數。匯編語句 B.為在當前語句死循環。下面我們看一下啟動文件 startup_stm32f030x8.s
定義堆和棧:
中斷向量表:
現在這個工程用到的只有綠線框中的幾個向量:
__initial_sp
初始堆棧指針
Reset_Handler
復位向量,我們在上一篇文章已經講到如何從復位向量一步一步執行到用戶代碼中的主程序main( )。
SysTick_Handler
系統時鐘中斷向量。此程序每 1ms 產生一次中斷。
需要注意的是 SysTick_Handler 這個中斷處理函數在用戶代碼文件stm32f0xx_it.c
中進行了重定義,所以當 SysTick 中斷發生時,實際會跳轉到用戶代碼的中斷處理函數,而不是跳到下圖所示的匯編代碼中斷處理函數進入死循環。
再往下可以看到,對所有芯片級中斷定義了一個共享的陷阱函數。用戶在實際使用到某一個中斷的時候,要在中斷處理文件 stm32f0xx_it.c 中用相同的函數名定義,從而在中斷發生時跳轉到實際的中斷處理函數。
在此文件的最下面的代碼,是用來傳遞堆棧信息給庫的:
在芯片資源比較少時,可以通過選中 Options for Target->Target->Use MicroLIB 選項,使用簡化版的庫來實現 printf 等操作。若資源充足時使用標準庫,庫將調用下面的 __user_initial_stackheap 函數來獲得堆棧信息。
M0 內核初始化
system_stm32f0xx.c此文件只有兩個函數:SystemInit( ),在啟動代碼中調用,把系統時鐘復位到初始默認狀態(8MHz的高頻內部時鐘 HSI)。SystemCoreClockUpdate( ), 在用戶調用庫函數更改時鐘配置后,需要調用此函數以更新全局系統時鐘變量 SystemCoreClock。其它模塊基于此時鐘的計算才會正確。一般來說更改時鐘配置的 HAL函數已經包含此函數的調用,如 HAL_RCC_ClockConfig( ), 無需用戶再次調用。
驅動
stm32f0xx_hal_cortex.c包含 Cortex 內核中兩個重要模塊的驅動:可嵌套中斷向量控制器 NVIC(Nested Vectored Interrupt Controller),系統滴答時鐘 SYSTICK。
stm32f0xx_hal.c
此文件包含用戶程序必須首先調用的 HAL_Init( ),它會使能數據和指令緩存,預取指令隊列;配置系統滴答時鐘產生 1ms 中斷;調用 HAL_MspInit( )回調函數。
HAL_MspInit( )函數用來做系統級的初始化,配置某一模塊相關的 時鐘,引腳,DMA,中斷等資源,但是在所有的例程中都沒有實際用到此函數。可以先忽略。
stm32f0xx_hal_rcc.cstm32f0xx_hal_rcc_ex.c
RCC(Reset and Clock Controller)模塊的驅動。一個模塊為什么要兩個驅動文件呢?前一個文件提供了基本的通用的功能驅動,后一個文件是擴展功能驅動,通常針對某一特定型號的芯片。如同我們吃飯需要餐具,_rcc.c 提供碗筷等常用必備工具,_rcc_ex 可能提供的就是酒杯,燭臺等這些東西。
stm32f0xx_hal_gpio.c
GPIO 模塊的驅動。
BSP 板級支持包
stm32f0xx_nucleo.c
針對 STM32 Nucleo 開發板的類型,宏定義,支持代碼。
用戶代碼
main.c 主程序
stm32f0xx_it.c 中斷處理
前面介紹了一大堆文件,主要是為了清除系統的工作流程。在開發中使用庫還是很簡單的。在主程序中調用庫,只需要通過 main.h 包含下面這個頭文件:stm32f0xx_hal.h如果有 BSP 則包含 BSP 的頭文件,在本工程是:stm32f0xx_nucleo.h
使用到哪個模塊就在配置文件中打開使能該模塊的宏定義。
stm32f0xx_hal_conf.h
然后第一步必須調用 HAL_Init( )。
第二步,如果希望系統時鐘工作在默認內部時鐘(8MHz HIS)以外的頻率,則需要調用 SystemClock_Config( )。此函數又調用 HAL_RCC_ClockConfig( ) 完成新配置。
下面是應用代碼:
所有模塊一般都是這三個步驟:使能模塊的時鐘,初始化模塊,使用模塊的功能。
stm32f0xx_it.c 中的中斷處理函數 SysTick_Handler( ) 很簡單,每次進入就對滴答計時變量 uwTick 加1,其它 HAL 函數可以基于此變量計時。
審核編輯:劉清
-
單片機
+關注
關注
6037文章
44558瀏覽量
635301 -
led燈
+關注
關注
22文章
1592瀏覽量
107999 -
中斷處理
+關注
關注
0文章
94瀏覽量
10976 -
STM32F0
+關注
關注
0文章
61瀏覽量
17106
發布評論請先 登錄
相關推薦
評論