位帶操作在stm32中的C語言實(shí)現(xiàn)
#define BITBAND(addr,bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) << 5) + (bitnum << 2))
對(duì)上句程序的解釋:
利用宏定義的方式將位帶地址的映射表示出來,該函數(shù)有兩個(gè)參數(shù)addr和bitnum,分別是原本的地址和在數(shù)據(jù)中的第幾位。我們知道兩個(gè)公式如下:
0x2000_0000‐0x200F_FFFF地址空間:AliasAddr = 0x22000000 + (A – 0x20000000)*32 + n*4
0x4000_0000‐0x400F_FFFF地址空間:AliasAddr = 0x42000000 + (A – 0x40000000)*32 + n*4
仔細(xì)觀察我們可以發(fā)現(xiàn),是有規(guī)律可尋的。兩個(gè)公式的基地址一個(gè)是0x22000000,一個(gè)是0x42000000,他們只是最高位不一樣,這個(gè)最高位和最原始的地址的最高位是一致的。所以我們通過 (addr & 0xF0000000) 來取最高位,再加上0x2000000就得到了公式中的基地址。我們知道兩個(gè)地址空間中地址的變換只是在低5位上,比如0x2000_0000 — 0x200F_FFFF(有5個(gè)F),利用(A – 0x20000000)的目的是得到地址addr和0x2000_0000之間的偏移,也就是低5位的內(nèi)容,所以我們通過 (addr & 0xFFFFF)得到了低5位的數(shù)據(jù),也即是偏移量。公式中的乘以32,我們使用效率更高的左移5位,同理,之后的乘以4也是通過移位操作來實(shí)現(xiàn)的。
然后我們需要將上述地址轉(zhuǎn)換為一個(gè)指針,也就是,我們要告訴編譯器這是一個(gè)地址。
#define MEM_ADDR(addr) *((volatile unsigned long *) (addr))
其中使用到的volatile這個(gè)關(guān)鍵字是為了防止編譯器進(jìn)行優(yōu)化。這是必須的。
完成上述兩步之后,我們就可以使用位帶操作了,比如我們要對(duì)GPIOA中的1管腳進(jìn)行輸出控制,我們需要控制GPIOA的ODR寄存器,通過手冊(cè)我們知道它的地址是(GPIOA_BASE + 0x0C),所以我們定義:
#define GPIOA_ODR_Addr (GPIOA_BASE + 0x0C)
#define GPIOA(BitNum) MEM_ADDR( BITBAND(GPIOA_ODR_Addr,BitNum))
將GPIOA的1管腳置高,就可以這樣寫:
GPIOA(1) = 1;
同理,我們可以得到其他管腳控制的方法,或者獲取其他管腳的輸入。
以上,就是我對(duì)stm32的位帶操作的實(shí)現(xiàn)的理解,有什么理解不到位的地方,請(qǐng)大家指證,希望和大家多多交流。
評(píng)論