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

若协议中如下图所示: 

注意:

        长度为1,表示1个字节,也就是0xFF,也就是 1111 1111

(这里0xFF只是单纯表示一个数,也可以是其他数,这里需要注意的是1个字节的意思)

一、按位与 &

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

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

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

#include <stdio.h>
// (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");

    printf("\n\n");
    printf("Green Mask Value: 0x%x\n", greenMask);
    printf("Yellow Mask Value: 0x%x\n", yellowMask);
    printf("White Mask Value: 0x%x\n", whiteMask);

    return 0;
}

输出: 
    绿灯灭 黄灯灭 红灯亮 蜂鸣器停 蓝灯亮 白灯亮
    Green Mask Value: 0x1      // 0x1 = 0001
    Yellow Mask Value: 0x2     // 0x2 = 0010
    White Mask Value: 0x20     // 0x20 = 10 0000

在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;
}

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

综合 

示例 1 :

要求: 取一个数的高八位与低八位,并将二者的顺序替换

涉及操作:

  • 取一个数中的某些值
  • 将两个8位的数合并为一个16位的数
#include <stdio.h>
#include <stdint.h>

int main() {
	uint16_t combinedData = 0b0110011110110100; // (BIN) 0110011110110100 = (HEX) 0x67B4
	
	uint8_t highByte = combinedData >> 8;  // 取左边的八位
	uint8_t lowByte = combinedData & 0xFF; // 取右边的八位
	
	printf("Combined data in hexadecimal: 0x%x\n", combinedData);
	printf("highByte data in hexadecimal: 0x%x\n", highByte);
	printf("lowByte data in hexadecimal: 0x%x\n", lowByte);
	
	// 调换高八位与低八位顺序
    combinedData = (lowByte << 8) | highByte; // 右边的八位左移后变成16位,再与原本的左边八位取或
    
    printf("Combined data in hexadecimal: 0x%x\n", combinedData);
    
    return 0;
}

输出:
        Combined data in hexadecimal: 0x67b4
        highByte data in hexadecimal: 0x67
        lowByte data in hexadecimal: 0xb4
        Combined data in hexadecimal: 0xb467


比如是在串口接收的时候:

if(upAck->funcCode==0x03) // 表示要读寄存器时
    {
        // upAck->regAmt 为寄存器的数量,若一个寄存器为16位
        for(u16 i = 0; i < upAck->regAmt; i+=2) // 每两个字节一组进行高低字节交换
        {
            u16 lowByte = MeterAck->data[i];          // 保存低字节
            u16 highByte = MeterAck->data[i+1];       // 保存高字节
            
            // 组合成正确的16位值,此时lowByte已经是低字节,highByte是高字节
            u16 temp = (highByte << 8) | lowByte; 
            
            // 分别提取高字节和低字节到响应缓冲区
            upAck->rdata[i] = highByte;               // 高字节
            upAck->rdata[i+1] = lowByte;              // 低字节
        }
    }

示例 2 :

要求: 检测所有器件是否全部停止

涉及操作:

  • 位与操作

#include <stdio.h>

int main()
{   
    int data_0 = 0x34;     // (DEC)64 = (BIN)0011 0100 = (HEX)0x34
    int data_1 = 0x00;

    if (data_0 & 0x3F)   // 0x3F = 0011 1111
        printf("存在器件在运行\n");
    else 
        printf("所有已经停止\n");

    if (data_1 & 0x3F)   // 0x3F = 0011 1111
        printf("存在器件在运行\n");
    else 
        printf("所有已经停止\n");

    return 0;
}

输出:
        存在器件在运行
        所有已经停止

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/790465.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

URI:URL、URN

名称解释&#xff1a; URI:统一资源标识符&#xff1b; URL:统一资源定位符; URN:统一资源命名符&#xff1b; URI、URL、URN关系 URI是URL和URN的超集,也就是说URI有两种方式&#xff0c;一种是URL一种是URN,不过URL的方式用的比较多。 看了一个视频&#xff0c;博主解释非…

