單片機(jī)STM32學(xué)習(xí)筆記之寄存器映射詳解

  我們知道,存儲器本身沒有地址袋马,給存儲器分配地址的過程叫存儲器映射初澎,那什么叫寄存器映射?寄存器到底是什么?

  在存儲器Block2

這塊區(qū)域,設(shè)計(jì)的是片上外設(shè)虑凛,它們以四個(gè)字節(jié)為一個(gè)單元碑宴,共32bit,每一個(gè)單元對應(yīng)不同的功能桑谍,當(dāng)我們控制這些單元時(shí)就可以驅(qū)動外設(shè)工作延柠。我們可以找到每個(gè)單元的起始地址,然后通過C

語言指針的操作方式來訪問這些單元锣披,如果每次都是通過這種地址的方式來訪問贞间,不僅不好記憶還容易出錯(cuò)贿条,這時(shí)我們可以根據(jù)每個(gè)單元功能的不同,以功能為名給這個(gè)內(nèi)存單元取一個(gè)別名增热,這個(gè)別名就是我們經(jīng)常說的寄存器整以,這個(gè)給已經(jīng)分配好地址的有特定功能的內(nèi)存單元取別名的過程就叫寄存器映射。

  比如钓葫,我們找到GPIOB 端口的輸出數(shù)據(jù)寄存器ODR 的地址是0x4001 0C0C(至于這個(gè)地址如何找到可以先跳過悄蕾,后面我們會有詳細(xì)的講解),ODR

寄存器是32bit础浮,低16bit有效帆调,對應(yīng)著16 個(gè)外部IO,寫0/1 對應(yīng)的的IO 則輸出低/高電平《雇現(xiàn)在我們通過C 語言指針的操作方式番刊,讓GPIOB 的16

個(gè)IO 都輸出高電平。

  1 // GPIOB 端口全部輸出 高電平

  2 *(unsigned int*)(0x4001 0C0C) = 0xFFFF;

  0x4001 0C0C 在我們看來是GPIOB 端口ODR

的地址影锈,但是在編譯器看來芹务,這只是一個(gè)普通的變量,是一個(gè)立即數(shù)鸭廷,要想讓編譯器也認(rèn)為是指針枣抱,我們得進(jìn)行強(qiáng)制類型轉(zhuǎn)換,把它轉(zhuǎn)換成指針辆床,即(unsigned int

*)0x4001 0C0C佳晶,然后再對這個(gè)指針進(jìn)行 * 操作。剛剛我們說了讼载,通過絕對地址訪問內(nèi)存單元不好記憶且容易出錯(cuò)轿秧,我們可以通過寄存器的方式來操作。

  1 // GPIOB 端口全部輸出 高電平

  2 #define GPIOB_ODR (unsigned int*)(GPIOB_BASE+0x0C)

  3 * GPIOB_ODR = 0xFF;

  為了方便操作咨堤,我們干脆把指針操作“*”也定義到寄存器別名里面菇篡。

  1 // GPIOB 端口全部輸出 高電平

  2#define GPIOB_ODR * (unsigned int*)(GPIOB_BASE+0x0C)

  3 GPIOB_ODR = 0xFF;

  STM32 的外設(shè)地址映射

  片上外設(shè)區(qū)分為三條總線,根據(jù)外設(shè)速度的不同一喘,不同總線掛載著不同的外設(shè)驱还,APB1掛載低速外設(shè),APB2 和AHB

掛載高速外設(shè)凸克。相應(yīng)總線的最低地址我們稱為該總線的基地址铝侵,總線基地址也是掛載在該總線上的首個(gè)外設(shè)的地址。其中APB1

總線的地址最低触徐,片上外設(shè)從這里開始,也叫外設(shè)基地址狐赡。

  1. 總線基地址

  2. 外設(shè)基地址

  總線上掛載著各種外設(shè)撞鹉,這些外設(shè)也有自己的地址范圍,特定外設(shè)的首個(gè)地址稱為“XX 外設(shè)基地址”,也叫XX 外設(shè)的邊界地址鸟雏。具體有關(guān)STM32F10xx

