咱們知道,存儲器自己沒有地址,給存儲器分配地址的過程叫存儲器映射,那什麼叫寄存器映射?寄存器究竟是什麼?html
在存儲器Block2 這塊區域,設計的是片上外設,它們以四個字節爲一個單元,共32bit,每個單元對應不一樣的功能,當咱們控制這些單元時就能夠驅動外設工做。咱們能夠找到每一個單元的起始地址,而後經過C 語言指針的操做方式來訪問這些單元,若是每次都是經過這種地址的方式來訪問,不只很差記憶還容易出錯,這時咱們能夠根據每一個單元功能的不一樣,以功能爲名給這個內存單元取一個別名,這個別名就是咱們常常說的寄存器,這個給已經分配好地址的有特定功能的內存單元取別名的過程就叫寄存器映射。linux
好比,咱們找到GPIOB 端口的輸出數據寄存器ODR 的地址是0x4001 0C0C(至於這個地址如何找到能夠先跳過,後面咱們會有詳細的講解),ODR 寄存器是32bit,低16bit有效,對應着16 個外部IO,寫0/1 對應的的IO 則輸出低/高電平。如今咱們經過C 語言指針的操做方式,讓GPIOB 的16 個IO 都輸出高電平。編程
1 // GPIOB 端口所有輸出 高電平學習
2 *(unsigned int*)(0x4001 0C0C) = 0xFFFF;設計
0x4001 0C0C 在咱們看來是GPIOB 端口ODR 的地址,可是在編譯器看來,這只是一個普通的變量,是一個當即數,要想讓編譯器也認爲是指針,咱們得進行強制類型轉換,把它轉換成指針,即(unsigned int *)0x4001 0C0C,而後再對這個指針進行 * 操做。剛剛咱們說了,經過絕對地址訪問內存單元很差記憶且容易出錯,咱們能夠經過寄存器的方式來操做。指針
1 // GPIOB 端口所有輸出 高電平視頻
2 #define GPIOB_ODR (unsigned int*)(GPIOB_BASE+0x0C)htm
3 * GPIOB_ODR = 0xFF;blog
爲了方便操做,咱們乾脆把指針操做「*」也定義到寄存器別名裏面。內存
1 // GPIOB 端口所有輸出 高電平
2#define GPIOB_ODR * (unsigned int*)(GPIOB_BASE+0x0C)
3 GPIOB_ODR = 0xFF;
STM32 的外設地址映射
片上外設區分爲三條總線,根據外設速度的不一樣,不一樣總線掛載着不一樣的外設,APB1掛載低速外設,APB2 和AHB 掛載高速外設。相應總線的最低地址咱們稱爲該總線的基地址,總線基地址也是掛載在該總線上的首個外設的地址。其中APB1 總線的地址最低,片上外設從這裏開始,也叫外設基地址。
1. 總線基地址
2. 外設基地址
總線上掛載着各類外設,這些外設也有本身的地址範圍,特定外設的首個地址稱爲「XX 外設基地址」,也叫XX 外設的邊界地址。具體有關STM32F10xx 外設的邊界地址請參考《STM32F10xx 參考手冊》的2.3 小節的存儲器映射的表1:STM32F10xx 寄存器邊界地址。
這裏面咱們以GPIO 這個外設來說解外設的基地址,GPIO 屬於高速的外設 ,掛載到APB2 總線上。
3. 外設寄存器
在XX 外設的地址範圍內,分佈着的就是該外設的寄存器。以GPIO 外設爲例,GPIO是通用輸入輸出端口的簡稱,簡單來講就是STM32 可控制的引腳,基本功能是控制引腳輸出高電平或者低電平。最簡單的應用就是把GPIO 的引腳鏈接到LED 燈的陰極,LED 燈的陽極接電源,而後經過STM32 控制該引腳的電平,從而實現控制LED 燈的亮滅。
GPIO 有不少個寄存器,每個都有特定的功能。每一個寄存器爲32bit,佔四個字節,在該外設的基地址上按照順序排列,寄存器的位置都以相對該外設基地址的偏移地址來描述。這裏咱們以GPIOB 端口爲例,來講明GPIO都有哪些寄存器。
有關外設的寄存器說明可參考《STM32F10xx 參考手冊》中具體章節的寄存器描述部分,在編程的時候咱們須要反覆的查閱外設的寄存器說明。
這裏咱們以「GPIO 端口置位/復位寄存器」爲例,告訴你們如何理解寄存器的說明。
①名稱
寄存器說明中首先列出了該寄存器中的名稱,「(GPIOx_BSRR)(x=A…E)」這段的意思是該寄存器名爲「GPIOx_BSRR」其中的「x」能夠爲A-E,也就是說這個寄存器說明適用於GPIOA、GPIOB 至GPIOE,這些GPIO端口都有這樣的一個寄存器。
②偏移地址
偏移地址是指本寄存器相對於這個外設的基地址的偏移。本寄存器的偏移地址是0x18,從參考手冊中咱們能夠查到GPIOA 外設的基地址爲0x4001 0800 ,咱們就能夠算出GPIOA的這個GPIOA_BSRR 寄存器的地址爲:0x4001 0800+0x18 ;同理,因爲GPIOB 的外設基地址爲0x4001 0C00,可算出GPIOB_BSRR 寄存器的地址爲:0x4001 0C00+0x18 。其餘GPIO端口以此類推便可。
③寄存器位表
緊接着的是本寄存器的位表,表中列出它的0-31 位的名稱及權限。表上方的數字爲位編號,中間爲位名稱,最下方爲讀寫權限,其中w 表示只寫,r 表示只讀,rw 表示可讀寫。本寄存器中的位權限都是w,因此只能寫,若是讀本寄存器,是沒法保證讀取到它真正內容的。而有的寄存器位只讀,通常是用於表示STM32 外設的某種工做狀態的,由STM32硬件自動更改,程序經過讀取那些寄存器位來判斷外設的工做狀態。
④位功能說明
位功能是寄存器說明中最重要的部分,它詳細介紹了寄存器每個位的功能。例如本寄存器中有兩種寄存器位,分別爲BRy 及BSy,其中的y 數值能夠是0-15,這裏的0-15表示端口的引腳號,如BR0、BS0 用於控制GPIOx 的第0 個引腳,若x 表示GPIOA,那就是控制GPIOA的第0 引腳,而BR一、BS1 就是控制GPIOA 第1 個引腳。
其中BRy 引腳的說明是「0:不會對相應的ODRx 位執行任何操做;1:對相應ODRx位進行復位」。這裏的「復位」是將該位設置爲0 的意思,而「置位」表示將該位設置爲1;說明中的ODRx 是另外一個寄存器的寄存器位,咱們只須要知道ODRx 位爲1 的時候,對應的引腳x 輸出高電平,爲0 的時候對應的引腳輸出低電平便可(感興趣的讀者能夠查詢該寄存器GPIOx_ODR 的說明了解)。因此,若是對BR0 寫入「1」的話,那麼GPIOx 的第0 個引腳就會輸出「低電平」,可是對BR0 寫入「0」的話,卻不會影響ODR0 位,因此引
腳電平不會改變。要想該引腳輸出「高電平」,就須要對「BS0」位寫入「1」,寄存器位BSy 與BRy 是相反的操做。
C 語言對寄存器的封裝
1. 封裝總線和外設基地址
在編程上爲了方便理解和記憶,咱們把總線基地址和外設基地址都以相應的宏定義起來,總線或者外設都以他們的名字做爲宏名。
首先定義了 「片上外設」基地址PERIPH_BASE,接着在PERIPH_BASE 上加入各個總線的地址偏移, 獲得APB1 、APB2 總線的地址APB1PERIPH_BASE 、APB2PERIPH_BASE,在其之上加入外設地址的偏移,獲得GPIOA-G的外設地址,最後在外設地址上加入各寄存器的地址偏移,獲得特定寄存器的地址。一旦有了具體地址,就能夠用指針讀寫。
該代碼使用 (unsigned int *) 把GPIOB_BSRR 宏的數值強制轉換成了地址,而後再用「*」號作取指針操做,對該地址的賦值,從而實現了寫寄存器的功能。一樣,讀寄存器也是用取指針操做,把寄存器中的數據取到變量裏,從而獲取STM32 外設的狀態。
2. 封裝寄存器列表
用上面的方法去定義地址,仍是稍顯繁瑣,例如GPIOA-GPIOE 都各有一組功能相同的寄存器,如GPIOA_ODR/GPIOB_ODR/GPIOC_ODR 等等,它們只是地址不同,但卻要爲每一個寄存器都定義它的地址。爲了更方便地訪問寄存器,咱們引入C 語言中的結構體語法對寄存器進行封裝。
這段代碼用typedef 關鍵字聲明瞭名爲GPIO_TypeDef 的結構體類型,結構體內有7 個成員變量,變量名正好對應寄存器的名字。C 語言的語法規定,結構體內變量的存儲空間是連續的,其中32 位的變量佔用4 個字節,16 位的變量佔用2 個字節。
也就是說,咱們定義的這個GPIO_TypeDef ,假如這個結構體的首地址爲0x40010C00(這也是第一個成員變量CRL 的地址), 那麼結構體中第二個成員變量CRH 的地址即爲0x4001 0C00 +0x04 ,加上的這個0x04 ,正是表明CRL 所佔用的4 個字節地址的偏移量,其它成員變量相對於結構體首地址的偏移,在上述代碼右側註釋已給。
這樣的地址偏移與STM32 GPIO 外設定義的寄存器地址偏移一一對應,只要給結構體設置好首地址,就能把結構體內成員的地址肯定下來,而後就能以結構體的形式訪問寄存器。
這段代碼先用GPIO_TypeDef 類型定義一個結構體指針GPIOx,並讓指針指向地址GPIOB_BASE(0x4001 0C00),使用地址肯定下來,而後根據C 語言訪問結構體的語法,用GPIOx->ODR 及GPIOx->IDR 等方式讀寫寄存器。
最後,咱們更進一步,直接使用宏定義好GPIO_TypeDef 類型的指針,並且指針指向各個GPIO端口的首地址,使用時咱們直接用該宏訪問寄存器便可。
這裏咱們僅是以GPIO 這個外設爲例,給你們講解了C 語言對寄存器的封裝。以此類推,其餘外設也一樣能夠用這種方法來封裝。好消息是,這部分工做都由固件庫幫咱們完成了,這裏咱們只是分析了下這個封裝的過程,讓你們知其然,也只其因此然。
stm32視頻學習資料
STM32能夠這樣玩
http://www.makeru.com.cn/live/4034_1460.html?s=45051
分析STM32的的開發方式
http://www.makeru.com.cn/live/3523_1673.html?s=45051
釋放潛能:學習效率提高、編程能力提高
http://www.makeru.com.cn/live/3507_1276.html?s=45051
從單片機到嵌入式linux咱們須要作什麼
http://www.makeru.com.cn/live/5413_1994.html?s=45051
stm32 如何用DMA搬運數據
http://www.makeru.com.cn/live/detail/1484.html?s=45051
(STM32中斷系統)
http://www.makeru.com.cn/live/1392_1124.html?s=45051
pdf以及相關文檔下載羣:830802928