xcode配置swift使用自定义主题颜色或者使用RGB或者HEX颜色

要想在xcode中使用自定义颜色或者配置主题色&#xff0c;需要在Assets中配置&#xff0c;打开Assets文件&#xff0c;然后点击添加Color Set&#xff1a; 输入颜色的名称&#xff0c;然后选中这个颜色&#xff0c;会出现两个颜色&#xff1a; Any Appearance表示亮色模式下使用…

基于uni-app与图鸟UI的知识付费小程序模板

一、项目概述 在知识经济蓬勃发展的背景下&#xff0c;移动互联网成为知识传播与消费的重要渠道。本项目旨在利用前沿的前端技术栈——uni-app及高效UI框架图鸟UI&#xff0c;打造一款集多功能于一体的、面向广大求知者的知识付费平台移动端模板。该模板旨在简化开发流程&…

【最强八股文 -- 计算机网络】【快速版】TCP 与 UDP 头部格式

目标端口和源端口: 应该把报文发给哪个进程包长度: UDP 首部的长度跟数据的长度之和校验和: 为了提供可靠的 UDP 首部和数据而设计&#xff0c;接收方使用检验和来检查该报文段中是否出现差错 源端口号和目的端口号: 用于多路复用/分解来自或送到上层应用的数据。告诉主机报文段…

轻松理解c++17的string_view

文章目录 轻松理解c17的string_view设计初衷常见用法构造 std::string_view常用操作作为函数参数 注意事项总结 轻松理解c17的string_view std::string_view 是 C17 引入的一个轻量级、不拥有&#xff08;non-owning&#xff09;的字符串视图类。它的设计初衷是提供一种高效、…

Web学习day03

maven&Mybatis 目录 maven&Mybatis 文章目录 一、maven 1.1作用 1.2仓库 1.3命令 1.4依赖范围 1.5生命周期 二、MyBatis 2.1简介 2.2API 2.3增删改的实现&案例 总结 一、maven 1.1作用 统一项目结构&#xff1b;项目构建&#xff1a;通过简单命令&a…

高阶面试-dubbo的学习

SPI机制 SPI&#xff0c;service provider interface&#xff0c;服务发现机制&#xff0c;其实就是把接口实现类的全限定名配置在文件里面&#xff0c;然后通过加载器ServiceLoader去读取配置加载实现类&#xff0c;比如说数据库驱动&#xff0c;我们把mysql的jar包放到项目的…

16. Revit API: Family、FamilySymbol、FamilyInstance

前言 前面写着一直絮絮叨叨&#xff0c;感觉不好。想找些表情包来&#xff0c;写得好玩点&#xff0c;但找不到合适的&#xff0c;或者说耗时费力又不满意&#xff0c;而自个儿又做不来表情包&#xff0c;就算了。 其次呢&#xff0c;之前会把部分类成员给抄表列出来&#xf…

昇思25天学习打卡营第15天|基于 MindSpore 实现 BERT 对话情绪识别

文章目录 昇思MindSpore应用实践1、基于 MindSpore 实现 BERT 对话情绪识别BERT 模型简介数据集数据加载和数据预处理 2、模型训练模型验证 3、模型推理 Reference 昇思MindSpore应用实践 本系列文章主要用于记录昇思25天学习打卡营的学习心得。 1、基于 MindSpore 实现 BERT…

FOLANNIC FD31 UPS工作原理介绍

1&#xff0e;1简介 FOLANNIC FD31系列UPS系工业级电厂型不间断电源&#xff0c;是为重要负载提供不受电网干扰、稳压、稳频的电力供应的电源设备&#xff0c;在市电掉电后&#xff0c;UPS可给负载继续提供一段时间供电&#xff0c;此系列UPS采用带输出隔离变压器的高频双变换结…

回收站删除了是不是彻底删除了 回收站删除了怎么找回 回收站删除了还能找回来吗

