几个操作寄存器常用的宏
本文地址: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)