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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

crh寄存器_STM32 学习笔记(寄存器)---2

發(fā)布時間:2023/12/14 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 crh寄存器_STM32 学习笔记(寄存器)---2 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

故事很多,我打算用一輩子來跟你講,你準(zhǔn)備好了嗎?(狗頭

沒必要一次看完,多看幾遍消化消化。

所有操作,最終目的都是操作寄存器

stm32編程實(shí)質(zhì)上是修改寄存器的32位的具體的值

單片機(jī)

sfr P0=0x80; //關(guān)鍵字sfr 聲明地址和名稱的映射

P0=0x00; //將0x00賦值給P0口的8位(51單片機(jī)一組IO為8位)

STM32

GPIOA->ODR=0x00000000 //為GPIOA的ODR寄存器地址賦值0x00000000

什么是寄存器?

寄存器是中央處理器內(nèi)的組成部分,它可以從其他寄存器,或者內(nèi)存中獲取指令,地址,數(shù)據(jù)然后給CPU用,有時候 由于內(nèi)存太慢,內(nèi)存和寄存器之間要加一個叫Cache的東西,為了彌補(bǔ)內(nèi)存的不足,內(nèi)存-》Cache-》寄存器-》CPU。

指令、地址寄存器與數(shù)據(jù)寄存器都類似,里邊存放的都是0和1,畢竟單片機(jī)也只認(rèn)識機(jī)器碼,機(jī)器碼都是0或1,只是特別的規(guī)定下,數(shù)據(jù)寄存器里面存放的0和1表示數(shù)據(jù),指令寄存器里存放的表示指令。

既然有不同的寄存器,那CPU怎么去區(qū)分這些寄存器?

---通過地址,STM32給不同的寄存器分配了不同的地址。

怎么找到某個寄存器的地址?---查看數(shù)據(jù)手冊

補(bǔ)充:32位cpu代表了什么,stm32也是32位

代表的是數(shù)據(jù)總線32位,也就是說cpu一次可以處理32位數(shù)據(jù),而上面我們說了,cpu要從寄存器取數(shù)據(jù),所以它寄存器也是32位的,所以32位代表什么?代表它的寄存器是32位的。

敲黑板:stm32的寄存器是32位的,都是存儲8位16進(jìn)制的數(shù)或者32位2進(jìn)制的01數(shù)字。

什么是地址映射?

所謂地址映射,就是將芯片上的寄存器 甚至I/O等資源與地址建立一一對應(yīng)的關(guān)系。

如果某地址對應(yīng)著某寄存器,我們就可以運(yùn)用C語言的指針來尋址并修改這個地址上的內(nèi)容,從而實(shí)現(xiàn)修改該寄存器的內(nèi)容。

所以我們能操作IO資源(如引腳)的根本原因是,這些引腳由于地址映射與地址建立了對應(yīng)關(guān)系,而 部分地址 又和 寄存器建立了對應(yīng)關(guān)系,所以,我們說操作某些資源就是操作某些寄存器應(yīng)該不難理解了

IO資源---地址---寄存器

正是因?yàn)轭^文件中有了對于各種 寄存器 和 I/O端口 的地址映射,我們才可以在51單片機(jī)程序中方便地使用P2^0 =0xFF; TMOD =0xFF等賦值句子對寄存器進(jìn)行配置,從而控制單片機(jī)。

我們可以看出地址才最重要的紐帶,那么我們怎么去訪問地址,能訪問多少?怎么抽象出地址這一概念的?是不是得有一些東西支撐?這個東西就是地址總線。cpu通過地址總線訪問地址,我們操作地址當(dāng)然也是通過地址總線啦,因?yàn)槲覀儾僮髦鳦PU嘛(滑稽),假如一個芯片有32根地址總線,每根線有兩種狀態(tài)(0/1)所以32根能表示2^32個狀態(tài),一個狀態(tài)代表一個地址,所以這一共有4G的地址能表示(訪問)。

