C语言位操作

一、位操作概述

针对MCU的嵌入是开发中经常涉及到寄存器的操作,例如GPIO配置低寄存器GPIOx_CRL(共32个bit),有时需要改变其中的一位或者几位bit值,同时不能影响其它bit位的值。

例如,需要设置第0位bit=1时,不能简单的设置为:GPIOx_CRL=0x01  ,这样的方法会使得低配置寄存器GPIOx_CRL的其它比特位都置为0。

对于二进制位操作来说:

不管该位原来的值是0还是1,它跟0进行&运算,得到的结果都是0,而跟1进行&运算,将保持原来的值不变;

不管该位原来的值是0还是1,它跟1进行|运算,得到的结果都是1,而跟0进行|运算,将保持原来的值不变。

正确的方法是:

GPIOx_CRL=GPIOx_CRL | 0x01      或者        GPIOx_CRL |= 0x01

或者使用如下方法更加清晰,第几位需要置1就将0x01左移几位。

GPIOx_CRL  |=   (0x01 << 0);

二、位操作具体用法-提取、清零、置1、判断

位操作的用法可以分为四类:

1、寄存器数据的位、字节读取操作:1)提取某一个字节,2)提取某一位;

2、寄存器数据的位、字节清零操作:1)清零某一个字节,2)清零某一位;

3、寄存器数据的位、字节置1操作:  1)将某一个字节置1, 2)将某一位置1;

4、判断某一位或某几位连续的值:1)判断某一位的值,2)判断某几位连续位的值。

1、寄存器数据的位、字节读取操作

1)提取某一个字节

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #defineGET_LOW_BYTE0(x)((x >> 0) & 0x000000ff)/* 获取第0个字节 */
  4. #defineGET_LOW_BYTE1(x)((x >> 8) & 0x000000ff)/* 获取第1个字节 */
  5. #defineGET_LOW_BYTE2(x)((x >> 16) & 0x000000ff)/* 获取第2个字节 */
  6. #defineGET_LOW_BYTE3(x)((x >> 24) & 0x000000ff)/* 获取第3个字节 */
  7. int main()
  8. {
  9. unsigned int a=0x44332211;
  10. printf('0x%x的第0个字节为:0x%x\n',a,GET_LOW_BYTE0(a));
  11. printf('0x%x的第1个字节为:0x%x\n',a,GET_LOW_BYTE1(a));
  12. printf('0x%x的第2个字节为:0x%x\n',a,GET_LOW_BYTE2(a));
  13. printf('0x%x的第3个字节为:0x%x\n',a,GET_LOW_BYTE3(a));
  14. return 0;
  15. }

2)提取某一位

#include <stdio.h>#include <stdlib.h>#defineGET_BIT(x, bit)((x & (1 << bit)) >> bit)/* 获取第bit位 */int main(){unsigned int a=0x51;printf('0x%x的对应的二进制是:%x %x %x %x %x %x %x %x \n',a,GET_BIT(a,7),GET_BIT(a,6),GET_BIT(a,5),GET_BIT(a,4),GET_BIT(a,3),GET_BIT(a,2),GET_BIT(a,1),GET_BIT(a,0));printf('0x%x的第0位的值是:%x\n',a,GET_BIT(a,0));printf('0x%x的第1位的值是:%x\n',a,GET_BIT(a,1));printf('0x%x的第2位的值是:%x\n',a,GET_BIT(a,2));printf('0x%x的第3位的值是:%x\n',a,GET_BIT(a,3));printf('0x%x的第3位的值是:%x\n',a,GET_BIT(a,4));printf('0x%x的第3位的值是:%x\n',a,GET_BIT(a,5));printf('0x%x的第3位的值是:%x\n',a,GET_BIT(a,6));printf('0x%x的第3位的值是:%x\n',a,GET_BIT(a,7));return 0;}

2、寄存器数据的位、字节清零操作

1)清零某一个字节

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #defineCLEAR_LOW_BYTE0(x)(x &= 0xffffff00)/* 清零第0个字节 */
  4. #defineCLEAR_LOW_BYTE1(x)(x &= 0xffff00ff)/* 清零第1个字节 */
  5. #defineCLEAR_LOW_BYTE2(x)(x &= 0xff00ffff)/* 清零第2个字节 */
  6. #defineCLEAR_LOW_BYTE3(x)(x &= 0x00ffffff)/* 清零第3个字节 */
  7. int main()
  8. {
  9. unsigned int a=0x44332211;
  10. unsigned int b=0x44332211;
  11. unsigned int c=0x44332211;
  12. unsigned int d=0x44332211;
  13. printf('0x44332211的第0个字节清零后的值是:%#.8x\n',a,CLEAR_LOW_BYTE0(a));
  14. printf('0x44332211的第1个字节清零后的值是:%#.8x\n',b,CLEAR_LOW_BYTE1(b));
  15. printf('0x44332211的第2个字节清零后的值是:%#.8x\n',c,CLEAR_LOW_BYTE2(c));
  16. printf('0x44332211的第3个字节清零后的值是:%#.8x\n',d,CLEAR_LOW_BYTE3(d));
  17. return 0;
  18. }

