C語言位操作 - bit 、byte的清零,置1,提取,判斷

一、位操作概述

針對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)提取某一個字節

#include <stdio.h>
#include <stdlib.h>

#define	GET_LOW_BYTE0(x)	((x >>  0) & 0x000000ff)	/* 獲取第0個字節 */
#define	GET_LOW_BYTE1(x)	((x >>  8) & 0x000000ff)	/* 獲取第1個字節 */
#define	GET_LOW_BYTE2(x)	((x >> 16) & 0x000000ff)	/* 獲取第2個字節 */
#define	GET_LOW_BYTE3(x)	((x >> 24) & 0x000000ff)	/* 獲取第3個字節 */

int main()
{
   unsigned int a=0x44332211;

    printf("0x%x的第0個字節爲:0x%x\n",a,GET_LOW_BYTE0(a));
    printf("0x%x的第1個字節爲:0x%x\n",a,GET_LOW_BYTE1(a));
    printf("0x%x的第2個字節爲:0x%x\n",a,GET_LOW_BYTE2(a));
    printf("0x%x的第3個字節爲:0x%x\n",a,GET_LOW_BYTE3(a));
    return 0;
}

 

2)提取某一位

#include <stdio.h>
#include <stdlib.h>

#define	GET_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)清零某一個字節

#include <stdio.h>
#include <stdlib.h>


#define	CLEAR_LOW_BYTE0(x)	(x &= 0xffffff00)	/* 清零第0個字節 */
#define	CLEAR_LOW_BYTE1(x)	(x &= 0xffff00ff)	/* 清零第1個字節 */
#define	CLEAR_LOW_BYTE2(x)	(x &= 0xff00ffff)	/* 清零第2個字節 */
#define	CLEAR_LOW_BYTE3(x)	(x &= 0x00ffffff)	/* 清零第3個字節 */

int main()
{
   unsigned int a=0x44332211;
   unsigned int b=0x44332211;
   unsigned int c=0x44332211;
   unsigned int d=0x44332211;

    printf("0x44332211的第0個字節清零後的值是:%#.8x\n",a,CLEAR_LOW_BYTE0(a));
    printf("0x44332211的第1個字節清零後的值是:%#.8x\n",b,CLEAR_LOW_BYTE1(b));
    printf("0x44332211的第2個字節清零後的值是:%#.8x\n",c,CLEAR_LOW_BYTE2(c));
    printf("0x44332211的第3個字節清零後的值是:%#.8x\n",d,CLEAR_LOW_BYTE3(d));
    return 0;
}

2)清零某一位

#include <stdio.h>
#include <stdlib.h>


#define	CLEAR_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

#include <stdio.h>
#include <stdlib.h>


#define	SET_LOW_BYTE0(x)  (x |= 0x000000ff)	/* 第0個字節置1 */
#define	SET_LOW_BYTE1(x)  (x |= 0x0000ff00)	/* 第1個字節置1 */
#define	SET_LOW_BYTE2(x)  (x |= 0x00ff0000)	/* 第2個字節置1 */
#define	SET_LOW_BYTE3(x)  (x |= 0xff000000)	/* 第3個字節置1 */



int main()
{
   unsigned int a0=0x11111111;
   unsigned int a1=0x11111111;
   unsigned int a2=0x11111111;
   unsigned int a3=0x11111111;



    printf("0x11111111的第0個字節置1後的值是:%#.2x\n",a0,SET_LOW_BYTE0(a0));
    printf("0x11111111的第1個字節置1後的值是:%#.2x\n",a1,SET_LOW_BYTE1(a1));
    printf("0x11111111的第2個字節置1後的值是:%#.2x\n",a2,SET_LOW_BYTE2(a2));
    printf("0x11111111的第3個字節置1後的值是:%#.2x\n",a3,SET_LOW_BYTE3(a3));
    return 0;
}

 

 2)將某一位置1

#include <stdio.h>
#include <stdlib.h>


#define	SET_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)判斷某一位的值

#include <stdio.h>
#include <stdlib.h>


#define	SET_BIT(x, bit)	(x |= (1 << bit))	/* 置位第bit位 */



int main()
{
   unsigned int a=0x66;//二進制 01100110
    int i;
     for(i=0;i<8;i++)
    {
        if(a&(1<<i))//關鍵點
        {
            printf("0x66二進制的bit%d位的值是1\n",i);
        }
        else
        {
            printf("0x66二進制的bit%d位的值是0\n",i);
        }
    }


    return 0;
}

要判斷第幾位的值,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;//二進制 10101010
   unsigned 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介紹關於具體寄存器的操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章