STM32入門系列 使用C語言封裝暫存器

2021-08-11 06:07:30 字數 3617 閱讀 7316

前面介紹了儲存器對映、暫存器和暫存器對映,這些都是為了介紹使用 c語言封裝暫存器做鋪墊。這裡我們通過乙個例項來對 c 語言封裝暫存器進行介紹。

具體例項:控制 gpioc 埠的第 0 管腳輸出乙個低電平。首先我們需要知道gpioc 埠外設是掛接在哪個匯流排上的,然後根據匯流排基位址和本身的偏移位址得到 gpioc 外設基位址,最後通過這個外設基位址得到裡面各種暫存器基位址。

匯流排和外設基位址封裝

根據暫存器的概念,我們可以使用 c 語言中的巨集定義對暫存器進行定義。具體**如下:

//定義外設基位址

#define periph_base ((unsigned int)0x40000000) 1)

//定義 apb2 匯流排基位址

#define apb2periph_base (periph_base + 0x00010000) 2)

//定義 gpioc 外設基位址

#define gpioc_base (ahb1periph_base + 0x0800) 3)

//定義暫存器基位址 這裡以 gpioc 為例

#define gpioc_crl *(unsigned int*)(gpioc_base+0x00) 4)

#define gpioc_crh *(unsigned int*)(gpioc_base+0x04)

#define gpioc_idr *(unsigned int*)(gpioc_base+0x08)

#define gpioc_odr *(unsigned int*)(gpioc_base+0x0c)

#define gpioc_bsrr *(unsigned int*)(gpioc_base+0x10)

#define gpioc_brr *(unsigned int*)(gpioc_base+0x14)

#define gpioc_lckr *(unsigned int*)(gpioc_base+0x18)

上述**中我們在後面備註了數字,下面對其進行簡單介紹下其功能:

定義外設的基位址,這個位址也是 block2 的基位址。

定義 apb2 匯流排基位址,因為 block2 的第乙個匯流排是 apb1,而 apb2 匯流排位址只需要加上對應的位址偏移量即可。

定義 gpio 外設基位址,因為 gpioc 是掛接在 apb2 匯流排上的,所以找到對應的埠位址偏移量即可知道 gpioc 埠基位址。

定義 gpio 外設暫存器基位址,這裡以 gpioc 埠為例,因gpioc_crl是 gpioc 外設的第乙個暫存器,所以基位址就是 gpioc 位址,其他暫存器位址只需要在 gpioc 基位址上加上相應的偏移量即可。

我們得到了暫存器具體的位址,那麼就可以使用 c 語言指標來操作讀寫。例如我們需要 gpioc0 輸出乙個低電平或者高電平,可以使用下面語句來操作。

//控制 gpioc 第 0 管腳輸出乙個低電平

gpioc_bsrr = (0x01<<(16+0));

//控制 gpioc 第 0 管腳輸出乙個高電平

gpioc_bsrr = (0x01<<0);

我們知道 gpioc_bsrr 的值是這個暫存器的位址,但是編譯器不知道它是位址,而是把它當做立即數,所以我們必須要強制轉換為(unsigned int *)指標型別才可以對其操作,這一點特別要注意。

嵌入式物聯網智慧型硬體等系統學習企鵝意義氣嗚嗚吧久零就易,

然後再在前面加上乙個「*」作取指標操作,表示對該位址內內容進行寫,讀操作也同樣使用「*」取指標操作。如下:

unsigned int temp;

temp =gpioc_idr;

將暫存器內的資料儲存在變數 temp 中,使用到變數時一定要進行定義。

暫存器封裝

通過前面講解,我們已經可以對暫存器進行操作,但是還稍有不足,因為stm32的gpio比較多, 我們不可能每使用乙個gpio都做前面一樣的一大堆定義。根據gpio暫存器的特點,我們知道不論gpioa還是gpiob等都擁有一組功能相同的暫存器,如gpioa_odr/gpiob_odr/gpioc_odr等等,它們只是位址不一樣。

為了更方便地訪問暫存器,我們引入c語言中的結構體對暫存器進行封裝,具體**如下:

typedef unsigned int uint32_t; /*無符號 32 位變數*/

