STM32暫存器的簡介 位址查詢,與直接操作暫存器

2021-10-09 10:57:17 字數 3362 閱讀 9805

手冊中沒有直接給出所有的暫存器的位址,需要讀者稍加計算。stm32給不同的暫存器分配了不同的位址,有點像劃分了片區。在《stm32中文參考手冊_v10》的第28頁,有不同暫存器的位址範圍。

現在,假如我們想讀取pb3引腳的電平,該怎麼找到相關的暫存器?

第一步,找到gpiob的基位址

也就是找到gpiob的小區。結論是,所有gpiob相關的暫存器,都住在0x4001 0c00到0x4001 0fff範圍內。

第二步,找到埠輸入暫存器的位址偏移

找到儲存資料的那個屋子,結論是0x4001 0c00+8 = 0x4001 0c08

第三步,找到知道資料的那個人

pb3的資料位於從右往左數第4個。

而這個暫存器的位數是32位(雖然高16位沒有用到),這就是32位的微控制器的意思。每個暫存器都佔據4位元組,32位。而cpu的匯流排一次可以操作32位,所以比8位微控制器厲害一點。

經過這三步查詢,我們可以做出以下結論:

pb3的輸入資料位於0x4001 0c08這個位址上,這個位址上存放資料的右起第4個位就是pb3引腳對應的高低電平。

unsigned int *pgpiob_idr = (unsigned int *)0x40010c08;

unsigned char pb3 = *pgpiob_idr & 0x8;//取出從右往左數的第4位

直接訪問的操作並不好用,每操作乙個暫存器就必須去檢視資料手冊,然後找找這個暫存器的位址。

意法半導體公司為了方便大家使用,就把這些暫存器都起了一目了然的名字,把暫存器與位址對映關係放在他們提供的標頭檔案裡。這個檔案就是stm32f10x.h。

我的板子對應的led是pb8。

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

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

由於stm32的每個io都需要4個位來配置,所以乙個32位的暫存器最大只能配置8個io(32位的微控制器的暫存器就是32位的)。stm32中,用埠配置低暫存器(gpiox_crl)來配置引腳px0-px7, 用埠配置高暫存器(gpiox_crh)來配置引腳px8-px15。

配置引腳pb8,使用的暫存器是gpiob_crh。下面我們來尋找這個暫存器的位址。

關於此暫存器的說明位於8.2.2小節。先看標題gpiox,表示不管是pa,pb還是pe,都能用。

偏移位址是0x04,意思是在基位址的基礎上再加0x04,所以,對於gpiob來說就是0x4001 0c04。如果配置pb0-pb7,那麼需要的暫存器是低位的暫存器gpiob_crl,它的位址是0x4001 0c00。我們需要配置的暫存器是gpiob_crh。

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

復位值是0x4444 4444,並不是0x0000 0000。所謂的復位值,就是指如果沒有操作這個暫存器時,暫存器存放的預設值。復位值按位拆分0x4 = 0b0100,0x表示16進製制,0b表示二進位制,也就是預設cnf 01,mode 00,是浮空輸入。

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

推挽輸出:可以輸出高,低電平,連線數字器件;推挽結構一般是指兩個三極體分別受兩互補訊號的控制,總是在乙個三極體導通的時候另乙個截止。

開漏輸出:輸出端相當於三極體的集電極,要得到高電平狀態需要上拉電阻才行,適合於做電流型的驅動,其吸收電流的能力相對強(一般20ma以內)。

開漏是需要外接上拉電阻才可以輸出高電平的,這裡並不適合。所以需要設定為推挽輸出。

功能是否是復用呢?復用的意思是有別的功能在這個腳上,比如usb,can,串列埠等,所以這些個腳就可能有多個功能。暫時講多了反而會迷惑,等用到了這些功能再講解,我直接告訴大家,pb8沒有復用。

所以配置為輸出模式,通用推挽輸出。速度暫時不關注,隨便填寫乙個50mhz吧,其它速度當然也可以。所以設定gpiob_crh的mode8與cnf8為0b0011,即0x3。此暫存器中其它的位暫時不做修改,使用預設值,也就是gpiob_crh設定為:0x4444 4443。

在微控制器的程式設計中,要想做某件事,必須尋找相應的暫存器。在8.2.4小節,可以找到埠輸出資料暫存器,就是我們需要的。我們需要輸出0。但是中文手冊有乙個小小的bug,0x0c寫成了0ch,可以參考英文原版。得知位址的偏移是0x0c,所以這個資料暫存器的位址就是0x4001 0c0c,把第8位寫為0就行。預設就是0,但是也得學一下怎麼寫,萬一是高電平點亮呢。

在搞清楚我們要用的幾個暫存器的位址,以及暫存器中需要裝填的數值以後,現在用乙個簡單粗暴的方法來操作這些暫存器——直接操作。(注意,這段**不是實用的**,只是為了寫出乙個最簡單的led,有些部分是不可取的。)將main函式修改為:

int main(void)

c語言總是從main函式開始執行。

定義幾個指標,指向剛剛看到的位址。對於編譯器來說,它並不知道0x40021018代表的是資料還是指標,所以用(unsigned int *)作強制的型別轉換,告訴編譯器0x40021018是個指標。指標可以理解為位址。操作指標,把這些位址存放的值修改。

最後的return,代表main函式結束。

我們寫了一段另類的**,直接操作暫存器的位址,就是想得到這麼乙個結論:不論**怎麼寫,不論是暫存器,庫函式,還是其他的作業系統,要在stm32f103這個微控制器點亮led燈,肯定需要把時鐘和gpio這幾個相關的特殊位址,進行賦值或修改數值的操作。有點像打籃球,不論進攻時有怎樣花哨的運球與傳切配合,最後都要完成把球放入籃筐的動作,才能得分。

STM32暫存器的簡介 位址查詢,與直接操作暫存器

手冊中沒有直接給出所有的暫存器的位址,需要讀者稍加計算。stm32給不同的暫存器分配了不同的位址,有點像劃分了片區。在 stm32中文參考手冊 v10 的第28頁,有不同暫存器的位址範圍。現在,假如我們想讀取pb3引腳的電平,該怎麼找到相關的暫存器?第一步,找到gpiob的基位址 也就是找到gpio...

筆記 STM32暫存器位址對映

例如 struct student p p可以指向struct student 型別的變數或陣列元素 例題 main stu1 pstu stu1 讀取結構體成員的值 printf s的學號是 d,年齡是 d,在 c組,今年的成績是 1f!n pstu name,pstu num,pstu age,...

STM32蜂鳴器 暫存器

這次實驗犯了個笑話,竟然在巨集定義後面加分號.就像這樣 define 大家千萬不要學我,結果報錯expected expression,還苦惱半天,想為啥操作不了暫存器了?我真愚蠢!剛開始我也不會寫這些東西,其實摸清套路就好,rcc時鐘使能 gpio初始化 相關暫存器初始化 延時函式 串列埠等初始化...