stm32位操作詳解
STM32位操作原理
思想:把一個比特分成32位,每位都分配一個地址,這樣就有32個地址,通過地址直接訪問。
位操作基礎
位運算
位運算的運算分量只能是整型或字符型數據,位運算把運算對象看作是由二進位組成的位串信息,按位完成指定的運算,得到位串信息的結果。
位運算
&(按位與)、|(按位或)、^(按位異或)、~ (按位取反)。
其中,按位取反運算符是單目運算符,其余均為雙目運算符。
位運算符的優先級從高到低,依次為~、&、^、|,
其中~的結合方向自右至左,且優先級高於算術運算符,其余運算符的結合方向都是自左至右,且優先級低於關系運算符。
(1)按位與運算符(&) 按位與運算將兩個運算分量的對應位按位遵照以下規則進行計算: 0 & 0 = 0, 0 & 1 = 0, 1 & 0 = 0, 1 & 1 = 1。 即同為 1 的位,結果為 1,否則結果為 0。 例如,設3的內部表示為 00000011 5的內部表示為 00000101 則3&5的結果為 00000001 按位與運算有兩種典型用法,一是取一個位串信息的某幾位,如以下代碼截取x的最低7位:x & 0177。二是讓某變量保留某幾位,其余位置0,如以下代碼讓x只保留最低6位:x = x & 077。以上用法都先要設計好一個常數,該常數只有需要的位是1,不需要的位是0。用它與指定的位串信息按位與。 (2)按位或運算符(|) 按位或運算將兩個運算分量的對應位按位遵照以下規則進行計算: 0 | 0 = 0, 0 | 1 = 1, 1 | 0 = 1, 1 | 1 = 1 即只要有1個是1的位,結果為1,否則為0。 例如,023 | 035 結果為037。 按位或運算的典型用法是將一個位串信息的某幾位置成1。如將要獲得最右4為1,其他位與變量j的其他位相同,可用邏輯或運算017|j。若要把這結果賦給變量j,可寫成: j = 017|j (3)按位異或運算符(^) 按位異或運算將兩個運算分量的對應位按位遵照以下規則進行計算: 0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0 即相應位的值相同的,結果為 0,不相同的結果為 1。 例如,013^035結果為026。 異或運算的意思是求兩個運算分量相應位值是否相異,相異的為1,相同的為0。按位異或運算的典型用法是求一個位串信息的某幾位信息的反。如欲求整型變量j的最右4位信息的反,用邏輯異或運算017^j,就能求得j最右4位的信息的反,即原來為1的位,結果是0,原來為0的位,結果是1。 (4)按位取反運算符(~) 按位取反運算是單目運算,用來求一個位串信息按位的反,即哪些為0的位,結果是1,而哪些為1的位,結果是0。例如, ~7的結果為0xfff8。 取反運算常用來生成與系統實現無關的常數。如要將變量x最低6位置成0,其余位不變,可用代碼x = x & ~077實現。以上代碼與整數x用2個字節還是用4個字節實現無關。 當兩個長度不同的數據進行位運算時(例如long型數據與int型數據),將兩個運算分量的右端對齊進行位運算。如果短的數為正數,高位用0補滿;如果短的數為負數,高位用1補滿。如果短的為無符號整數,則高位總是用0補滿。 位運算用來對位串信息進行運算,得到位串信息結果。如以下代碼能取下整型變量k的位串信息的最右邊為1的信息位:((k-1)^k) & k。
移位運算
移位運算用來將整型或字符型數據作為二進位信息串作整體移動。有兩個運算符: << (左移) 和 >> (右移) 移位運算是雙目運算,有兩個運算分量,左分量為移位數據對象,右分量的值為移位位數。移位運算將左運算分量視作由二進位組成的位串信息,對其作向左或向右移位,得到新的位串信息。 移位運算符的優先級低於算術運算符,高於關系運算符,它們的結合方向是自左至右。 (1)左移運算符(<<) 左移運算將一個位串信息向左移指定的位,右端空出的位用0補充。例如014<<2,結果為060,即48。 左移時,空出的右端用0補充,左端移出的位的信息就被丟棄。在二進制數運算中,在信息沒有因移動而丟失的情況下,每左移1位相當於乘2。如4 << 2,結果為16。 (2)右移運算符(>>) 右移運算將一個位串信息向右移指定的位,右端移出的位的信息被丟棄。例如12>>2,結果為3。與左移相反,對於小整數,每右移1位,相當於除以2。在右移時,需要注意符號位問題。對無符號數據,右移時,左端空出的位用0補充。對於帶符號的數據,如果移位前符號位為0(正數),則左端也是用0補充;如果移位前符號位為1(負數),則左端用0或用1補充,取決於計算機系統。對於負數右移,稱用0 補充的系統為“邏輯右移”,用1補充的系統為“算術右移”。以下代碼能說明讀者上機的系統所采用的右移方法: printf("%d\n\n\n", -2>>4); 若輸出結果為-1,是采用算術右移;輸出結果為一個大整數,則為邏輯右移。 移位運算與位運算結合能實現許多與位串運算有關的復雜計算。設變量的位自右至左順序編號,自0位至15位,有關指定位的表達式是不超過15的正整數。以下各代碼分別有它們右邊注釋所示的意義: ~(~0 << n) (x >> (1 p-n)) & ~(~0 << n) new |= ((old >> row) & 1) << (15 – k) s &= ~(1 << j) for(j = 0; ((1 << j) & s) == 0; j ) ;
STM32地址映射關系及使用
地址映射關系
每個比特分成32個位,對應32個地址,之間映射關系,要不然我們怎么知道訪問哪個地址,當然有公式可以計算出來,但是stm32已經幫我們封裝好了映射關系,我們可以直接使用。
映射關系定義在sys.h文件下。
#ifndef __SYS_H #define __SYS_H #include "stm32f10x.h" //0,不支持ucos //1,支持ucos #define SYSTEM_SUPPORT_OS 0 //定義系統文件夾是否支持UCOS //位帶操作,實現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 WFI_SET(void); //執行WFI指令 void INTX_DISABLE(void);//關閉所有中斷 void INTX_ENABLE(void); //開啟所有中斷 void MSR_MSP(u32 addr); //設置堆棧地址 #endif
使用
1.定義
這里我們以LED0與LED1為例。
LED0的io口為PB5
LED的io口為PE5
我們需要設置IO口輸出。選擇對應GPIO組,然后傳入引腳號。
PBout(5)
PEout(5)
#define LED0 PBout(5)// PB5 #define LED1 PEout(5)// PE5
2.使用
LED0=1; LED1=0;