2^10 = 1024 = 1Kb

2^30 = 1024x1024x1024= 1024*(1024*1kb) = 1024Mb = 1G

2^32 = 1G x 4= 4G

APB2總線就是指特定的一段地址,如:0x4001 0000—XXXX

然后官方書上有段話,大致意思:你能理解這句話的深刻含義嗎?

程序存儲器、數(shù)據(jù)存儲器、寄存器和輸入輸出端口 被 組織在同一個4GB的線性地址空間內(nèi)。

說到映射大家可能就會想到函數(shù)映射,腦海里會有一個畫面:左邊一個集合中的某個元素“射”出一條帶箭頭的直線指向右邊的集合的某個元素。如果你高數(shù)或離散數(shù)學(xué)再好一點(diǎn)兒的話會想到單射、雙射、滿射、恒等映射(你要是這個都想到了,那你牛B!)……其實(shí)外圍設(shè)備的內(nèi)存映射原理是一樣的,只不過左邊的集體變成了CPU,右邊的集合變成了外圍設(shè)備,那條帶箭頭的線就是連接CPU和外設(shè)地址引腳的地址總線。

學(xué)習(xí)stm32最困難的地方,就是理解功能對應(yīng)的寄存器的邏輯關(guān)系,甚至一個簡單的功能往往是多個寄存器的調(diào)用的結(jié)果,理解寄存器之間的關(guān)系,學(xué)會查看寄存器的值。

以GPIOA為例說明STM32寄存器和名稱的映射

GPIOA下的某個寄存器,掛載在GPIOA下,地址為GPIOA基地址+偏移量

GPIOA掛載在APB2總線,地址為APB2總線基地址+GPIOA偏移量

ABP2掛載加外設(shè)基地址,地址為外設(shè)基地址+ABP2偏移量

源碼中可以找到:

//外部總線基地址 8位16進(jìn)行不剛好是32位2進(jìn)制嗎?---地址總線的作用別忘了

#define PERIPH_BASE ((uint32_t)0x40000000)

//APB2基地址=外部總線基地址+偏移量

#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

//GPIOA基地址=APB2基地址+偏移量

#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)

//GPIOA將地址順序分配給7個32位寄存器(結(jié)構(gòu)體分配)

#define GPIOA ((GPIO_TypeDef*)GPIOA_BASE)

/將寄存器地址映射到7個32位寄存器,分別控制

typedef struct

{

IO unit32_t CRL;

IO unit32_t CRH;

IO unit32_t ODR;

IO unit32_t IDR;

IO unit32_t BSRR;

IO unit32_t BRR;

IO unit32_t LCKR;

}GPIO_TypeDef;

關(guān)于寄存器的都說了,怎么查寄存器的地址呢?

上面說了利用參考手冊找,參考手冊網(wǎng)盤鏈接在文末

假如你想讀取PB3引腳的電平

第一步 找到GPIOB的基地址:(以后找就來這)

第二步找到端口輸入寄存器的地址偏移(結(jié)論是0x4001 0C00+8 = 0x4001 0C08),地址偏移上面寫著 8,PB3的數(shù)據(jù)位于從右往左數(shù)第4個 即IDR3

這張圖片包含了很多信息,首先這兩行表示的是一個寄存器的內(nèi)部結(jié)構(gòu),上面一行告訴我們保留,就是放著不用,始終讀為0,而下面就是0~15個引腳位置,最下面的r的意思是只讀,不能寫

總結(jié):PB3的輸入數(shù)據(jù)位于0x4001 0C08這個地址上,這個地址上所存放數(shù)據(jù)的右起第4個位就是PB3引腳 對應(yīng) 的高低電平

我們可以簡單粗暴地直接訪問這個地址:

unsigned int *pGPIOB_IDR = (unsigned int *)0x40010C08;

