本文地址:https://www.cnblogs.com/jqdy/p/14385295.html
操作寄存器時經常用到令某位等於零或者等於一,還有令連續的幾位等於某個值,等等這樣的操作。
按照一般的做法,比如讓某個寄存器的 B1 位等於一時,會“或”上0x02,每次總是反復確認是否正確;換成和(1<<1)進行“或”操作后,雖然簡單明了保證不出錯了,但是左移一位到底代表什么,時間長了還得去查手冊。
因此,編了幾個宏替代上述操作,簡單明了,又不會出錯:
1. 讓某個寄存器的其中一位等於1
寄存器的8個位 B7 ~ B0, 其中,__M__表示 BX中的X,恰好和手冊中寄存器位定義表表頭中的次序一樣。
為了進一步提高位操作的可讀性,將寄存器的各個位的次序也進行宏定義。
1 /*將寄存器 REGISTER 的 M 位 置1。M 取值 0 ~ 7*/ 2 #define SET_BIT(__REGISTER__, __M__) do{__REGISTER__ |= (1 << __M__);}while(0) 3 4 //本宏的意思,就是將I2CCFG寄存器的 B7 位 ENI2C 置 1,顧名思義就是將I2CCFG寄存器中的I2C使能位置位 5 SET_BIT(I2CCFG, ENI2C_BIT);
寄存器位次序宏定義片段:
1 // S4CON(84H) 2 #define S4SM0_BIT 7 3 #define S4ST4_BIT 6 4 #define S4SM2_BIT 5 5 #define S4REN_BIT 4 6 #define S4TB8_BIT 3 7 #define S4RB3_BIT 2 8 #define S4TI_BIT 1 9 #define S4RI_BIT 0
2. 讓某個寄存器的其中一位等於 0
1 /*將寄存器 REGISTER 的 M 位清零。M 取值 0 ~ 7*/ 2 #define CLEAR_BIT(__REGISTER__, __M__) do{__REGISTER__ &= (~(1 << __M__));}while(0)
3. 單獨取出某寄存器中的一位的值
1 /*將寄存器 REGISTER 的 M 位取出。M 取值 0 ~ 7*/ 2 #define GET_BIT(__REGISTER__, __M__) (__REGISTER__ & (1 << __M__))
4. 將寄存器中連續幾位清零
/*將寄存器 REGISTER 從 M 位到 N 位清零。M 和 N 取值 0 ~ 7,且 M > N*/ #define CLEAR_BITS(__REGISTER__, __M__, __N__)\
do{\
__REGISTER__ &= (~((0xffU >> (7 - __M__ + __N__)) << __N__));\
}while(0)
以將B5~B3連續3位清零為例,說明該宏的思路:
將B5、B4、B3連續3位清零,就是把寄存器和 C7H(1100 0111B)相“與”。其中 1100 0111B 中的 B 是借用 16進制數表示法 C7H 中 H的作用,表示二進制數。
上邊的 1100 0111B = C7H = ~(0011 1000B) = ~(38H)。
到這里就出現了和單一位清零類似的局面,就是把 1 左移幾位,再取反,最后和寄存器的值相“與”,即 REGISTER &= ~(0x38)。
那么接下來的問題就是,在宏代碼中連續3個“1”怎么得到,以及左移3位怎么得到:
- 得到連續 3 個 1:將連續8個1,即 0xff 右移 5 次,就得到了 “111”,即:5 = 8 - 5 + 3 - 1 = (8 - 1) - 5 + 3 = 7 - 5 + 3。這樣,宏表達式中的 7 - __M__ + __N__ 就代表着將 0xff 右移 5 次。
- 左移3位:很簡單,這里的 3 就是 B3 的次序號。
完整表達下來就是:CLEAR_BITS(P1M1, 5, 3),這里的 REGISTER 是 P1M1 這個寄存器。
對於8位單片機,表達式中使用0xff,對於16、32位單片機,換成0xffff、0xffffffff。
5. 將寄存器中的連續幾位賦新值
/*將寄存器 REGISTER 從 M 位到 N 位賦值為 NEW。M 和 N 取值 0 ~ 7,且 M > N*/ #define LET_BITS(__REGISTER__, __M__, __N__, __NEW__)\
do{\
CLEAR_BITS(__REGISTER__, __M__, __N__);\
__REGISTER__ |= (__NEW__ << __N__);\
}while(0)
將寄存器中的連續幾個位賦值,要分成兩步走,首先需將這幾位清零,然后再將新值左移適當的次數后,再與寄存器的值相“或”即可。
還用上面哪個例子,將 B5 ~ B3 連續3位賦值為 101 (0x05):
- 將 B5~B3位清零:借用 “4.將寄存器中連續幾位清零”一節中的 CLEAR_BITS(P1M1, 5, 3)即可
- 將新值101(0x05)左移3位(3即為B3的次序號),再和寄存器的值相“或”:P1M1 |= (0x05 << 3),這就是宏定義中的 __REGISTER__ |= (__NEW__ << __N__)
整體效果是這樣的:LET_BITS(P1M1, 5, 3, 0x05)。
另外,還有一個宏是令寄存器的連續幾位都等於1,不過不太常用:
/*將寄存器 REGISTER 從 M 位到 N 位置位。M 和 N 取值 0 ~ 7,且 M > N*/ #define SET_BITS(__REGISTER__,__M__,__N__)\ do{\ __REGISTER__|=((0xffU>>(7-__M__+__N__))<<__N__);\ }while(0)