寄存器是用来管理硬件的,所以读写寄存器就是操纵硬件。
怎么操纵寄存器? 三部曲读改写,读改写的意思,就是先把寄存器的值读出来,修
改寄存器中部分位的内容后再写回到寄存器中去。 由于我们操作寄存器时往往只需
要修改寄存器的特定几位就可以了(其它位不能改变),但是寄存器只能按照比如32
位来整个进行读写, 并不能只读写寄存器中特定的一些位,这里就产生了一个矛
盾, 那怎么解决这个问题呢? 常用的方法有以下3种:
1、位与&可以用来清零某些位而不改变其它位 位与:任何数(0或1)与0相与为
0, 与1相与为它自己,所以只要寄存器中的数的某些位与0相与,其它位与1相与
即可
//位与&清零寄存器中的BIT4~BIT7位而不改变其它位
unsigned int a = 0x1234ABCD, b = 0xFFFFFF0F;
unsigned int c;
c = a & b; //0x1234AB0D
printf("c = 0x%x\n", c);
2.位或|可以用来置1某些位而不改变其它位 位或|:任何数(0或1)与1相或为
1,与0相或则为它自己。
//位或|置1寄存器中的BIT8~BIT15位而不改变其它位
unsigned int a = 0x1234ABCD, b = 0x0000FF00;
unsigned int c;
c = a | b; //0x1234FFCD
printf("c = 0x%x\n", c);
3.位异或^可以用来取反某些位而不改变其它位 位异或^: 任何数(0或1)与1异
或则取反,与0异或则为它自己。
//位异或^取反寄存器中的BIT8~BIT11位而不改变其它位
unsigned int a = 0x1234ABCD, b = 0x00000F00;
unsigned int c;
c = a ^ b; //0x1234A4CD
printf("c = 0x%x\n", c);
用位与&、位或|、位异或^可以分别用来对寄存器的某些位进行清理、置1、取反操
作,但是需要构建一个32位的由0和1构成的数来满足我们的要求 ,比较麻烦,需
要依赖软件工具、计算器或者大脑来计算得到,不是很直观,因为不好理解,代码
的可读性会变差, 所以可以通过以下方法构造特定二进制数来实现。
4.通过移位(<<或>>)和位或来实现。
//构造一个bit7~bit12是1,其余位全是0的数
(0x3F<<7)
//构造一个bit0~bit2、bit7~bit12、bit18~bit21为1,其余位全是0的数
((7<<0)|(0x3F<<7)|(0xF<<18))
代码实现:
//构造一个bit7~bit12是1,其余位全是0的数
unsigned int a;
a = (0x3F<<7); //0x1F80
printf("a = %x.\n", a);
//构造一个bit0~bit2、bit7~bit12、bit18~bit21为1,其余位全是0的数
unsigned int a;
a = ((7<<0)|(0x3F<<7)|(0xF<<18)); //0x3C1F87
printf("a = %x.\n", a);
5.通过取反和移位来构造特定的二进制数
//构造一个bit5~bit9是0,其余位全是1的二进制数
//方法一:(0x1F<<0)|(0x7FFFFF<<10) 用移位<<和或|操作实现,比较笨的方法
//方法二:~(0x1F<<5) 先构建一个位反数,然后取反得到,比较聪明的方法
代码实现:
//构造一个bit5~bit9是0,其余位全是1的二进制数
//方法一:比较笨的方法
unsigned int a;
a = (0x1F<<0)|(0x7FFFFF<<10); //0xFFFFFC1F
printf("a = %x.\n", a);
//方法二:比较聪明的方法
unsigned int b;
b = ~(0x1F<<5); //0xFFFFFC1F
printf("b = %x.\n", b);
一般来说,如果需要构建的二进制数中大多数是0,少数是1,可以通过移位的
方法来构造; 如果需要构建的二进制数中大多数是1,少数是0,可以通过移
位构建位反数然后取反的方法来构造; 如果有多段连续1的数出现,则可以分
段移位然后或起来叠加得到。
6.位操作的相关练习:
回顾:要置1用|,用清零用&,要取反用^,~和<<、>>用来构建特定二进制数。
①给定一个整型数a,设置a的bit3,保证其他位不变。
a |= (1<<3);
②给定一个整型数a,设置a的bit3~bit7,保持其他位不变。
a |= (0x1F<<3); 或者 a |= (0b11111<<3);
③给定一个整型数a,清除a的bit15,保证其他位不变。
a &= (~(1<<15));
④给定一个整形数a,清除a的bit15~bit23,保持其他位不变。
a &= (~(0x1FF<<15));
⑤给定一个整形数a,取出a的bit3~bit8。
//保持bit3~bit8的数不变,其它位全部清零。然后再右移3位。
a &= (0x3F<<3);
a >>= 3;
⑥用C语言给一个寄存器的bit7~bit17赋值937(其余位不受影响)。
//把bit7~bit17清零或者置1,其余位不变,然后位或或者位与0x3A9
a &= (~(0x7FF<<7));
a |= (0x3A9<<7);
⑦用C语言将一个寄存器的bit7~bit17中的值加17(其余位不受影响)。
b= a &(0x7FF<<7);
b >>= 7;
b += 17;
a &= (~(0x7FF<<7));
a |= (b<<7);
⑧用C语言给一个寄存器的bit7~bit17赋值937,同时给bit21~bit25赋值17.
a &= (~((0x7FF<<7) | (0x1F<<21)));
a |= ((0x3A9<<7) | (0x11<<21));
代码验证:
//给定一个整型数a,设置a的bit3,保证其他位不变。
unsigned int a = 0;
a |= (1<<3); //0x8
printf("a = 0x%x.\n", a);
//给定一个整型数a,设置a的bit3~bit7,保持其他位不变。
/*unsigned int a = 0;
//a |= (0x1F<<3); //0xf8
a |= (0b11111<<3); //0xf8
printf("a = 0x%x.\n", a); */
//给定一个整型数a,清除a的bit15,保证其他位不变。
/*unsigned int a = 0xFFFFFFFF;
a &= (~(1<<15)); //0xFFFF7FFF
printf("a = 0x%x.\n", a); */
//给定一个整形数a,清除a的bit15~bit23,保持其他位不变。
/*unsigned int a = 0xFFFFFFFF;
a &= (~(0x1FF<<15)); //0xFF007FFF
printf("a = 0x%x.\n", a);*/
//给定一个整形数a,取出a的bit3~bit8。
/*unsigned int a = 0xFFFF1234;
a &= (0x3F<<3); //0x30
a >>= 3; //0x6
printf("a = 0x%x.\n", a); */
//用C语言给一个寄存器的bit7~bit17赋值937(其余位不受影响)。
/*unsigned int a = 0xFFFF1234;
a &= (~(0x7FF<<7));
a |= (0x3A9<<7); //0xfffdd4b4
printf("a = 0x%x.\n", a); */
//用C语言给一个寄存器的bit7~bit17赋值937,同时给bit21~bit25赋值17.
/*unsigned int a = 0xFFFF1234, b;
b= a &(0x7FF<<7);
b >>= 7;
b += 17;
a &= (~(0x7FF<<7));
a |= (b<<7); //0xffff1ab4
printf("a = 0x%x.\n", a); */
//用C语言给一个寄存器的bit7~bit17赋值937,同时给bit21~bit25赋值17.
unsigned int a = 0xFFFF1234;
a &= (~((0x7FF<<7) | (0x1F<<21)));
a |= ((0x3A9<<7) | (0x11<<21)); //0xfe3dd4b4
printf("a = 0x%x.\n", a);