博客
关于我
2、位操作
阅读量:795 次
发布时间:2019-03-25

本文共 2610 字,大约阅读时间需要 8 分钟。

常用位操作符

今天,我想分享一些关于位操作符的知识点,这些对嵌入式开发和计算机基础很有用。位操作是计算机科学中非常重要的基础知识,尤其是在处理硬件接口和底层驱动时,常常需要用到这些高效的操作方式。

位与(&)

位与操作符是一个非常强大的工具,用于按位进行逻辑与操作。& 是位与符号,两个 && 则表示逻辑与操作。例如,两个数 0xAA 和 0xF0 的位与结果是 0xA0。而逻辑与则不一样,0xAA && 0xF0 的结果是 1(因为逻辑与只关心两者是否为真,如果至少有一个为假,结果为假)。

从真值表可以看出:

  • 1 & 1 = 1
  • 其他组合都为 0

这种特性使得位与操作非常适合用于清零特定的位或者保留特定位的值。

位或(|)

位或操作符就是它名字说的那样,用于按位或操作。| 是位或符号,两个 || 就表示逻辑或操作。例如,1|0 的结果是 1,0|1 的结果是 1,而 0|0 的结果是 0。

位或操作的特点是,只要有至少一个位为 1,结果位就会为 1。如果你希望某一位变成 1,而其他位保持不变,位或操作就是很好的选择。

位取反(~)

位取反是一个非常有用的操作符,它可以将二进制数中的每一位取反(1变成0,0变成1)。在 C 语言中,~ 是按位取反的符号,而 ! 是逻辑取反符号(如果数不为零,则结果为非零,否则为零)。这一点需要特别注意,避免在编程中混淆这两个操作符的含义。

按位取反对数位数的影响非常明显,例如,0xAAAAAAAA 的按位取反结果就是 0x55555555。

位异或(^)

位异或操作符就是 ^,它的结果是两个对应位是否相同。如果相同,结果位为 0;不同,结果位为 1。例如,1 ^ 1 的结果是 0,1 ^ 0 的结果是 1。

位与、位或、位异或的特点总结

  • 位与:保留所有为 1 的位,其他位为 0。
  • 位或:保留所有为 1 的位,其他位为 1。
  • 位异或:结果为两者对应位的异或结果。

这些操作符在各种场景下都有不同的应用,下面我们将进一步探讨如何使用这些操作符来操作寄存器。


寄存器操作的要求

在嵌入式开发中,寄存器操作是一项非常重要的任务。寄存器通常用来控制外设,例如 GPIO 控制器、定时器等。寄存器操作的特点是对特定位进行操作,而不影响其他位。

ARM 架构中,CPU 与外设寄存器之间是通过 Memory-Mapped IO 统一的,这意味着读写寄存器就是在读写内存。因此,操作寄存器实际上就是在操作硬件。

寄存器操作的注意事项

  • 寄存器的操作是整体的:在 ARM 架构中,寄存器的访问是基于 32 位的。如果我需要修改寄存器中的某些特定位,我必须读出整个寄存器的值,进行修改,然后再写回寄存器。这一操作虽然看起来效率不高,但由于寄存器操作可能会影响硬件状态,因此必须保证操作的准确性。
  • 读改写法:这是一个常用的方法。例如,为了改变寄存器中的某几个特定位为 1,而其他位保持不变,我可以先读出寄存器的当前值,然后在这个基础上修改特定的位,最后写回寄存器。

特定位清零、置 1、取反的方法

特定位清零的方法

要清零某个寄存器中的特定位而不影响其他位,可以构造一个掩码,然后与寄存器的当前值进行位与操作。例如,假设寄存器值是 0xAAAAAAAA,我们希望清零 bit8 ~ bit15,可以构造掩码 0xFFFF00FF,然后进行位与操作。

特定位置 1 的方法

类似地,要将某些特定位置为 1,可以构造一个掩码,然后与寄存器的当前值进行位或操作。例如,如果寄存器中 bit3 ~ bit7 为 0,我们希望它们变为 1,可以写一个掩码 0x1F << 3,然后进行位或操作。

特定位取反的方法

