参考
博文01:https://blog.csdn.net/hongjiujing/article/details/2178593
一、理论知识
学习本节课之前要先去学习位运算操作符的理论知识,注意运算符之间的优先级。
1、 位操作运算符 :非~ 与 & 或 |
(优先级顺序是 非~ 与 & 或 | )
2、逻辑运算符 : 非! 与&& 或 ||
(优先级顺序是 非! 与&& 或 || )
3、^ 异或运算符———不同则为1,相同则为0 // 当且仅当两个运算值中有一个为1但不同时为1时,返回值为1
4、位操作运算符 : 优先级也是以下顺序排列的
~ 非(也叫按位取反运算符)
<< (左移) >> (右移)
& 与 (按位与)
^ (按位 “异或”)
| 或 (按位或)
二、如何对某一位置0或者置1?
方法一:
写成宏,方便移植
#define setbit(x,y) x|=(1<<y) //将X的第Y位置1
#define clrbit(x,y) x&=~(1<<y) //将X的第Y位清0
方法二:
C语言位运算除了可以提高运算效率外,在嵌入式系统的编程中,它的另一个最典型的应用,而且十分广泛地正在被使用着的是位间的与(&)、或(|)、非(~)操作,这跟嵌入式系统的编程特点有很大关系。我们通常要对硬件寄存器进行位设置
譬如,我们通过将AM186ER型80186处理器的中断屏蔽控制寄存器的
第低6位设置为0(开中断2),最通用的做法是:
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
outword(INT_MASK, wTemp &~INT_I2_MASK);
而将该位设置为1的做法是:
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
outword(INT_MASK, wTemp | INT_I2_MASK);
判断该位是否为1的做法是:
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
if(wTemp & INT_I2_MASK)
{
… /* 该位为1 */
}
方法三:
int a|=(1<<x) //X就是某位需要置1的数字,如第四位置1为: a|=(1<<4)
int b&=~(1<<x) //把某位置0
x=x|0x0100 //把第三位置1
x=x&0x1011 //把第三位置0
#define BitGet(Number,pos) ((Number) >> (pos)&1)) //用宏得到某数的某位
#define BitGet(Number,pos) ((Number) |= 1<<(pos)) //把某位置1
#define BitGet(Number,pos) ((Number) &= ~(1<<(pos)) //把某位置0
#define BitGet(Number,pos) ((Number) ^= 1<<(pos)) //把Number的POS位取反
典型操作有:
WTCON |= (1 << 5) //WTCON的第五位清1
WTCON &= ~(1 << 5) //WTCON的第五位清0
博客02:https://blog.csdn.net/u010665638/article/details/84726301
三、位操作的实际应用(最经典,必看)
一般在操作寄存器的时候使用,如32位的arm寄存器,每个位代表的pin脚不同,效果也不同。有时候你只想改变某个pin脚的值从而实现某项功能,其余pin脚保持不变,就得使用位操作,只对目标位进行操作。操作的方式是:读->改->写。不要直接给寄存器赋目标值是因为你只知道要把目标位设置为某值,但是其他的位你并不知道原本是多少,所以要先读取这个寄存器的整体值,然后再修改其中的目标位,然后再把修改后的值写到寄存器。
1)特定位清零用&
譬如:将0xAAAAAAAA 的bit8 ~bit15清零,其他位保持不变。
分析:[位与]任何数(0/1)与1位与时为本身,与0位与为0,所以可以用位与的方式。
unsigned int a = 0xAAAAAAAA;
unsigned int b = 0xFFFF00FF;
unsigned int c;
c = a & b;
printf("c = 0x%x ", c); //c = 0xaaaa00aa
2)特定位 置1用 |
譬如:将0xffff00ff的bit8 ~bit15置1,其他位保持不变。
分析:位或 任何数(0/1)与1位或变为1,与0位或为本身
unsigned int a = 0xffff00ff;
unsigned int b = 0x000ff00;
unsigned int c;
c = a | b;
printf("c = 0x%x ", c); // = 0xffffffff
3)特定位取反用 ^
譬如:将0xffff00ff的bit8 ~bit15取反,其余保持不变
分析:位异或 任何数(0/1)与1位异或会取反,与0位异或为本身
unsigned int a = 0xffff00ff;
unsigned int b = 0xff00;
unsigned int c;
c = a ^ b;
printf("c = 0x%x ", c); // = 0xffffffff
四、特定二进制数的获取
由于上面示例中的unsigned int b的值太过于呆板,后续看代码的时候可能不知道为什么是这个值,所以需要以另外的方式来表达(主要是通过位移和位取反来获取这个特定的二进制数)。
(1) 譬如:unsigned int b = 0xff00; 中的0xff00
可表示为:0xFF<<8 (0xFF :8个二进制1 <<: 左移 8: 8位)
(2) 需要一个bit3 ~bit7, bit23 ~bit25为1的数(隐含意思是其他位都为0)
可为:0x1F<<3 | 0x7<<23
1F (7-3+1=5个1,转换为十六进制则为1F);
7 ( 25-23+1=3个1,转换为十六进制则为7)
| ( 位或,任何数与1位或都为1,与0位或为本身,所以这里用位或就相当于把这2个位移后的数叠加起来)
(3) 需要一个bit3 ~ bit7为0的数
可为:~(0x1F<<3)
总结:
(1)当需要的1比较少,需要的0比较多,就使用1位移的方式;
(2)当需要的0比较少,需要的1比较多,就使用位移然后取反的方式;(3)当需要的数比较复杂,如bit3 ~ bit7,bit23~bit25为1,就可以先位移然后位或的方式。