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

STM32F030F4單片機(jī)的出廠(chǎng)程序詳細(xì)資料免費(fèi)下載

使用STM32F030單片機(jī)讀取溫濕度傳感器SHT20的C語(yǔ)言源代碼免費(fèi)下載

STM32F030新建工程模板資料免費(fèi)下載

STM32F030單片機(jī)和TFT薄膜晶體管的電路原理圖免費(fèi)下載

STM32F030芯片的IAP升級(jí)

stm32f030系列時(shí)鐘介紹

STM32F030在低溫下無(wú)法啟動(dòng)

評(píng)論