STM32位帶操作詳細介紹

2021-10-07 07:49:59 字數 3483 閱讀 8333

3.gpio位帶實現

//在stm32中,如果我們要使pb0埠輸出低電平,可以用如下語句

gpiob->odr |=0

<<0;

//在51微控制器中我們是這樣的

p0 =

0xff

;//匯流排操作

//還有一種方法

sbit led1 = p0^0;

led1 =0;

//位操作

在stm32中能不能實現位操作呢,當然是可以的,這種方法我們叫做位帶操作。位操作就是可以單獨的對乙個位元位讀和寫。

在stm32中,有兩個地方實現了位帶,乙個是 sram 區的最低 1mb 空間,另乙個是外設區最低 1mb 空間。這兩個 1mb 的空間除了可以像正常的 ram 一樣操作外,他們還有自己的位帶別名區,位帶別名區把這 1mb 的空間的每乙個位膨脹成乙個 32 位的字,當訪問位帶別名區的這些字時,就可以達到訪問位帶區某個位元位的目的。

例子:pb的odr暫存器位址為0x40010c0c,假設我們就操作pb0,即操作odr暫存器第0位,那麼這個位新的位址addr= =0x42000000+ (0x40010c0c-0x40000000)84 +0*4。

給這個位址命名為pbout(0);

aliasaddr= =0x42000000+ (a-0x40000000)84 +n*4

0x42000000 是外設位帶別名區的起始位址, 0x40000000 是外設位帶區的起始位址,(a-0x40000000)表示該位元前面有多少個位元組,乙個位元組有 8 位,所以8,乙個位膨脹後是 4 個位元組,所以4, n 表示該位元在 a 位址的序號,因為乙個位經膨脹後是四個位元組,所以也*4。

aliasaddr= =0x22000000+ (a-0x20000000)84 +n*4

公式分析同上

為了方便操作,我們可以把這兩個公式合併成乙個公式,把「位帶位址+位序號」轉

換成別名區位址統一成乙個巨集。

// 把「位帶位址+位序號」轉換成別名位址的巨集

2 #define bitband

(addr, bitnum)

((addr &

0xf0000000)+

0x02000000+(

(addr &

0x00ffffff

)<<5)

+(bitnum<<2)

)

addr & 0xf0000000 是為了區別 sram 還是外設,實際效果就是取出 4 或者 2,如果是外設,則取出的是 4, +0x02000000 之後就等於 0x42000000, 0x42000000 是外設別名區的起始位址。如果是 sram,則取出的是 2, +0x02000000 之後就等於 0x22000000,0x22000000 是 sram 別名區的起始位址。

addr & 0x00ffffff 遮蔽了高三位,相當於減去 0x20000000 或者 0x40000000,但是為什麼是遮蔽高三位?因為外設的最高位址是: 0x2010 0000, 跟起始位址 0x20000000 相減的時候,總是低 5 位才有效,所以乾脆就把高三位遮蔽掉來達到減去起始位址的效果,具體遮蔽掉多少位跟最高位址有關。 sram 同理分析即可。 <<5 相當於84, <<2 相當於*4,這兩個我們在上面分析過。

最後我們就可以通過指標的形式操作這些位帶別名區位址,最終實現位帶區的位元位操作。

// 把乙個位址轉換成乙個指標

#define mem_addr(addr) *((volatile unsigned long *)(addr))

// 把位帶別名區位址轉換成指標

#define bit_addr(addr, bitnum) mem_addr(bitband(addr, bitnum))

// 把「位帶位址+位序號」轉換成別名位址的巨集

#define bitband(addr, bitnum) ((addr & 0xf0000000)+0x02000000+((addr & 0x00ffffff)<<5)+(bitnum<<2))

// 把乙個位址轉換成乙個指標

#define mem_addr(addr) *((unsigned long *)(addr))

// 把位帶別名區位址轉換成指標

#define bit_addr(addr, bitnum) mem_addr(bitband(addr, bitnum))

//gpio odr 和 idr 暫存器位址對映

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

//單獨操作 gpio 的某乙個 io 口, n(0,1,2...16),n 表示具體是哪乙個 io 口

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

//輸入

這樣就可以使用pbout(0),相比之下還是很方便的。

stm32之位帶操作

stm32相對於8位微控制cpu來說實在強大的不得了,依稀記得51控制i o空的時候是 sbit led1 p0 0 然而我們在32卻沒有想 sbit 類似的關鍵字進行i o的某位進行操作。於是引入了 位帶操作的概念 什麼事位帶操作?標準的定義是 通過訪問位帶別名區來實現,即通過將每個位元位膨脹成乙...

STM32筆記(四)位帶操作介紹

位帶操作就是對可以單一的位元bit進行讀寫,在51微控制器中可以用關鍵字sbit來實現位定義,在stm32微控制器中就沒有這樣的關鍵字,取而代之的是通過訪問位帶別名區來實現位帶操作的。在 stm32 中,有兩個地方實現了位帶,乙個是sram 區的最低1mb範圍,另乙個是片內外設 區的最低 1mb 範...

STM32 Contex M的位帶操作

位帶操作的思想在30年前就已經有了,還是8051開創的先河。如今,contex m3將此能力進化,這裡的位帶操作位定址區威力大幅度增強。有兩個區中實現了位帶。其中乙個是 sram 區的最低 1mb 範圍,第二個則是片內外設區的最低 1mb 範圍。這兩個區中的位址除了可以像普通的 ram 一樣使用外,...