使用庫函數點亮LED,不用我們自己去查看寄存器,方便我們的開發,但是庫函數是怎樣封裝的呢?
int main(void)
{
//聲明一個結構體變量
GPIO_InitTypeDef GPIO_InitStructure;
//使能GPIO外設時鐘
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
//定義一個結構體
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9 |GPIO_Pin_10;//連接LED的引腳
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //輸出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; //推輓
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOF,&GPIO_InitStructure);
delay_init(84);
while(1)
{
GPIO_SetBits(GPIOF,GPIO_Pin_9 |GPIO_Pin_10);
delay_ms(1000);
GPIO_ResetBits(GPIOF,GPIO_Pin_9 |GPIO_Pin_10);
delay_ms(1000);
}
}
一. 首先我們應該先從整體上了解內存地址分佈,從0~0xFFFFFFFF,將其分成8個block,每個block爲512M。
在block0中,比較關心的應該是flash,也就是我們存放代碼的地方(應該可以說是二進制代碼)。
在block1中,是SRAM,128KB。
在block2中,這個纔是這裏最關鍵要講的,這裏包含了APB1,APB2,其中有很多的外設如IIC,SPI,TIMER等,從圖中,我們就可以看到該外設的總線的基地址。
二.先明確一點,我們通常是如何操作寄存器的。
*((uint32_t *)0x42024000)=0x00000001;
將一個數值將其強制裝換爲一個32位地址,然後就可以將其進行32位的存取操作
三.接下看看庫函數中是如何封裝的,以GPIOF爲例
思路:先判斷GPIO在那條總線上,然後找到其總線基地址,然後GPIOF的偏移量是多少
所以如下圖可知,GPIOF在AHB1總線上,找到AHB1的總線地址,爲0x40020000(上面圖少個一個0,是4個字節)
在頭文件stm32f4xx.h
總外設的基地址:
AHB1外設總線的基地址爲:
因此,地址顯而易見
0x40000000+0x00020000=0x40020000
接下來我們再找到GPIO的基地址:
在STM32F4xx中文參考手冊中,我們可以找到這樣的文字,看出它的偏移地址爲0x00001400
因此GPIOF的基地址定義如下
四.寄存器結構體(我自己命名的,不知道有沒有這種說法)
所謂寄存器結構體,就是將某種功能的寄存器,一起封裝而成,以GPIOF爲例
我們知道要操作一個IO口,要進行多種寄存器配置,所以庫函數頭文件stm32f4xx.h中,就有如下結構體
爲什是要按照這個順序排列呢,從下面幾圖就可以清楚看出來
封裝之後這些寄存器就好控制了,但是現在和我們上面說的基地址有什麼關係?自己剛看出來的時候,覺得巧妙
庫函數中對其進行如下處理:
將以GPIOF_BASE爲基地址轉化爲結構體指針 ,也就是說,該結構體以0x40021400爲基地址,結構體中的寄存器進行4個字節偏移的偏移,然後進行操作,如下圖所示
先將GPIOF指針傳入,然後直接進行寄存器進行操作,庫函數的寄存器封裝到此爲止
五.人性化結構體(這也是我自己這樣叫的)
所謂人性化結構體,就是以我們正常人比較好理解的方式進行封裝成結構體,如下
這種結構體我們一下就可以看出它是做什麼的,怎麼賦值的,所以人性化,
一般常見於,我們平常所要用的外設頭文件中,所以該結構體在是stm32f4xx_gpio.h中(點到爲止,該類結構體類似)
將該人性化結構體進行聲明,定義之後,就可以將其傳入庫函數中,判斷,拆解之後,直接用 寄存器結構體 操作底層寄存器,進行GPIO的初始化。
最後就可以進行GPIO的控制了,當然是在GPIOF時鐘使能之後了
-----------------------這是終結線------------------------------------------
其他外設也是如此,可以去庫函數中以此類推