STM32入門:從位到位帶操作

ErHa_lodman發表於2020-12-10

位(bit)-> 位元組(byte)->字(word)

1、位(bit)
位來自英文bit(位元),常用‘b’表示
是計算的內部資料儲存的最小單位,其狀態有1與0兩種。
2、位元組(byte)
位元組來自英文byte(拜特),常用’B’表示
位元組是計算機中資料的處理基本單位,一個位元組’B’ = 8位’b’(bit)
3、字(word)
計算機進行資料處理時,一次存取、加工和傳送的資料長度稱為字(word)
一個字由若干個位元組組成,不同的計算機系統的字長是不同的,常見的有8位(1位元組)、16位(2位元組)、32位(4位元組)、64位等(8位元組),字長越長,計算機一次處理的資訊位就越多,精度就越高,字長是計算機效能的一個重要指標。目前主流微機都是32位機。

STM32暫存器的奧祕

在STM32中,每個外設暫存器含有多個對應的內部暫存器。且外設暫存器的所佔位元組個數是各個內部暫存器所佔位元組個數的總和。
舉個例子啊~
在stm32各個埠的起始地址與結束地址之間包含多個內部細分的暫存器。
在這裡插入圖片描述
其中如GPIO埠A的起始地址是:0x40010800 ,那麼要設定GPIO埠A的第1個引腳的輸出模式為推輓輸出、輸出速率為50MHZ時,就要用到GPIO暫存器中的埠配置低暫存器(GPIOA_CRL)
埠配置低暫存器(GPIOA_CRL)(x=A..E)
埠配置高暫存器(GPIOx_CRH) (x=A..E)

如上
可知埠配置低暫存器(GPIOA_CRL)的偏移地址為:0x00
可得埠配置低暫存器(GPIOA_CRL)的起始地址為:(0x40010800+0x00)

對應設定GPIO埠A的第1個引腳**的輸出模式為推輓輸出、輸出速率為50MHZ
對應程式碼:

#define GPIOA  (int)0x40010800

*((int *)(GPIOA+0X00)) = 0x44444443;

由於埠配置低暫存器(GPIOA_CRL)的復位值為0x4444 4444,因此設定時在此狀態上進行設定。

細心的小夥伴會發現,我們用8位十六進位制的數來賦值這個32位的暫存器
並且埠配置低暫存器(GPIOA_CRL)到埠配置高暫存器(GPIOx_CRH)的偏移地址偏動了4個位元組(0x00->0x04)
因此可得:
一個暫存器中由4個位元組組成,其中2位十六進位制數表示一個位元組,且一個位元組表示4位。
可參考上方復位值進行理解
在這裡插入圖片描述
在埠配置高暫存器(GPIOx_CRH) (x=A…E)中,其僅能設定前8個引腳(0 -> 7引腳),因此一個十六進位制位(4個bit位)控制一個引腳。埠配置高暫存器(GPIOx_CRH)同理

位帶操作

搞清楚了暫存器正常情況下的位的關係後,我們開搞位帶!
一個暫存器中由4個位元組組成,其中2位十六進位制數表示一個位元組,且一個位元組表示4位。
在開搞前,我們要先搞清楚他為什麼要搞位帶操作呢?
學過51微控制器的同學可能都知道,我們在設定引腳時是直接可以對引腳進行0/1設定的,例如P0_1引腳置高。

P0^1=1

很是方便,但STM32不一樣,它要通過暫存器來設定引腳,我們拿埠輸出資料暫存器(GPIOx_ODR) (x=A…E)進行討論。

埠輸出資料暫存器(GPIOx_ODR) (x=A..E)
埠輸出資料暫存器(GPIOx_ODR) (x=A…E)的復位值為0x0000 0000
之前我們說過,16進位制的中的一位代表的4個(bit)位
在埠輸出資料暫存器(GPIOx_ODR) 中一位及代表一個引腳。那麼要想設值其中一個引腳,就必須修改對應的16進位制位。相當於直接四個引腳封裝到一塊,修改時也要一起呼叫。使用起來就很麻煩。
在這裡插入圖片描述
那麼有沒有辦法讓它一對一的設定輸出呢?
那就是將每一位對應設定一個地址!

位帶操作就是對位一個位對應設定相應的地址,方便對位進行修改。
那麼如何來設定這個地址呢!要按怎樣的格式來設定呢?
不知道有沒有小夥伴看過《三體》,裡面出現過一個詞,叫量級,比如我們說的個、十、百、千、萬就是數量級的差別。而量級,則是比數量級差距更大的概念。量級之間是跳躍式的差距,且不是連續的。簡單的講,量級就是螞蟻、蘋果、西瓜、大象、大山、地球、太陽、銀河系這樣大的差別。
位帶操作就相當於提升了(bit)位的量級,將其提升到位元組。將原地址變為位帶別名地址從而得到該位相應的位帶別名地址!
現在位提升了一個量級變成位元組,那麼位元組肯定也要提升一個量級啊。位元組變成字。 沒有位帶操作之前地址碼:2位十六進位制數表示一個位元組,且一個位元組表示4位。
在這裡插入圖片描述
通過位帶操作之後:將原位地址上的一個16進位制位變為一個字,一個字下含有4個位元組,一個位元組為8位。一個字代表32位
計算方法如下:
在這裡插入圖片描述
A原地址的起始量級為位元組,在對地址進行修改都是從(bit)位開始操作。因此處理完原地址A後要×8轉換為位元位,加上n對應引腳的引腳號(0->F)。因為又多了一個字到位元組的量級跳變(一個字下含有4個位元組),因此最後整體要×4。處理後就可得出相應的位帶別名地址。

位帶操作程式為:

#include <stm32f10x.h>   
 	 
//λ´ø²Ù×÷,ʵÏÖ51ÀàËƵÄGPIO¿ØÖƹ¦ÄÜ
//¾ßÌåʵÏÖ˼Ïë,²Î¿¼<<CM3ȨÍþÖ¸ÄÏ>>µÚÎåÕÂ(87Ò³~92Ò³).
//IO¿Ú²Ù×÷ºê¶¨Òå
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO¿ÚµØÖ·Ó³Éä
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO¿Ú²Ù×÷,Ö»¶Ôµ¥Ò»µÄIO¿Ú!
//È·±£nµÄֵСÓÚ16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //輸入
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //輸出

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //輸入
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //輸出 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //輸入 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //輸出 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //輸入 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //輸出 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //輸入 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //輸出

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //輸入 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //輸出

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //輸入 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //輸出
/
void NVIC_Configuration(void);
	void Delay(u16 x);							   

相關文章