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

2023-11-06

一、位操作概述

针对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介绍关于具体寄存器的操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言位操作 - bit 、byte的清零,置1,提取,判断 的相关文章

随机推荐

  • python批量爬取公众号文章

    前言 本文的文字及图片来源于网络 仅供学习 交流使用 不具有任何商业用途 版权归原作者所有 如有问题请及时联系我们以作处理 作者 舴艋的舟 PS 如有需要Python学习资料的小伙伴可以加点击下方链接自行获取 python免费学习资料以及群
  • js逆向:rpc远程调用

    websocket python代码 服务端 先开启这个 import asyncio import websockets connected set async def server websocket connected add web
  • Linux系统连接华为oceanstor数据存储

    Linux系统连接华为oceanstor数据存储 一 登录检查oceanstor数据存储 二 配置linux使用的数据储存 1 创建LUN 2 创建Lun组 3 创建主机 4 创建主机组 5 创建映射关系 三 Linux客户端操作 1 查看
  • 「建议收藏」Pycharm使用教程(非常详细,非常实用)

    Pycharm使用教程 1 Jetbrains家族和Pycharm版本划分 pycharm是Jetbrains家族中的一个明星产品 Jetbrains开发了许多好用的编辑器 包括Java编辑器 IntelliJ IDEA JavaScrip
  • Atcoder Beginner Contest 300

    A N choice question AC代码 include
  • 【Java基础11】面向对象、面向过程、类、对象、封装

    一 面向对象和面向过程 面向对象 以对象为单位 通过调度组合不同的对象来完成某一个功能 面向过程 以步骤为单位 一步一步完成某一个具体的功能 二 类 1 类的定义 class 类名 在类中定义属性 方法 class student Stri
  • pytorch 多个模型 求平均

    from collections import OrderedDict import torch from models faceland d import FaceLanndInference d if name main model F
  • Vite 打包体积分析,性能提升不再困扰

    其实这个问题最好改成 rollup 打包体积分析 但是为什么我会取这个名字呢 其实这主要是由于我的习惯性引起的 因为太久没用一个东西 如果遇到问题 肯定会去围绕它自身去进行搜索 例如遇到 vite 打包分析相关问题 就会在 google 搜
  • MinIO从信息泄漏到RCE

    文章目录 信息泄露 漏洞利用 漏洞分析 漏洞修复 RCE 漏洞分析 参考文章 信息泄露 漏洞利用 如果MinIO以集群方式部署 存在信息泄露漏洞 攻击者可以通过HTTP请求获取目标进程的所有环境变量 包括MINIO SECRET KEY和M
  • 计算机网络——分层的体系结构(OSI模型/五层协议栈)

    一 基础知识 计算机网络 计算机网络是一个非常复杂的系统 涉及许多组成部分 主机 hosts 路由器 routers 各种链路 links 应用 applications 协议 protocols 硬件 软件 网络体系结构的特点 1 网络体
  • [高级数据结构C++] 树状数组进阶(求逆序对的个数)

    算法竞赛 file author jUicE g2R qq 3406291309 彬 bin 必应 一个某双流一大学通信与信息专业大二在读 brief 一直在算法竞赛学习的路上 copyright 2023 9 COPYRIGHT 原创技术
  • ROS模型构建、定位导航

    利用URDF或者Xacro文件 以XML的方式描述小车底盘 camera laser Kinect等基本机器人结构 通过Gazebo或Rviz将文件解析为图形化的机器人模型 其中很多代码可以从网络上找到 主要注意参数和坐标系的设置 例如在K
  • CSS之美化网页 span标签 与 div标签

    CSS高级特性 我们大家在学习CSS之前 肯定已经接触过了HTML了吧 那么我们为什么还要学习CSS呢 首先哈 CSS可以有效的传递页面信息 使用CSS美化过的页面文本 非常漂亮 美观 并且可以突出重点 使用户看到页面的主要内容 具有良好的
  • UE4笔记-进程/线程/网络/IO模块的相关问题记录

    吐槽 如果有Qt的开发经验 会发现其实在比较底层编程理念UE4和Qt极其相识 很多类名和用法甚至都是相同的 Q 创建线程类 UE4文档没有特别介绍关于线程模块的文章 这里自己简单记录一下 备查 目前来说UE4的线程模块还是比较简陋的 命名风
  • 如果一个节点重新安装了,处理办法

    1 安装操作系统 如果可以最好所有的包都安装上 创建用户 组 更改核心参数 bash profile 2 配制ssh 保证新的结点和原有的节点互信 3 安装asmlib 然后用 etc init d oracleasm scandisks
  • Mybatis中的动态SQL

    Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能 它存在的意义是为了解决拼接SQL语句字符串时的痛点问题 一 if 单独使用较少 if标签可通过test属性 即传递过来的数据 的表达式进行判断 若表达式的结果为t
  • 单目3D检测-坐标系、数据集

    0 单目3D检测任务 c x y z w
  • JAVA基本数据类型与byte互相转换(位运算,原码,补码)

    最近整理了之前的一些知识 做了一个java中byte类型与int long转换以及将字节信息表示成字符串形式的工具 对前面的只是做了一下复习整理 原码 反码 补码 首先这三者都是二进制码即 0 1组合 原码 最高位为符号位 0表示正数 1表
  • CAN 帧ID 与J1939 PGN 转换例子

    在saeJ1939中文版中找的三张图如下 例如 0x18 FE DF 00 110 0 0 11111110 11011111 00000000 P R DP PF PS SA 具体参数即为数据段 0 64 优先级为 P 110 2 或6
  • C语言位操作 - bit 、byte的清零,置1,提取,判断

    一 位操作概述 针对MCU的嵌入是开发中经常涉及到寄存器的操作 例如GPIO配置低寄存器GPIOx CRL 共32个bit 有时需要改变其中的一位或者几位bit值 同时不能影响其它bit位的值 例如 需要设置第0位bit 1时 不能简单的设