stm32初學之GPIO寄存器

想從LED開始學起,但對寄存器什麼的都不懂,小白一個,只好各種查資料,同時做下筆記。

要控制GPIO端口,就得控制相關的寄存器。可分爲4類,其功能簡單概括如下:

1 .配置寄存器:選定GPIO 的特定功能,最基本的如:選擇作爲輸入還是輸出端口。

2. 數據寄存器:保存了 GPIO 的輸入電平 或 將要輸出的電平。

3. 位控制寄存器:設置某引腳的數據 爲 1 或 0,控制輸出的電平。

4. 鎖定寄存器:設置某鎖定引腳後,就不能修改其配置。

配置器的具體參數,還是參考《STM32參考手冊》的寄存器說明,如下圖:


由圖可知,對於 GPIO 端口,每個端口有 16 個引腳,由兩位控制一個引腳的配置。地址偏移是寄存器相對於所在寄存器組的偏移地址,下面會說。參考手冊的數據很詳細,到時直接看手冊就行。比如我對X端口的BS0寫1,則此端口第0引腳被設置爲1,輸出高電平,若要再令其引腳輸出低電平,則只需向BR0寫1。

接下來在看看STM32的地址映射

所謂地址映射,就是將芯片上的存儲器  甚至 I/O 等資源與地址建立一一對應的關係。到時就可以直接運用C語言的指針來直接修改寄存器的內容。

STM32的Cortex-M3 有 32 根地址線,所以它的尋址空間大小爲 2^32 bit=4GB,而且ARM公司還預先分配好了尋址空間。如下圖。


STM32中有一個stm32f10x.h頭文件,這個文件中就對STM32中所有的寄存器進行了地址映射。由圖可以看到片上外設使用的地址是0x40000000到0x5FFFFFFF,其中把0x40000000稱爲外設基地址,在文件中定義爲PERIPH_BASE。在這個文件中,可以發現以下類似的宏:

#define GPIOA_BASE        (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE        (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE        (APB2PERIPH_BASE + 0x1000)

GPIOA_BASE代表GPIOA的寄存器組基地址,以下類似。這裏APB2PERIPH_BASE是指APB2總線基地址,其值爲(PERIPH_BASE + 0x10000),就不多說了,看手冊吧。在每個寄存器組之間的地址就是分配給寄存器的,剛開始說的寄存器的地址偏移就是指基於GPIOx_BASE的偏移量。在這STM32採用的是結構體來封裝寄存器組,結構體如下:

typedef struct
{
     __IO uint32_t CRL;
     __IO uint32_t CRH;
     __IO uint32_t IDR;
     __IO uint32_t ODR;
     __IO uint32_t BSRR;
     __IO uint32_t BRR;
     __IO uint32_t LCKR;
}GPIO_TypeDef;

其中__IO是一個宏,定義如下:

#define  __IO     volatile

而volatile是一個關鍵字,其作用是確保本條指令不會因編譯器的優化而省略,且要求每次直接讀值。

這些變量每個都爲 32 位,也就是每個變量佔內存空間 4 個字節,剛好對應4個字節的偏移量,所以在stm32f10x.h中有以下代碼:

#define GPIOA      ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB      ((GPIO_TypeDef *) GPIOB_BASE)
其他寄存器組類似,這樣只要我們匹配了結構體的首地址,就可以確定各寄存器的具體地址了。所以就可以用以下方式來修改GPIO的寄存器了。

GPIO_TypeDef  *GPIOx;
GPIOx  = GPIOA;
GPIOx->CRL = 0xffffffff;

當然,這樣自己寫太費時間了,也沒啥效率,而且我還是小白,這只是爲了理解底層寄存器操作,實際寫程序肯定不會這樣寫,而是選擇用STM32的庫了,各種API,用起來多方便啊。





發佈了34 篇原創文章 · 獲贊 8 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章