C语言按位运算符

image.png
在嵌入式编程中,常常需要对一些寄存器进行配置,有的情况下需要改变一个字节中的某一位或者几位,但是又不想改变其它位原有的值,这时就可以使用按位运算符进行操作。下面进行举例说明,假如有一个8位的TEST寄存器:
image.png
当我们要设置第0位bit0的值为1时,可能会这样进行设置:

  1. TEST = 0x01;

但是,这样设置是不够准确的,因为这时候已经同时操作到了高7位:bit1~bit7,如果这高7位没有用到的话,这么设置没有什么影响;但是,如果这7位正在被使用,结果就不是我们想要的了。
在这种情况下,我们就可以借用按位操作运算符进行配置。
对于二进制位操作来说,不管该位原来的值是0还是1,它跟0进行&运算,得到的结果都是0,而跟1进行&运算,将保持原来的值不变;不管该位原来的值是0还是1,它跟1进行|运算,得到的结果都是1,而跟0进行|运算,将保持原来的值不变。
所以,此时可以设置为:

  1. TEST = TEST | 0x01;

其意义为:TEST寄存器的高7位均不变,最低位变成1了。在实际编程中,常改写为:

  1. TEST |= 0x01;

这种写法可以一定程度上简化代码,是 C 语言常用的一种编程风格。设置寄存器的某一位还有另一种操作方法,以上的等价方法如:

  1. TEST |= (0x01 << 0);

第几位要置1就左移几位。

移位:高位丢弃,低位补0,得到新值

同样的,要给TEST的低4位清0,高4位保持不变,可以进行如下配置:

  1. TEST &= 0xF0;
  1. 把变量的某位清零

    1. //定义一个变量a = 1001 1111 b (二进制数)
    2. unsigned char a = 0x9f;
    3. //对bit2 清零
    4. a&=~(1<<2);
    5. //括号中的1左移两位,(1<<2)得二进制数:0000 0100 b
    6. //按位取反,~(1<<2)得1111 1011 b
    7. //假如a 中原来的值为二进制数: a = 1001 1111 b
    8. //所得的数与a 作”位与&”运算,a = (1001 1111 b)&(1111 1011 b)
    9. //经过运算后,a 的值 a=1001 1011 b
    10. // a 的bit2 位被被零,而其它位不变。
  2. 把变量的某几个连续位清零 ```c //若把a 中的二进制位分成2 个一组 //即bit0、bit1 为第0 组,bit2、bit3 为第1 组 // bit4、bit5 为第2 组,bit6、bit7 为第3 组 //要对第1 组的bit2、bit3 清零

a &= ~(3<<2*1);

//括号中的3左移两位,(3<<21)得二进制数:0000 1100 b //按位取反,~(3<<21)得1111 0011 b //假如a 中原来的值为二进制数: a = 1001 1111 b //所得的数与a 作”位与&”运算,a = (1001 1111 b)&(1111 0011 b) //经过运算后,a 的值 a=1001 0011 b // a 的第1 组的bit2、bit3 被清零,而其它位不变。

//上述(~(3<<2*1))中的(1)即为组编号;如清零第3 组bit6、bit7 此处应为3 //括号中的(2)为每组的位数,每组有2 个二进制位;若分成4 个一组,此处即为4 //括号中的(3)是组内所有位都为1 时的值;若分成4 个一组,此处即为二进制数“1111 b”

//例如对第2 组bit4、bit5 清零 a &= ~(3<<2*2);

  1. 3. 对变量的某几位进行赋值
  2. ```c
  3. //a = 1000 0011 b
  4. //此时对清零后的第2 组bit4、bit5 设置成二进制数“01 b ”
  5. a |= (1<<2*2);
  6. //a = 1001 0011 b,成功设置了第2 组的值,其它组不变
  1. 对变量某位取反 ```c //a = 1001 0011 b //把bit6 取反,其它位不变 a^=(1<<6);

//a = 1101 0011 b ```