几个操作寄存器常用的宏

本文地址: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)  

 

posted @ 2021-02-07 15:11  jqdy  阅读(1319)  评论(0编辑  收藏  举报