typedef unsigned short int uint16_t; /*無符號 16 位變數*/

/* gpio 暫存器列表 */

typedef struct

gpio_typedef;

這段**用 typedef 關鍵字宣告了名為gpio_typedef的結構體型別,結構體內有7 個成員變數,變數名正好對應暫存器的名字。c 語言的語法規定,結構體內變數的儲存空間是連續的,其中32位的變數占用4個位元組,16 位的變數占用2個位元組。

於是,我們定義的gpio_typedef,假如這個結構體的首位址為0x4001 1000(這也是第乙個成員變數 crl的位址),那麼結構體中第二個成員變數crh的位址即為0x4001 1000 +0x04,加上的這個0x04,正是代表crh所占用的4個位元組位址的偏移量,其它成員變數相對於結構體首位址的偏移,在上述**右側注釋已給出。

這樣的位址偏移與stm32 gpio外設定義的暫存器位址偏移一一對應,只要給結構體設定好首位址,就能把結構體內成員的位址確定下來,然後就能以結構體的形式訪問暫存器了,比如我們還是將gpioc0輸出低電平,具體**如下:

gpio_typedef * gpiox; //定義乙個gpio_typedef型結構體指標gpiox

gpiox = gpioc_base; //把指標位址設定為巨集 gpioc_base 位址

gpiox->bsrr =(1<<(16+0)); //通過指標訪問並修改 gpioc_bsrr 暫存器

這段**先用gpio_typedef型別定義乙個結構體指標gpiox,並讓指標指向gpioc基位址gpioc_base,位址確定下來,然後根據c語言訪問結構體的內容,用gpiox->bsrr寫暫存器。為了操作更簡便靈活,我們直接使用巨集定義好gpio_typedef型別的指標,而且指標指向各個gpio埠的首位址,使用時我們直接用該巨集訪問暫存器即可。具體**如下:

#define gpioa ((gpio_typedef *) gpioa_base)

#define gpiob ((gpio_typedef *) gpiob_base)

#define gpioc ((gpio_typedef *) gpioc_base)

#define gpiod ((gpio_typedef *) gpiod_base)

#define gpioe ((gpio_typedef *) gpioe_base)

#define gpiof ((gpio_typedef *) gpiof_base)

#define gpiog ((gpio_typedef *) gpiog_base)

gpioc->bsrr = (1<<(16+0));

我們這裡僅僅以gpio這個外設為例,給大家講解了如何使用c語言對暫存器封裝,對於其他的外設也是使用同樣方法。其實到了後面的實驗程式的編寫,我們都是使用st公司提供的韌體庫,他們把stm32所有外設都已經封裝好了,我們只需要呼叫即可。 我們這裡分析這個封裝過程只是想讓大家更加清楚理解如何使用c來封裝暫存器的。

STM32入門系列 使用C語言封裝暫存器

具體例項 控制 gpioc 埠的第 0 管腳輸出乙個低電平。首先我們需要知道gpioc 埠外設是掛接在哪個匯流排上的,然後根據匯流排基位址和本身的偏移位址得到 gpioc 外設基位址,最後通過這個外設基位址得到裡面各種暫存器基位址。根據暫存器的概念,我們可以使用 c 語言中的巨集定義對暫存器進行定義...

STM32入門系列 使用C語言封裝暫存器

前面文章介紹了儲存器對映 暫存器和暫存器對映,這些都是為了介紹使用 c語言封裝暫存器做鋪墊。這裡我們通過乙個例項來對 c 語言封裝暫存器進行介紹。具體例項 控制 gpioc 埠的第 0 管腳輸出乙個低電平。首先我們需要知道gpioc 埠外設是掛接在哪個匯流排上的,然後根據匯流排基位址和本身的偏移位址...

STM32入門系列 STM32最小系統介紹

stm32最小系統組成 stm32微控制器最小系統,也就是能夠使得微控制器正常執行程式,最少需要連線哪些器件。一般來說,stm32最小系統由四部分組成 stm32微控制器由armcortexm3 匯流排矩陣 外設組成。微控制器開發板能夠做哪些事情是自己的選擇。我們可以製作一款stm32最小系統核心開...