外設(shè)的邊界地址請參考《STM32F10xx 參考手冊》的2.3 小節(jié)的存儲器映射的表1:STM32F10xx 寄存器邊界地址享郊。

  這里面我們以GPIO 這個(gè)外設(shè)來講解外設(shè)的基地址,GPIO 屬于高速的外設(shè) 孝鹊,掛載到APB2 總線上炊琉。

  3. 外設(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è)基地址的偏移地址來描述。這里我們以GPIOB

端口為例目锭,來說明GPIO都有哪些寄存器评汰。

  有關(guān)外設(shè)的寄存器說明可參考《STM32F10xx 參考手冊》中具體章節(jié)的寄存器描述部分,在編程的時(shí)候我們需要反復(fù)的查閱外設(shè)的寄存器說明痢虹。

  這里我們以“GPIO 端口置位/復(fù)位寄存器”為例被去,告訴大家如何理解寄存器的說明。

 〗蔽ā①名稱

  寄存器說明中首先列出了該寄存器中的名稱惨缆,“(GPIOx_BSRR)(x=A…E)”這段的意思是該寄存器名為“GPIOx_BSRR”其中的“x”可以為A-E,也就是說這個(gè)寄存器說明適用于GPIOA丰捷、GPIOB

至GPIOE坯墨,這些GPIO端口都有這樣的一個(gè)寄存器。

 〔⊥②偏移地址

  偏移地址是指本寄存器相對于這個(gè)外設(shè)的基地址的偏移捣染。本寄存器的偏移地址是0x18,從參考手冊中我們可以查到GPIOA 外設(shè)的基地址為0x4001

0800 停巷,我們就可以算出GPIOA的這個(gè)GPIOA_BSRR 寄存器的地址為:0x4001 0800+0x18 ;同理耍攘,由于GPIOB

的外設(shè)基地址為0x4001 0C00榕栏,可算出GPIOB_BSRR 寄存器的地址為:0x4001 0C00+0x18 。其他GPIO端口以此類推即可蕾各。

 “谴拧③寄存器位表

  緊接著的是本寄存器的位表,表中列出它的0-31 位的名稱及權(quán)限式曲。表上方的數(shù)字為位編號妨托,中間為位名稱,最下方為讀寫權(quán)限吝羞,其中w 表示只寫兰伤,r

表示只讀,rw 表示可讀寫脆贵。本寄存器中的位權(quán)限都是w医清,所以只能寫,如果讀本寄存器卖氨,是無法保證讀取到它真正內(nèi)容的会烙。而有的寄存器位只讀,一般是用于表示STM32

外設(shè)的某種工作狀態(tài)的筒捺,由STM32硬件自動更改柏腻,程序通過讀取那些寄存器位來判斷外設(shè)的工作狀態(tài)。

 ∠悼浴④位功能說明

  位功能是寄存器說明中最重要的部分五嫂,它詳細(xì)介紹了寄存器每一個(gè)位的功能肯尺。例如本寄存器中有兩種寄存器位沃缘,分別為BRy 及BSy,其中的y

數(shù)值可以是0-15则吟,這里的0-15表示端口的引腳號槐臀,如BR0、BS0 用于控制GPIOx 的第0 個(gè)引腳氓仲,若x 表示GPIOA水慨,那就是控制GPIOA的第0

引腳,而BR1敬扛、BS1 就是控制GPIOA 第1 個(gè)引腳晰洒。

  其中BRy 引腳的說明是“0:不會對相應(yīng)的ODRx 位執(zhí)行任何操作;1:對相應(yīng)ODRx位進(jìn)行復(fù)位”。這里的“復(fù)位”是將該位設(shè)置為0

的意思啥箭,而“置位”表示將該位設(shè)置為1;說明中的ODRx 是另一個(gè)寄存器的寄存器位谍珊,我們只需要知道ODRx 位為1 的時(shí)候,對應(yīng)的引腳x 輸出高電平急侥,為0

