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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

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

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

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

stm32編程實質上是修改寄存器的32位的具體的值

單片機

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

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

STM32

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

什么是寄存器?

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

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

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

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

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

補充:32位cpu代表了什么,stm32也是32位

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

敲黑板:stm32的寄存器是32位的,都是存儲8位16進制的數或者32位2進制的01數字。

什么是地址映射?

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

如果某地址對應著某寄存器,我們就可以運用C語言的指針來尋址并修改這個地址上的內容,從而實現修改該寄存器的內容。

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

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

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

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

2^10 = 1024 = 1Kb

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

2^32 = 1G x 4= 4G

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

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

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

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

學習stm32最困難的地方,就是理解功能對應的寄存器的邏輯關系,甚至一個簡單的功能往往是多個寄存器的調用的結果,理解寄存器之間的關系,學會查看寄存器的值。

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

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

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

ABP2掛載加外設基地址,地址為外設基地址+ABP2偏移量

源碼中可以找到:

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

#define PERIPH_BASE ((uint32_t)0x40000000)

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

#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

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

#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)

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

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

關于寄存器的都說了,怎么查寄存器的地址呢?

上面說了利用參考手冊找,參考手冊網盤鏈接在文末

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

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

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

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

總結:PB3的輸入數據位于0x4001 0C08這個地址上,這個地址上所存放數據的右起第4個位就是PB3引腳 對應 的高低電平

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

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

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

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

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

直接操作寄存器來點亮LED。

我的板子對應的LED是PB8。首先要配置時鐘使能。

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

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

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

下圖系統結構可以看到時鐘的從屬關系,此圖位于手冊P25頁,十分重要。可以看出AHB總線包含RCC時鐘控制,GPIO是屬于APB2的。

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

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

可以在6.3.7小節找到APB2外設時鐘使能寄存器(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。下面我們來尋找這個寄存器的地址。

因為是PB8所以要配置對應的:CNF8和MODE8

關于此寄存器的說明位于8.2.2小節。先看標題GPIOx,表示PA,PB,PC直到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。點亮LED需要輸出低電平

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

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

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

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

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函數開始執行。

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

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

參考手冊第10版:

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。