电脑删除的数据文件一般不会直接被彻底删除掉&#xff0c;而是会暂存在回收站中&#xff0c;这样设计主要是为了防止误删除等操作&#xff0c;如果不小心删除了很重要的文件&#xff0c;只需要在回收站对文件进行还原即可。为了让大家更了解回收站&#xff0c;下面给大家详细讲…

JavaWeb-js(4)

js事件 在前端页面中&#xff0c;js程序大多数是由事件来驱动的&#xff0c;当触发某些事件的时候&#xff0c;可以使用js负责响应。 js事件由三部分组成: 事件源——》指的是被触发的对象; 事件类型——》如何触发的事件&#xff0c;如:鼠标单击、双击、键盘操作等;…

【题目/算法训练】:单调队列单调栈

&#x1f680; 前言&#xff1a; 【算法】单调队列&&单调栈 可以在看完这篇文章后&#xff0c;再来写下面的题目 一、绝对差不超过限制的最长连续子数组 思路&#xff1a; 1&#xff09; 就相当于滑动窗口&#xff0c;维护滑动窗口内的两个值&#xff0c;一个是最大值…

CV05_深度学习模块之间的缝合教学(1)

1.1 在哪里缝 测试文件&#xff1f;&#xff08;&#xff09; 训练文件&#xff1f;&#xff08;&#xff09; 模型文件&#xff1f;&#xff08;√&#xff09; 1.2 骨干网络与模块缝合 以Vision Transformer为例&#xff0c;模型文件里有很多类&#xff0c;我们只在最后…

Flutter——最详细(Table)网格、表格组件使用教程

背景 用于展示表格组件&#xff0c;可指定线宽、列宽、文字方向等属性 属性作用columnWidths列的宽度defaultVerticalAlignment网格内部组件摆放方向border网格样式修改children表格里面的组件textDirection文本排序方向 import package:flutter/material.dart;class CustomTa…

Mac 上安转文字转 SQL 利器 WrenAI

WrenAI 是一个开源的 Text-SQL 的工具&#xff0c;通过导入数据库结构&#xff0c;通过提问的方式生成 SQL。本文将讲述如何在 MacOS 上安装 WrenAI。要运行WrenAI&#xff0c;首先需要安装 Docker 桌面版。 下载 WrenAI https://github.com/Canner/WrenAI/releases/tag/0.7.…

开源流程表单设计器都有哪些值得一提的优势?

如果需要提质、增效、降本&#xff0c;不妨来了解下低代码技术平台、开源流程表单设计器的功能和优势特点。想要实现流程化办公&#xff0c;低代码技术平台是助力增效的理想工具。功能灵活、操作方便、好维修、可视化操作等优势都是其深受行业喜爱的优势特点。通过本文&#xf…

DDL也会有undo吗?模拟Oracle中DML、DDL与undo的关系,10046跟踪DDL语句

已经有两个月没有更新博客了&#xff0c;主要实在忙毕设和毕业的一些事情&#xff01;这两个月也是非常的精彩呀&#xff0c;充分体会到了职场的和校园的不同&#xff0c;作为一名刚毕业就满 1 年工作经验的牛马人&#xff0c;在两个月期间经历了两次调岗、两次降薪&#xff0c…

一句歌词描述夏天

夏天总是带着一种奇特的魔力&#xff0c;既能让人沉醉在阳光和海浪的浪漫中&#xff0c;也能在炎热与燥热中让人心生烦闷。特别是在夏日里情绪低落时&#xff0c;那些可以抚平心情的歌曲显得尤为珍贵。音乐&#xff0c;这个神奇的存在&#xff0c;总能在最需要的时候带来心灵的…

使用AutoGPT构建智能体:从LSTM到Prompt编写实战教程001

如果报错,这里会有一个环境变量的设置需要设置上. 然后这一节我们来自己制作一个智能体,来感受一下,实际上现在,大模型还是可以做很多功能的. 可以看到上面是智能体的架构,之前也说过了, 上面这几个功能,如果用我们人类去操作,还是需要花些时间的,如果用大模型就快很多了. 以…