Bootstrap

[嵌入式 C 语言] 按位与、或、取反、异或

一、按位与 &

  • 有0则0,全1则1
  • 1010 & 0011 =  0010
  • 0xef & 0xfe = 0xee ( 0x1110 1111 & 0x1111 1110 = 0x1110 1110)

若协议中如下图所示: 

1.1 配合左移运算符  <<  取指定的位

 说明:DEC表示十进制、BIN表示二进制、HEX表示十六进制

// (DEC)64 = (BIN)0011 0100 = (HEX)0x34

int main()
{   
    int data = 0x34;    

    // 定义位掩码
    int greenMask = 1 << 0;    // 绿灯
    int yellowMask = 1 << 1;   // 黄灯
    int redMask = 1 << 2;      // 红灯
    int buzzerMask = 1 << 3;   // 蜂鸣器
    int blueMask = 1 << 4;     // 蓝灯
    int whiteMask = 1 << 5;    // 白灯
    
    // 检查并打印状态
    if((data & greenMask) == 0) printf("绿灯灭 "); else printf("绿灯亮 ");
    if((data & yellowMask) == 0) printf("黄灯灭 "); else printf("黄灯亮 ");
    if((data & redMask) == 0) printf("红灯灭 "); else printf("红灯亮 ");
    if((data & buzzerMask) == 0) printf("蜂鸣器停 "); else printf("蜂鸣器响 ");
    if((data & blueMask) == 0) printf("蓝灯灭 "); else printf("蓝灯亮 ");
    if((data & whiteMask) == 0) printf("白灯灭\n"); else printf("白灯亮\n");

    return 0;
}

输出: 绿灯灭 黄灯灭 红灯亮 蜂鸣器停 蓝灯亮 白灯亮

在C语言中,`<<` 是位左移运算符。当你有一个整数值(在这个例子中是1)并对其使用左移运算符,意味着你将该数值的二进制表示向左移动指定位数。每向左移一位,数值就相当于乘以2(因为二进制系统下,每一位代表的权重是2的幂次)。

具体到你的代码示例:

  • int greenMask = 1 << 0;表示将1(二进制表示为`00000001`)向左移动0位,实际上没有移动,所以`greenMask`的值为1,对应二进制的最低位,这里是用来控制绿灯的。
  • int yellowMask = 1 << 1;将1向左移动1位,得到`00000010`,即十进制的2,用作黄灯的控制位。
  • int redMask = 1 << 2;向左移2位,得到`00000100`,即十进制的4,对应红灯控制位。
  • int buzzerMask = 1 << 3;移动3位,得到`00001000`,即十进制的8,用于蜂鸣器。
  • int blueMask = 1 << 4;移动4位,得到`00010000`,即十进制的16,对应蓝灯。
  • int whiteMask = 1 << 5;移动5位,得到`00100000`,即十进制的32,控制白灯。

这样,每个掩码变量都对应了一个特定的位,可以用来单独控制或检测某个功能的状态。在后续的条件判断中,通过按位与操作(`&`)检查`data`中的特定位是否为1,以此来确定对应设备的状态(开启或关闭)。

1.2 整体按位与

#include <stdio.h>

// 0x64 = 0110 0100     0x34 =  0011 0100

int main() {
    int targetState = 0x34; // 这个掩码代表了指定的状态:白灯蓝灯亮,蜂鸣器停,红灯亮,黄绿灯灭
    int data_1 = 0x64; // 数据,假设这就是我们得到的数据
    int data_2 = 0x34;

    // 使用按位与操作来检查data是否匹配targetState

    if((data_1 & targetState) == targetState) {
        printf("状态匹配:白灯亮 蓝灯亮 蜂鸣器停 红灯亮 黄灯灭 绿灯灭\n");
    } else {
        printf("状态不匹配\n");
    }
    
    if((data_2 & targetState) == targetState) {
        printf("状态匹配:白灯亮 蓝灯亮 蜂鸣器停 红灯亮 黄灯灭 绿灯灭\n");
    } else {
        printf("状态不匹配\n");
    }
    

    return 0;
}

输出:
状态不匹配
状态匹配:白灯亮 蓝灯亮 蜂鸣器停 红灯亮 黄灯灭 绿灯灭

 1.3 清零状态

#include <stdio.h>

int main() {
    // 定义位掩码
    int greenMask = 1 << 0;    // 绿灯
    int yellowMask = 1 << 1;   // 黄灯
    int redMask = 1 << 2;      // 红灯
    int buzzerMask = 1 << 3;   // 蜂鸣器
    int blueMask = 1 << 4;     // 蓝灯
    int whiteMask = 1 << 5;    // 白灯
    
    // 假设初始状态
    int data = 0b01101000; // 二进制表示,举例:绿灯灭、黄灯灭、红灯亮、蜂鸣器停、蓝灯亮、白灯亮

    // 打印原始状态
    printf("原始状态: ");
    if((data & greenMask) == 0) printf("绿灯灭 "); else printf("绿灯亮 ");
    if((data & yellowMask) == 0) printf("黄灯灭 "); else printf("黄灯亮 ");
    if((data & redMask) == 0) printf("红灯灭 "); else printf("红灯亮 ");
    if((data & buzzerMask) == 0) printf("蜂鸣器停 "); else printf("蜂鸣器响 ");
    if((data & blueMask) == 0) printf("蓝灯灭 "); else printf("蓝灯亮 ");
    if((data & whiteMask) == 0) printf("白灯灭\n"); else printf("白灯亮\n");

    // 创建清零所有灯的掩码
    int clearLightsMask = ~(greenMask | yellowMask | redMask | blueMask | whiteMask);
    
    // 使用按位与操作清零所有灯的状态
    data &= clearLightsMask;
    
    // 打印更新后的状态
    printf("清零灯状态后: ");
    if((data & greenMask) == 0) printf("绿灯灭 "); else printf("绿灯亮 ");
    if((data & yellowMask) == 0) printf("黄灯灭 "); else printf("黄灯亮 ");
    if((data & redMask) == 0) printf("红灯灭 "); else printf("红灯亮 ");
    if((data & buzzerMask) == 0) printf("蜂鸣器停 "); else printf("蜂鸣器响 ");
    if((data & blueMask) == 0) printf("蓝灯灭 "); else printf("蓝灯亮 ");
    if((data & whiteMask) == 0) printf("白灯灭\n"); else printf("白灯亮\n");

    return 0;
}

输出:
原始状态: 绿灯灭 黄灯灭 红灯灭 蜂鸣器响 蓝灯灭 白灯亮
清零灯状态后: 绿灯灭 黄灯灭 红灯灭 蜂鸣器响 蓝灯灭 白灯灭

;