&(按位与)-> 全“1”得“1”,相当于乘法
|(按位或)->有“1”得“1”,相当于加法
~(按位非)->求“~a”,则结果为-(a+1)
^(按位异或)->相异为“1”
原码:二进制定点表示法,“0”表示正,“1”表示负。
反码:正数的反码是其本身;负数的反码是对原码逐位取反,符号为不变。
补码:正数的补码是其本身;负数的补码是其反码+1。
eg:
x=13 的补码00001101
~x : 11110010
第一位是符号位,因为x声明为int,所以,第一位是1,表明是负数
其他位:
1110010
取反
0001101 =13
+1
0001110=14
结果 是 -14(符号为为负数)
注:
如果x是unsigned int
那么 ~x=4294967282
在嵌入式系统编程中,位运算比其他运算更常用。这正是由于在嵌入式系统中涉及到更多有关硬件寄存器的操作,硬件寄存器由若干位组成,这些位可能具有读写,只读,只写等几种属性。在C语言中,可以通过8位,16位,32位的指针进行相应的数据操作,因此整字节数据的读写还是比较直观的。然而,C语言中没有专门的对指定位操作的语法,在进行位操作的时候,需要对指令进行简单的组合来完成功能。1)字节操作
在嵌入式系统中,很多寄存器可能都是多字节的(如16位和32位),而实际上,我们可能需要在其中写入或读出单个字节,可以用下面的宏:
1.
#define GETBYTE0(x) (x & 0x000000ff) //通过位与(&)操作使得最后8位保持
不变,其余位为0
2.
#define GETBYTE1(x) (x & 0x0000ff00)
3.
#define GETBYTE2(x) (x & 0x00ff0000)
4.
#define GETBYTE3(x) (x & 0xff000000)
同样,将一个32位数的指定字节全部置为1或者或者清0,用如下宏:
1.
#define SETBYTE0(x) (x | 0x000000ff) //通过位或(|)操作使得最后8位为1,其余位保持不变
2.
#define SETBYTE1(x) (x | 0x0000ff00)
3.
#define SETBYTE2(x) (x | 0x00ff0000)
4.
#define SETBYTE3(x) (x | 0xff000000)
5.
#define CLRBYTE0(x) (x & 0xffffff00) //通过位与(&)操作使得最后8位为0,其余位保持不变
6.
#define CLRBYTE1(x) (x & 0xffff00ff)
7.
#define CLRBYTE2(x) (x & 0xff00ffff)
8.
#define CLRBYTE3(x) (x & 0x00ffffff)
2)整个字的设置
在嵌入式系统中,有时需要对整个寄存器进行设置,例如在初始化阶段,整个寄存器的所有位都需要按照具体需求设置初始值,如要求如下:
该怎么做呢,如下:
x = (0x1) | (0xe << 2) | (0x2 <<6) | (13 << 8) | (1 << 31)
这里应用的公式是:(需要设置的数值 <
在程序中有时候需要设置和读取寄存器的指定位和位组,如取单个位,单个位置0,读取32位寄存器的第10位。a.判断第n的情况可以用
x & (1 << n)b.对于单个位的置0和置1操作可用如下宏:
1.
#define SETBIT(x,n)
x = x | (1 <
2.
#define SETBIT(x,n)
x = x & ~(1 <
c.获取一个32位无符号整数的31到第n位值的宏如下:
1.
#define TOPBITS(value32u, n) (value32u >> n)
对上面的进行延伸,获取一个32位无符号整数的m到n位(value32u[n:m])的值的宏如下:
#define BITS(value32u, m, n) ((unsigned int) (value32u <> ((31 – (n)) + (m)))
其实上面的这个宏,可以分为两段来理解,第一步将n位通过移位变成最高位,第二步利用上面求31到n的宏来解决,两步和在一起,就是这个宏。
设置寄存器的某些位,而不影响其他位。例如LPC2XXX系列将P0.8、P0.9选择UART1功能:
PINSEL0=0x05<<16;
//可能影响其他管脚连接
PINSEL0=(
PINSEL0&(~(0x 0F<<16))|(0x05<<16);
//不影响其他管脚连接