的時(shí)候?qū)?yīng)的引腳輸出低電平即可(感興趣的讀者可以查詢該寄存器GPIOx_ODR 的說明了解)抬驴。所以炼七,如果對BR0 寫入“1”的話,那么GPIOx 的第0

個(gè)引腳就會輸出“低電平”布持,但是對BR0 寫入“0”的話,卻不會影響ODR0 位陕悬,所以引

  腳電平不會改變题暖。要想該引腳輸出“高電平”,就需要對“BS0”位寫入“1”捉超,寄存器位BSy 與BRy 是相反的操作胧卤。

  C 語言對寄存器的封裝

  1. 封裝總線和外設(shè)基地址

  在編程上為了方便理解和記憶,我們把總線基地址和外設(shè)基地址都以相應(yīng)的宏定義起來拼岳,總線或者外設(shè)都以他們的名字作為宏名枝誊。

  首先定義了 “片上外設(shè)”基地址PERIPH_BASE,接著在PERIPH_BASE 上加入各個(gè)總線的地址偏移惜纸, 得到APB1 叶撒、APB2

總線的地址APB1PERIPH_BASE

、APB2PERIPH_BASE耐版,在其之上加入外設(shè)地址的偏移祠够,得到GPIOA-G的外設(shè)地址,最后在外設(shè)地址上加入各寄存器的地址偏移粪牲,得到特定寄存器的地址古瓤。一旦有了具體地址,就可以用指針讀寫腺阳。

  該代碼使用 (unsigned int *) 把GPIOB_BSRR

宏的數(shù)值強(qiáng)制轉(zhuǎn)換成了地址落君,然后再用“*”號做取指針操作,對該地址的賦值亭引,從而實(shí)現(xiàn)了寫寄存器的功能绎速。同樣,讀寄存器也是用取指針操作痛侍,把寄存器中的數(shù)據(jù)取到變量里朝氓,從而獲取STM32

外設(shè)的狀態(tài)。

  2. 封裝寄存器列表

  用上面的方法去定義地址主届,還是稍顯繁瑣赵哲,例如GPIOA-GPIOE

都各有一組功能相同的寄存器,如GPIOA_ODR/GPIOB_ODR/GPIOC_ODR

等等君丁,它們只是地址不一樣枫夺,但卻要為每個(gè)寄存器都定義它的地址。為了更方便地訪問寄存器绘闷,我們引入C 語言中的結(jié)構(gòu)體語法對寄存器進(jìn)行封裝橡庞。

  這段代碼用typedef 關(guān)鍵字聲明了名為GPIO_TypeDef 的結(jié)構(gòu)體類型较坛,結(jié)構(gòu)體內(nèi)有7 個(gè)成員變量,變量名正好對應(yīng)寄存器的名字扒最。C

語言的語法規(guī)定丑勤,結(jié)構(gòu)體內(nèi)變量的存儲空間是連續(xù)的,其中32 位的變量占用4 個(gè)字節(jié)吧趣,16 位的變量占用2 個(gè)字節(jié)法竞。

  也就是說,我們定義的這個(gè)GPIO_TypeDef 强挫,假如這個(gè)結(jié)構(gòu)體的首地址為0x40010C00(這也是第一個(gè)成員變量CRL 的地址)岔霸,

那么結(jié)構(gòu)體中第二個(gè)成員變量CRH 的地址即為0x4001 0C00 +0x04 ,加上的這個(gè)0x04 俯渤,正是代表CRL 所占用的4

個(gè)字節(jié)地址的偏移量呆细,其它成員變量相對于結(jié)構(gòu)體首地址的偏移,在上述代碼右側(cè)注釋已給八匠。

  這樣的地址偏移與STM32 GPIO