要取反某些特定位,可以使用位异或操作符 ^。例如,如果我们希望位8 ~ bit15 取反,只需要计算 0xFF << 8,然后用 ^ 运算符进行操作。


如何用位运算构建特定二进制数

在嵌入式开发中,经常需要构建特定的二进制数来进行寄存器操作。位运算提供了强大的工具,例如移位和取反,可以帮助我们轻松构建所需的数。

获取特定二进制位的方法

将特定的二进制位构造在一起并进行移位,可以轻松得到对应的数。例如,要构造一个只有 bit3 ~ bit7 为 1,其余位为 0 的数,可以使用 (0x1F << 3) 的方式。

构建缺少连续 1 的二进制数

对于那些特定的位缺少连续 1 的情况,可以通过构造位反数再取反来实现。例如,我们需要构造一个 bit4 ~ bit10 为 0,其余位为 1 的数。我们可以先构造 bit4 ~ bit10 为 1 的数,然后对其进行按位取反。


位运算的练习

让我来回顾一下位运算的应用场景:

  • 如果我需要将某个寄存器的特定位置为 1,可以使用位或操作。
  • 如果我需要清零特定位,可以使用位与操作。
  • 如果我需要对某些位进行取反,可以用位异或操作。

想要构建特定二进制数,可以结合移位和取反操作。


使用宏定义来完成位运算

在 C 语言中,可以通过宏定义来封装这些位运算,方便重复使用。例如,定义一些宏辅助函数来完成将特定位设为 1、清零、取反等操作。

宏定义示例

#define SET_NTH_BIT(x, n) (x | ((1U) << (n - 1)))
#define CLEAR_NTH_BIT(x, n) (x & ~((1U) << (n - 1)))

使用示例

  • SET_NTH_BIT(reg, 5) 用于将寄存器的第 5 位置为 1。
  • CLEAR_NTH_BIT(reg, 5) 用于清零寄存器的第 5 位。

截取寄存器的部分连续位

有时候,我们需要从寄存器中提取某些连续的位。例如,给定寄存器值 0x00001000,想截取 bit 5 ~ bit 7 的值,可以通过以下步骤:

  • 构造一个掩码:0x000000FF。
  • 使用位与操作提取目标位:0x00001000 & 0x000000FF = 0x00000000。
  • 右移目标位:0x00000000 >> 3 = 0x00000000。
  • 通过合理设计掩码,我们可以轻松截取寄存器中的特定位组合。


    结语

    以上就是关于位操作符和寄存器操作的全部内容。这些知识点不仅可以帮助你更好地理解内核开发和嵌入式系统的工作原理,还能让你在实际项目中 应用这些技巧。希望这篇文章能为你提供丰富的参考价值!

    转载地址:http://ykpuk.baihongyu.com/

    你可能感兴趣的文章
    MySQL 有什么优点?
    查看>>
    mysql 权限整理记录
    查看>>
    mysql 权限登录问题:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)
    查看>>
    MYSQL 查看最大连接数和修改最大连接数
    查看>>
    MySQL 查看有哪些表
    查看>>
    mysql 查看锁_阿里/美团/字节面试官必问的Mysql锁机制,你真的明白吗
    查看>>
    MySql 查询以逗号分隔的字符串的方法(正则)
    查看>>
    MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT 、分页查询的优化、合理使用连接、子查询的优化)(上)
    查看>>
    mysql 查询,正数降序排序,负数升序排序
    查看>>
    MySQL 树形结构 根据指定节点 获取其下属的所有子节点(包含路径上的枝干节点和叶子节点)...
    查看>>
    mysql 死锁 Deadlock found when trying to get lock; try restarting transaction
    查看>>
    mysql 死锁(先delete 后insert)日志分析
    查看>>
    MySQL 死锁了,怎么办?
    查看>>
    MySQL 深度分页性能急剧下降,该如何优化?
    查看>>
    MySQL 深度分页性能急剧下降,该如何优化?
    查看>>
    MySQL 添加列,修改列,删除列
    查看>>
    mysql 添加索引
    查看>>
    MySQL 添加索引,删除索引及其用法
    查看>>
    MySQL 用 limit 为什么会影响性能?
    查看>>
    MySQL 用 limit 为什么会影响性能?有什么优化方案?
    查看>>