STM32F429入门(二)
開始學習嵌入式的第二天,發現昨天學習的東西有些遺漏,今天要做個補充😎。那么就從寄存器那一塊開始補學吧,昨天沒有那么仔細地去學習這個知識。
(一)學會看絲印:
-
如果有小圓點在芯片上,則從這個小圓點開始逆時針,就是引腳口從1到最大引腳口。
-
如果沒有小圓點在芯片上,則正看芯片,引腳口1在左上角開始,再逆時針。?
?
(二)芯片和外設之間通過各種總線連接,其中主控線(也就是內核控制的部分)有8條,被控總線有7條,主控總線通過一個總線矩陣來連接被控總線,總線矩陣用于主控總線之間的訪問仲裁管理,仲裁采用 循環調度算法。總線之間交叉的時候如果有個圓圈則表示可以通信,沒有圓圈則表示不可以通信。
(三)STM32有三種啟動方式:
-
從Flash啟動(包含系統存儲器)
-
從內部SRAM啟動
-
從外部RAM啟動
這也可以說明,啟動總線與三根被控總線有交叉,也就是再總線接口圖中有圓圈,這三種存儲器就剛好對應三條總線。
(四)總線基地址
片上的外設分為四條總線,根據外設速度不同,不同總線掛載著不同的外設,APB掛載低速外設,AHB掛載高速外設(GPIO為高速外設)。相應總線的最低地址我們陳為總線的基地址。
-
?
如圖,0x4002 0000為AHB1總線的基地址。
相對外設基地址的偏移:即該總線地址與“片上外設”基地址 0x4000 0000 的差值。方便對外設進行封裝使用。
?
(五)外設基地址
總線上掛載著各種外設,這些外設也有自己的地址范圍,特定外設的首個地址稱為 “XX 外設基地址”,也叫 XX 外設的邊界地址。
對于我的理解就是,在確定總線基地址之后,我們在對總線中的外設進行分配地址,而相對地址的偏移,就是相對于總線地址的偏移。
?
(六)外設寄存器
在 XX 外設的地址范圍內,分布著的就是該外設的寄存器。以 GPIO 外設為例,GPIO 是通用輸入輸出端口的簡稱,簡單來說就是 STM32 可控制的引腳,基本功能是控制引腳輸出高電平或者低電平。最簡單的應用就是把 GPIO 的引腳連接到 LED 燈的陰極,LED 燈的 陽極接電源,然后通過 STM32 控制該引腳的電平,從而實現控制 LED 燈的亮滅。
GPIO 有很多個寄存器,每一個都有特定的功能。每個寄存器為 32bit,占四個字節, 在該外設的基地址上按照順序排列,寄存器的位置都以相對該外設基地址的偏移地址來描述。
按照以上幾層基地址的層次嵌套,我們使用C語言封裝后,可以看到以下:
1 /* 外設基地址 */
?
2 #define PERIPH_BASE ((unsigned int)0x40000000)
4 /* 總線基地址 */
5 #define APB1PERIPH_BASE PERIPH_BASE
6 #define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
7 #define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
8 #define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000)
10 /* GPIO外設基地址 */
11 #define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000)
12 #define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400)
13 #define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800)
14 #define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00)
15 #define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000)
16 #define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400)
17 #define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800)
18 #define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00)
20 /* 寄存器基地址,以GPIOH為例 */
21 #define GPIOH_MODER (GPIOH_BASE+0x00)
22 #define GPIOH_OTYPER (GPIOH_BASE+0x04)
23 #define GPIOH_OSPEEDR (GPIOH_BASE+0x08)
24 #define GPIOH_PUPDR (GPIOH_BASE+0x0C)
25 #define GPIOH_IDR (GPIOH_BASE+0x10)
26 #define GPIOH_ODR (GPIOH_BASE+0x14)
27 #define GPIOH_BSRR (GPIOH_BASE+0x18)
28 #define GPIOH_LCKR (GPIOH_BASE+0x1C)
29 #define GPIOH_AFRL (GPIOH_BASE+0x20)
30 #define GPIOH_AFRH (GPIOH_BASE+0x24)
所以偏移地址的好處就顯而易見了,在封裝時,在基地址上加入偏移地址就可以了!😎
(七)舉個栗子
如果要使PH10實現輸出低/高電平,要怎么實現?
step1:確定總線地址
#define PERIPH_BASE ((unsigned int)0x40000000)
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
#define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00)
#define GPIOH_ODR *(unsignedint*)(GPIOH_BASE+0x14)
step 2 :
//輸出低電平
GPIOH_ODR &= ~(1<<10);
以上代碼是使1左移10位,后再取反,再與原來的值相與,保存原來的電平狀態。如圖所示:
?
step 3:
//輸出高電平
GPIOH_ODR |= (1<<10);
(八)由于每個寄存器的偏移地址都是4位,類似于結構體的成員,成員地址都是遞增的,所以我們使用結構體來封裝寄存器列表,也就是上一篇文的所有GPIO寄存器,那就再提及一遍吧:
typedef unsigned int uint32_t; /*無符號32位變量*/
typedef unsigned short int uint16_t; /*無符號16位變量*/
/* GPIO寄存器列表 */
typedef struct {
uint32_t MODER; /*GPIO模式寄存器 地址偏移: 0x00 */
uint32_t OTYPER; /*GPIO輸出類型寄存器 地址偏移: 0x04 */
uint32_t OSPEEDR; /*GPIO輸出速度寄存器 地址偏移: 0x08 */
uint32_t PUPDR; /*GPIO上拉/下拉寄存器 地址偏移: 0x0C */
uint32_t IDR; /*GPIO輸入數據寄存器 地址偏移: 0x10 */
uint32_t ODR; /*GPIO輸出數據寄存器 地址偏移: 0x14 */
uint16_t BSRRL; /*GPIO置位/復位寄存器低16位部分 地址偏移: 0x18 */
uint16_t BSRRH; /*GPIO置位/復位寄存器高16位部分 地址偏移: 0x1A */
uint32_t LCKR; /*GPIO配置鎖定寄存器 地址偏移: 0x1C */
uint32_t AFR[2]; /*GPIO復用功能配置寄存器 地址偏移: 0x20-0x24 */
} GPIO_TypeDef;
所以我們就可以使用結構體來訪問寄存器:
GPIO_TypeDef *GPIOx; //定義一個GPIO_TypeDef類型的結構體指針GPIOx
GPIOx = GPIOH_BASE; //把指針地址設置為宏GPIOH_BASE地址
GPIOx->BSRRL = 0xFFFF; //通過指針訪問并修改GPIOH_BSRRL寄存器
GPIOx->MODER = 0xFFFFFFFF; //修改GPIOH_MODER寄存器
GPIOx->OTYPER =0xFFFFFFFF; //修改GPIOH_OTYPER寄存器
uint32_t temp;
temp = GPIOx->IDR; //讀取GPIOH_IDR寄存器的值到變量temp中
還有一種更簡單的方法,就是定義GPIO端口基地址指針,這種方法比較常見:
/*使用GPIO_TypeDef把地址強制轉換成指針*/
#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)
#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)
定義以上后,我們可以直接”調用寄存器“:
GPIOA->ODR = 0xFF;
GPIOB->ODR = 0xFF;
... ...
那最后做個總結吧,其實封裝就是,從內存映射到寄存器(define),之后用結構體封裝,最后再用結構體指針指向從而可以直接使用。(個人理解)
以上只是以GPIO為例子來理解這個東西,其實其他外設也是這么封裝的,那么今天的學習就到這吧,希望明天課多的我還可以擠出時間來學習!而且學習不敢像第一天這么敷衍了,漏了好多知識點T T。
總結
以上是生活随笔為你收集整理的STM32F429入门(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大流量稳定交易系统-王晓钟
- 下一篇: 天猫魔盒系统配置服务器,教你设置天猫魔盒