2)清零某一位

#include <stdio.h>#include <stdlib.h>#defineCLEAR_BIT(x, bit)(x &= ~(1 << bit))/* 清零第bit位 */int main(){unsigned int a0=0x81;unsigned int a1=0x82;unsigned int a2=0x84;unsigned int a3=0x88;printf('0x81的第0个bit清零后的值是:%#.2x\n',a0,CLEAR_BIT(a0, 0));printf('0x82的第1个bit清零后的值是:%#.2x\n',a1,CLEAR_BIT(a1, 1));printf('0x84的第2个bit清零后的值是:%#.2x\n',a2,CLEAR_BIT(a2, 2));printf('0x88的第3个bit清零后的值是:%#.2x\n',a3,CLEAR_BIT(a3, 3));return 0;}

3、寄存器数据的位、字节置1操作

1)将某一个字节置1

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #defineSET_LOW_BYTE0(x) (x |= 0x000000ff)/* 第0个字节置1 */
  4. #defineSET_LOW_BYTE1(x) (x |= 0x0000ff00)/* 第1个字节置1 */
  5. #defineSET_LOW_BYTE2(x) (x |= 0x00ff0000)/* 第2个字节置1 */
  6. #defineSET_LOW_BYTE3(x) (x |= 0xff000000)/* 第3个字节置1 */
  7. int main()
  8. {
  9. unsigned int a0=0x11111111;
  10. unsigned int a1=0x11111111;
  11. unsigned int a2=0x11111111;
  12. unsigned int a3=0x11111111;
  13. printf('0x11111111的第0个字节置1后的值是:%#.2x\n',a0,SET_LOW_BYTE0(a0));
  14. printf('0x11111111的第1个字节置1后的值是:%#.2x\n',a1,SET_LOW_BYTE1(a1));
  15. printf('0x11111111的第2个字节置1后的值是:%#.2x\n',a2,SET_LOW_BYTE2(a2));
  16. printf('0x11111111的第3个字节置1后的值是:%#.2x\n',a3,SET_LOW_BYTE3(a3));
  17. return 0;
  18. }

2)将某一位置1

#include <stdio.h>#include <stdlib.h>#defineSET_BIT(x, bit)(x |= (1 << bit))/* 置位第bit位 */int main(){unsigned int a0=0x10;unsigned int a1=0x10;unsigned int a2=0x10;unsigned int a3=0x10;printf('0x10的第0个bit置1后的值是:%#.2x\n',a0,SET_BIT(a0, 0));printf('0x10的第1个bit置1后的值是:%#.2x\n',a1,SET_BIT(a1, 1));printf('0x10的第2个bit置1后的值是:%#.2x\n',a2,SET_BIT(a2, 2));printf('0x10的第3个bit置1后的值是:%#.2x\n',a3,SET_BIT(a3, 3));return 0;}

4、判断某一位或某几位连续的值

1)判断某一位的值

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #defineSET_BIT(x, bit)(x |= (1 << bit))/* 置位第bit位 */
  4. int main()
  5. {
  6. unsigned int a=0x66;//二进制 01100110
  7. int i;
  8. for(i=0;i<8;i++)
  9. {
  10. if(a&(1<<i))//关键点
  11. {
  12. printf('0x66二进制的bit%d位的值是1\n',i);
  13. }
  14. else
  15. {
  16. printf('0x66二进制的bit%d位的值是0\n',i);
  17. }
  18. }
  19. return 0;
  20. }

要判断第几位的值,if里就左移几位(不要移过头了)。在针对MCU的嵌入式编程中,可通过这样的方式来判断寄存器的状态位是否被置位。

2)判断某几位连续位的值

#include <stdio.h>#include <stdlib.h>/* 获取第[n:m]位的值 */#define BIT_M_TO_N(x, m, n)  ((unsigned int)(x << (31-(n))) >> ((31 - (n)) + (m)))int main(){unsigned int a=0xAA;//二进制 10101010unsigned int value=0;int i,j;for(i=0,j=1;i<8,j<8;i++,j++){value=BIT_M_TO_N(a, i, j);switch(value){case 0:printf('0xAA的bit[%d,%d]位是:00\n',i,j);break;case 1:printf('0xAA的bit[%d,%d]位是:01\n',i,j);break;case 2:printf('0xAA的bit[%d,%d]位是:10\n',i,j);break;case 3:printf('0xAA的bit[%d,%d]位是:11\n',i,j);break;}}return 0;}

这只是一个查询连续2个状态位的例子,当连续bit位大于2时,会有多种状态,这种情况下就可以用这种方法来取出状态位,再去执行相应操作。

下一篇文章结合STM32F103介绍关于具体寄存器的操作。

(0)

相关推荐