日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32F429入门(二)

發(fā)布時(shí)間:2024/1/1 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32F429入门(二) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

開始學(xué)習(xí)嵌入式的第二天,發(fā)現(xiàn)昨天學(xué)習(xí)的東西有些遺漏,今天要做個(gè)補(bǔ)充😎。那么就從寄存器那一塊開始補(bǔ)學(xué)吧,昨天沒有那么仔細(xì)地去學(xué)習(xí)這個(gè)知識。

(一)學(xué)會看絲印:

  • 如果有小圓點(diǎn)在芯片上,則從這個(gè)小圓點(diǎn)開始逆時(shí)針,就是引腳口從1到最大引腳口。

  • 如果沒有小圓點(diǎn)在芯片上,則正看芯片,引腳口1在左上角開始,再逆時(shí)針。?

    ?

(二)芯片和外設(shè)之間通過各種總線連接,其中主控線(也就是內(nèi)核控制的部分)有8條,被控總線有7條,主控總線通過一個(gè)總線矩陣來連接被控總線,總線矩陣用于主控總線之間的訪問仲裁管理,仲裁采用 循環(huán)調(diào)度算法。總線之間交叉的時(shí)候如果有個(gè)圓圈則表示可以通信,沒有圓圈則表示不可以通信。

(三)STM32有三種啟動(dòng)方式:

  • 從Flash啟動(dòng)(包含系統(tǒng)存儲器)

  • 從內(nèi)部SRAM啟動(dòng)

  • 從外部RAM啟動(dòng)

    這也可以說明,啟動(dòng)總線與三根被控總線有交叉,也就是再總線接口圖中有圓圈,這三種存儲器就剛好對應(yīng)三條總線。

    (四)總線基地址

    片上的外設(shè)分為四條總線,根據(jù)外設(shè)速度不同,不同總線掛載著不同的外設(shè),APB掛載低速外設(shè),AHB掛載高速外設(shè)(GPIO為高速外設(shè))。相應(yīng)總線的最低地址我們陳為總線的基地址。

  • ?

如圖,0x4002 0000為AHB1總線的基地址。

相對外設(shè)基地址的偏移:即該總線地址與“片上外設(shè)”基地址 0x4000 0000 的差值。方便對外設(shè)進(jìn)行封裝使用。

?

(五)外設(shè)基地址

總線上掛載著各種外設(shè),這些外設(shè)也有自己的地址范圍,特定外設(shè)的首個(gè)地址稱為 “XX 外設(shè)基地址”,也叫 XX 外設(shè)的邊界地址。

對于我的理解就是,在確定總線基地址之后,我們在對總線中的外設(shè)進(jìn)行分配地址,而相對地址的偏移,就是相對于總線地址的偏移。

?

(六)外設(shè)寄存器

在 XX 外設(shè)的地址范圍內(nèi),分布著的就是該外設(shè)的寄存器。以 GPIO 外設(shè)為例,GPIO 是通用輸入輸出端口的簡稱,簡單來說就是 STM32 可控制的引腳,基本功能是控制引腳輸出高電平或者低電平。最簡單的應(yīng)用就是把 GPIO 的引腳連接到 LED 燈的陰極,LED 燈的 陽極接電源,然后通過 STM32 控制該引腳的電平,從而實(shí)現(xiàn)控制 LED 燈的亮滅。

GPIO 有很多個(gè)寄存器,每一個(gè)都有特定的功能。每個(gè)寄存器為 32bit,占四個(gè)字節(jié), 在該外設(shè)的基地址上按照順序排列,寄存器的位置都以相對該外設(shè)基地址的偏移地址來描述。

按照以上幾層基地址的層次嵌套,我們使用C語言封裝后,可以看到以下:

1 /* 外設(shè)基地址 */

?

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外設(shè)基地址 */

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)

所以偏移地址的好處就顯而易見了,在封裝時(shí),在基地址上加入偏移地址就可以了!😎

(七)舉個(gè)栗子

如果要使PH10實(shí)現(xiàn)輸出低/高電平,要怎么實(shí)現(xiàn)?

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位,后再取反,再與原來的值相與,保存原來的電平狀態(tài)。如圖所示:

?

step 3:

//輸出高電平

GPIOH_ODR |= (1<<10);

(八)由于每個(gè)寄存器的偏移地址都是4位,類似于結(jié)構(gòu)體的成員,成員地址都是遞增的,所以我們使用結(jié)構(gòu)體來封裝寄存器列表,也就是上一篇文的所有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輸入數(shù)據(jù)寄存器 地址偏移: 0x10 */

uint32_t ODR; /*GPIO輸出數(shù)據(jù)寄存器 地址偏移: 0x14 */

uint16_t BSRRL; /*GPIO置位/復(fù)位寄存器低16位部分 地址偏移: 0x18 */

uint16_t BSRRH; /*GPIO置位/復(fù)位寄存器高16位部分 地址偏移: 0x1A */

uint32_t LCKR; /*GPIO配置鎖定寄存器 地址偏移: 0x1C */

uint32_t AFR[2]; /*GPIO復(fù)用功能配置寄存器 地址偏移: 0x20-0x24 */

} GPIO_TypeDef;

所以我們就可以使用結(jié)構(gòu)體來訪問寄存器:

GPIO_TypeDef *GPIOx; //定義一個(gè)GPIO_TypeDef類型的結(jié)構(gòu)體指針GPIOx

GPIOx = GPIOH_BASE; //把指針地址設(shè)置為宏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把地址強(qiáng)制轉(zhuǎn)換成指針*/

#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)

定義以上后,我們可以直接”調(diào)用寄存器“:

GPIOA->ODR = 0xFF;

GPIOB->ODR = 0xFF;

... ...

那最后做個(gè)總結(jié)吧,其實(shí)封裝就是,從內(nèi)存映射到寄存器(define),之后用結(jié)構(gòu)體封裝,最后再用結(jié)構(gòu)體指針指向從而可以直接使用。(個(gè)人理解)

以上只是以GPIO為例子來理解這個(gè)東西,其實(shí)其他外設(shè)也是這么封裝的,那么今天的學(xué)習(xí)就到這吧,希望明天課多的我還可以擠出時(shí)間來學(xué)習(xí)!而且學(xué)習(xí)不敢像第一天這么敷衍了,漏了好多知識點(diǎn)T T。

總結(jié)

以上是生活随笔為你收集整理的STM32F429入门(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。