外設(shè)定義的寄存器地址偏移一一對應(yīng)絮爷,只要給結(jié)構(gòu)體設(shè)置好首地址,就能把結(jié)構(gòu)體內(nèi)成員的地址確定下來臀叙,然后就能以結(jié)構(gòu)體的形式訪問寄存器略水。

  這段代碼先用GPIO_TypeDef 類型定義一個(gè)結(jié)構(gòu)體指針GPIOx,并讓指針指向地址GPIOB_BASE(0x4001

0C00)劝萤,使用地址確定下來渊涝,然后根據(jù)C 語言訪問結(jié)構(gòu)體的語法,用GPIOx->ODR 及GPIOx->IDR 等方式讀寫寄存器床嫌。

  最后跨释,我們更進(jìn)一步,直接使用宏定義好GPIO_TypeDef

類型的指針厌处,而且指針指向各個(gè)GPIO端口的首地址鳖谈,使用時(shí)我們直接用該宏訪問寄存器即可。

  這里我們僅是以GPIO 這個(gè)外設(shè)為例阔涉,給大家講解了C

語言對寄存器的封裝缆娃。以此類推,其他外設(shè)也同樣可以用這種方法來封裝瑰排。好消息是贯要,這部分工作都由固件庫幫我們完成了,這里我們只是分析了下這個(gè)封裝的過程椭住,讓大家知其然崇渗,也只其所以然。

stm32視頻學(xué)習(xí)資料

STM32可以這樣玩

http://www.makeru.com.cn/live/4034_1460.html?s=45051

分析STM32的的開發(fā)方式

http://www.makeru.com.cn/live/3523_1673.html?s=45051

釋放潛能:學(xué)習(xí)效率提升、編程能力提升

http://www.makeru.com.cn/live/3507_1276.html?s=45051

從單片機(jī)到嵌入式linux我們需要做什么

http://www.makeru.com.cn/live/5413_1994.html?s=45051

stm32 如何用DMA搬運(yùn)數(shù)據(jù)

http://www.makeru.com.cn/live/detail/1484.html?s=45051

(STM32中斷系統(tǒng))

http://www.makeru.com.cn/live/1392_1124.html?s=45051

pdf以及相關(guān)文檔下載群:830802928

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宅广,一起剝皮案震驚了整個(gè)濱河市葫掉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌跟狱,老刑警劉巖俭厚,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異驶臊,居然都是意外死亡套腹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門资铡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人幢码,你說我怎么就攤上這事笤休。” “怎么了症副?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵店雅,是天一觀的道長。 經(jīng)常有香客問我贞铣,道長闹啦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任辕坝,我火速辦了婚禮窍奋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酱畅。我一直安慰自己琳袄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布纺酸。 她就那樣靜靜地躺著窖逗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪餐蔬。 梳的紋絲不亂的頭發(fā)上碎紊,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天,我揣著相機(jī)與錄音樊诺,去河邊找鬼仗考。 笑死,一個(gè)胖子當(dāng)著我的面吹牛啄骇,可吹牛的內(nèi)容都是我干的痴鳄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼缸夹,長吁一口氣:“原來是場噩夢啊……” “哼痪寻!你這毒婦竟也來了螺句?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤橡类,失蹤者是張志新(化名)和其女友劉穎蛇尚,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顾画,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡取劫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了研侣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谱邪。...
    茶點(diǎn)故事閱讀 40,567評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖庶诡,靈堂內(nèi)的尸體忽然破棺而出惦银,到底是詐尸還是另有隱情,我是刑警寧澤末誓,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布扯俱,位于F島的核電站,受9級特大地震影響喇澡,放射性物質(zhì)發(fā)生泄漏迅栅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一晴玖、第九天 我趴在偏房一處隱蔽的房頂上張望读存。 院中可真熱鬧,春花似錦窜醉、人聲如沸宪萄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拜英。三九已至,卻和暖如春琅催,著一層夾襖步出監(jiān)牢的瞬間居凶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工藤抡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侠碧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓缠黍,卻偏偏與公主長得像弄兜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容