unsigned char PB3 = *pGPIOB_IDR & 0x8;//取出從右往左數(shù)的第4位

直接訪問的操作并不好用,每操作一個寄存器就必須去查看數(shù)據(jù)手冊,然后找找這個寄存器的地址。

意法半導(dǎo)體公司為了方便大家使用,就把這些寄存器都起了一目了然的名字,把寄存器與地址映射關(guān)系放在他們提供的頭文件里。這個文件就是stm32f10x.h。(我們上面地址映射那段講到的知識又用到了,現(xiàn)在是讀這段話是不是覺得理所當(dāng)然,是不是知道自己再做什么?而不是無腦比著其他代碼寫)

直接操作寄存器來點(diǎn)亮LED。

我的板子對應(yīng)的LED是PB8。首先要配置時鐘使能。

為什么配置時鐘?為了省電,默認(rèn)的時鐘都是關(guān)閉的。配置STM32的任何資源前,都必須首先使能時鐘。配置哪個時鐘?

時鐘的信息在參考手冊里邊,參考手冊十分巨大,不用通讀,就像一個字典,需要什么查什么。

時鐘控制名字叫做RCC,屬于AHB總線。GPIOB屬于APB2。

下圖系統(tǒng)結(jié)構(gòu)可以看到時鐘的從屬關(guān)系,此圖位于手冊P25頁,十分重要。可以看出AHB總線包含RCC時鐘控制,GPIO是屬于APB2的。

我們已經(jīng)知道,GPIO端口B的地址從0x4001 0C00開始。接下來只尋找時鐘使能寄存器的地址:

復(fù)位和時鐘控制RCC的地址從0x4002 1000開始。

可以在6.3.7小節(jié)找到APB2外設(shè)時鐘使能寄存器(RCC_APB2ENR),偏移地址是0x18,所以APB2的地址就是0x4002 1018。

看手冊RCC_APB2ENR,位3是IOPBEN---IO端口B時鐘使能,就是我們想要的。把RCC_APB2ENR的位3賦值為1,就是開啟GPIOB時鐘。配置為通用輸出

既然叫做IO,那么肯定就是可以輸入,可以輸出,到底是輸入還是輸出呢?

控制LED需要輸出高電平或是低電平,所以需要配置為輸出。

一個STM32的IO需要4個位來配置,所以一個32位的寄存器最大只能配置8個IO。STM32中,用端口配置低寄存器(GPIOx_CRL)來配置引腳Px0-Px7, 用端口配置高寄存器(GPIOx_CRH)來配置引腳Px8-Px15。

配置引腳PB8,使用的寄存器是GPIOB_CRH。下面我們來尋找這個寄存器的地址。

因?yàn)槭荘B8所以要配置對應(yīng)的:CNF8和MODE8

關(guān)于此寄存器的說明位于8.2.2小節(jié)。先看標(biāo)題GPIOx,表示PA,PB,PC直到PE都能用。

偏移地址是0x04,意思是在基地址的基礎(chǔ)上再加0x04,所以,對于GPIOB來說就是0x4001 0c04。如果配置PB0-PB7,那么需要的寄存器是低位的寄存器GPIOB_CRL,它的地址是0x4001 0c00。我們需要配置的寄存器是GPIOB_CRH。

找到需要操作的寄存器后,把它配置為通用輸出。

復(fù)位值是0x4444 4444,并不是0x0000 0000。所謂的復(fù)位值,就是指如果沒有操作這個寄存器時,寄存器存放的默認(rèn)值。復(fù)位值按位拆分0x4 = 0b0100,0x表示16進(jìn)制,0b表示二進(jìn)制,也就是默認(rèn)CNF 01,MODE 00,是浮空輸入。

我們需要的是輸出高低電平,所以要設(shè)置為輸出。輸出模式又有好幾種輸出:

推挽輸出:可以輸出高,低電平,連接數(shù)字器件;推挽結(jié)構(gòu)一般是指兩個三極管分別受兩互補(bǔ)信號的控制,總是在一個三極管導(dǎo)通的時候另一個截止。

開漏輸出:輸出端相當(dāng)于三極管的集電極,要得到高電平狀態(tài)需要上拉電阻才行,適合于做電流型的驅(qū)動,其吸收電流的能力相對強(qiáng)(一般20ma以內(nèi))。

開漏是需要外接上拉電阻才可以輸出高電平的,這里并不適合。所以需要設(shè)置為推挽輸出。

功能是否是復(fù)用呢?復(fù)用的意思是有別的功能在這個腳上,比如USB,CAN,串口等,所以這些個腳就可能有多個功能。暫時講多了反而會迷惑,等用到了這些功能再講解,我直接告訴大家,PB8沒有復(fù)用。

所以配置為輸出模式,通用推挽輸出。速度暫時不關(guān)注,隨便填寫一個50MHz吧,其它速度當(dāng)然也可以。所以設(shè)置GPIOB_CRH的MODE8與CNF8為0b0011,即0x3。此寄存器中其它的位暫時不做修改,使用默認(rèn)值,也就是GPIOB_CRH設(shè)置為:0x4444 4443。點(diǎn)亮LED需要輸出低電平

在單片機(jī)的編程中,要想做某件事,必須尋找相應(yīng)的寄存器。

在8.2.4小節(jié),可以找到端口輸出數(shù)據(jù)寄存器(GPIOx_ODR),就是我們需要的。我們需要輸出0。但是中文手冊有一個小小的BUG,0x0C寫成了0Ch,可以參考英文原版。得知地址的偏移是0x0C,所以這個數(shù)據(jù)寄存器的地址就是0x4001 0C0C,把第8位寫為0就行。默認(rèn)就是0,但是也得學(xué)一下怎么寫,萬一是高電平點(diǎn)亮呢。

使用直接賦值的方式寫寄存器的地址

在搞清楚我們要用的幾個寄存器的地址,以及寄存器中需要裝填的數(shù)值以后,現(xiàn)在用一個簡單粗暴的方法來操作這些寄存器——直接操作。(注意,這段代碼不是實(shí)用的代碼,只是為了寫出一個最簡單的LED,有些部分是不可取的。)將main函數(shù)修改為:

int main(void)

{

unsigned int *pRCC_APB2ENR = (unsigned int *)0x40021018;

unsigned int *pGPIOB_CRH = (unsigned int *)0x40010c04;

unsigned int *pGPIOB_ODR = (unsigned int *)0x40010c0c;

*pRCC_APB2ENR = 0x00000008;

*pGPIOB_CRH = 0x44444443;

*pGPIOB_ODR = 0x00000000;

return 0;

}

C語言總是從main函數(shù)開始執(zhí)行。

定義幾個指針,指向剛剛看到的地址。對于編譯器來說,它并不知道0x40021018代表的是數(shù)據(jù)還是指針,所以用(unsigned int *)作強(qiáng)制的類型轉(zhuǎn)換,告訴編譯器0x40021018是個指針。指針可以理解為地址。操作指針,把這些地址存放的值修改。

我們寫了一段另類的代碼,直接操作寄存器的地址,就是想得到這么一個結(jié)論:不論代碼怎么寫,不論是寄存器,庫函數(shù),還是其他的操作系統(tǒng),要在STM32F103這個單片機(jī)點(diǎn)亮LED燈,肯定需要把時鐘和GPIO這幾個相關(guān)的特殊地址,進(jìn)行賦值或修改數(shù)值的操作。有點(diǎn)像打籃球,不論進(jìn)攻時有怎樣花哨的運(yùn)球與傳切配合,最后都要完成把球放入籃筐的動作,才能得分。

參考手冊第10版:

總結(jié)

以上是生活随笔為你收集整理的crh寄存器_STM32 学习笔记(寄存器)---2的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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