野火STM32學(xué)習(xí)筆記(構(gòu)建庫函數(shù)模型第四節(jié)課)

緊接著第三節(jié)課的內(nèi)容
? ? ? ? 上一節(jié)課我們已經(jīng)在函數(shù)的頭文件里,描述了GPIO端口是如何通過結(jié)構(gòu)體和枚舉來定義和配置它的工作模式,工作速度以及端口號的。尤其對工作模式枚舉方式的講解做了具體的說明。知道了決定GPIO口的四種輸入與輸出模式的16進(jìn)制數(shù)是如何得來的。這一切都是為了在stm32f10x_gpio.c中編寫GPIO的初始化函數(shù)做準(zhǔn)備的。
GPIO初始化函數(shù)的編寫
這段代碼非常的長,我就直接復(fù)制官方庫里的函數(shù),來慢慢講解它。這段代碼先截圖給大家

將近100多行的代碼。。。。。沒關(guān)系這里面有注釋,只要大家認(rèn)真耐心看一定可以看明白。
初始化的時候,相當(dāng)于配置main.c函數(shù)里面的這倆行(控制端口配置低寄存器CRL),如圖:

畫紅色圈圈的兩行的工作,就可以由第一張圖那個一大段程序來完成。我們想要使用這個函數(shù),就要在頭文件里面定義一下,每一個新寫的函數(shù)都要這樣做!?。?!如圖:

目光轉(zhuǎn)移到stm32f10x_gpio.c這個C文件里的函數(shù)上,首先它有兩個形式參數(shù):GPIO_TypeDef* GPIOx和GPIO_InitTypeDef* GPIO_InitStruct。大家看到這個可能會云里霧里,這兩個參數(shù)干啥用的?請看下面。
對于GPIO初始化函數(shù)的形參1講解
? ? ? ? 第一個形式參數(shù)就是決定我們對哪一個GPIO口進(jìn)行初始化的,那個GPIOx是一個很明顯的特征,這個語句的意思是定義一個指針變量,指針的首地址是名字叫GPIO_TypeDef這個結(jié)構(gòu)體(下面我們將會看到它在哪)的首地址,這個參數(shù)我們只需要填入如GPIOA,GPIOB,GPIOC等等這些指針就可以。為什么說GPIOA,GPIOB,GPIOC是指針,答案可以在官方標(biāo)準(zhǔn)庫函數(shù)的頭文件stm32f10x.h里找到答案,如圖:已經(jīng)都是宏定義封裝好的指針(這些指針干啥用的不懂的,看我第一篇文章)

對于GPIO初始化函數(shù)的形參2(GPIO_InitTypeDef* GPIO_InitStruct)講解
第二個參數(shù)GPIO_InitTypeDef* GPIO_InitStruct,我們不妨來看一下他們在main.c文件里面是如何使用的,先把這倆行代碼刪除。

我們先定義一個GPIO初始化結(jié)構(gòu)體變量GPIO_InitStructure如圖所示

這個語句有兩點非常需要我們重視,第一點它是怎么定義一個GPIO初始化結(jié)構(gòu)體的:這個GPIO_InitTypeDef ,存在于stm32f10x_gpio.h這個頭文件之中,位于封裝GPIO工作狀態(tài)的結(jié)構(gòu)體的末尾,如圖所示:

GPIO_InitTypeDef,這在C語言當(dāng)中相當(dāng)于這個結(jié)構(gòu)體的名字。而在main函數(shù)中,它的后面加上GPIO_InitStructure的作用就是聲明一個結(jié)構(gòu)體,名字是GPIO_InitStructure。結(jié)構(gòu)體原型由名字叫GPIO_InitTypeDef的結(jié)構(gòu)體 確定。在之前的stm32f10x_gpio.h頭文件里設(shè)置完了GPIO_InitStructure(里面的內(nèi)容是GPIO_InitTypeDef的?)里面的內(nèi)容后
在初始化函數(shù)GPIO_Init (GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)里面調(diào)用,比如初始化pa口,就是GPIO_Init (GPIOA, &GPIO_InitStructure)。
? ? ? ?因為形式參數(shù)GPIO_InitTypeDef* GPIO_InitStruct(下面我簡稱形參2)也是一個指針變量,所以它只能是有效的指針和地址。由于第一個形式參數(shù)填入的GPIOA/B/C.......是已經(jīng)封裝好的地址,因此看起來不像一個正常的地址(上文已經(jīng)解釋)。因此,形參2要正常地進(jìn)行取結(jié)構(gòu)體(GPIO_InitStructure即GPIO_InitTypeDef)地址的操作,才會寫成GPIO_Init (GPIOx, &GPIO_InitStructure)看到最后大家就能知道在哪應(yīng)用的了。
? ? ? ?第二點,這個是C99版本C語言的一個默認(rèn)的規(guī)定,即定義的變量必須在第一個大括號之后,因此剛才定義的GPIO_InitTypeDef?GPIO_InitStructure必須放在開頭第一個大括號以后,前面不能以其他語句

? ? ? ? 因為前面的的語句(之前幾節(jié)課的內(nèi)容)用#if 0.......#else語句相當(dāng)于注釋了,我們只執(zhí)行#else......#endif之間的語句,因此GPIO_InitTypeDef?GPIO_InitStructure實際上是跟在第一個大括號后面。不過聽說后來的C語言標(biāo)準(zhǔn)沒那么嚴(yán)格了,有些版本的Keil 編譯器不會報錯。
配置結(jié)構(gòu)體成員
我們在main.c中配置結(jié)構(gòu)體GPIO_InitStructure的成員,輸入GPIO_InitStructure.(最后面有一個點千萬別忘了)如下圖:

配置的三個選項就出來了,可以看到它們本是結(jié)構(gòu)體GPIO_InitTypeDef的成員,我們選擇GPIO_Pin,再接上= GPIO_Pin_0;分號結(jié)束一個C語言語句,如圖

再配置速度和工作模式,它們的值可以在stm32f10x_gpio.h里面找到

我們配置為推挽輸出模式和50MHZ的工作速度(目的還是為了點亮LED綠燈)就在main.c里面這樣寫:

該結(jié)構(gòu)體配置完成以后,我們要將這些值寫入寄存器CRL(端口配置低寄存器)中,這時就調(diào)用GPIO_Init這個函數(shù)了,我們要配置GPIOB就這樣寫:GPIO_Init(GPIOB, &GPIO_InitStructure);

這樣我們配置CRL寄存器的工作就完成了,非常直觀明了。配置的哪一個口,什么模式,速度。比之前那兩行代碼容易理解多了。

這一節(jié)課的上下兩部分內(nèi)容就結(jié)束了,可以看到我們正在由寄存器編程向固件庫編程推進(jìn)。
端午假期摸了幾天??,不好意思哈。
下一節(jié)課,我會把GPIO_Init()函數(shù)(100多行那個)里面的內(nèi)容簡單講解一下。