资讯专栏INFORMATION COLUMN

【STM32】位操作、按位与、按位或、按位异或、取反、左移、右移等基础 C 语言知识补充

waruqi / 4922人阅读

摘要:总结对于原二进制数来说,是不变,是反转。的位数对应原二进制数的位数,对各位进行屏蔽,全部置。左移左移与右移比较类似,是将目标二进制数字向左右移动相应的位数。语言中的逻辑运算符按位与,按位或,按位异或,取反,左右移位不完全手册立创开源

1 位操作

运算符含义
&按位与
按位或
^按位异或
~取反
<<左移
>>右移

c 语言中存在以上 6 个位操作运算符,且它们只能用于整形操作数。

总结:对于原二进制数来说,&0是屏蔽,&1是不变。

总结:对于原二进制数来说,|0是不变,|1是置1。

总结:对于原二进制数来说,^0是不变,^1是反转。


1.1 按位与

按位与的定义是:同一二进制位上的数字都是1的话,& 的结果为1,否则为0。

运算结果
0 & 00
0 & 10
1 & 00
1 & 11

根据这个特性,& 操作常常用来屏蔽特定的二进制位。

例如:0000 1111 & 0000 0011 = 0000 0011

与运算0 0 0 0 1 1 1 1
&0 0 0 0 0 0 1 1
结果0 0 0 0 0 0 1 1

可以看见,1111的前两位被屏蔽成为0了。

所以如果想清空数据,只需要将原二进制数与上 &0 就可以了。0的位数对应原二进制数的位数,对各位进行屏蔽,全部置0。

相对的,&可以利用0来屏蔽,也可以用1来读取。

例如: 一个二进制数 1101 1001,我只想要它的后四位,怎么办呢?

只需要进行如下操作:1101 1001 & 0000 1111即可。

与运算1 1 0 1 1 0 0 1
&0 0 0 0 1 1 1 1
结果0 0 0 0 1 0 0 1

其实该方法是屏蔽和读取的结合,&0保证消除无用位,&1保证有用数据的完整性。

总结:对于原二进制数来说,&0是屏蔽,&1是不变。


1.2 按位或

定义:只要参与运算的双方其中有一个是1,结果就是1.同0才为0。

运算结果
0 | 00
0 | 11
1 | 01
1 | 11

主要用作将某些特定位置1。

例如:1010 0000 | 0000 1111 = 1010 1111。

或运算1 0 1 0 0 0 0 0
0 0 0 0 1 1 1 1
结果1 0 1 0 1 1 1 1

总结:对于原二进制数来说,|0是不变,|1是置1。


1.3 按位异或

只要参与运算的双方互异,结果就为1,否则为0。

运算结果
0 ^ 00
0 ^ 11
1 ^ 01
1 ^ 10

可以通过上面的定义看到,一个数^1 的话就会0变成1,1变成0,而^0则不对原数进行改变。所以根据此特性可以对特定位进行0 1 反转。

例如: 1100 1100 ^ 0000 1100 = 1100 0000。

异或运算1 1 0 0 1 1 0 0
^0 0 0 0 1 1 0 0
结果1 1 0 0 0 0 0 0

同样的,如果对一个数进行^0,代表保留原值。

总结:对于原二进制数来说,^0是不变,^1是反转。


1.4 取反

对一个二进制数进行取反。1变0,0变1。

唯一需要注意的一点是,~的优先级是逻辑运算符中最高的,必须优先计算。


1.5 左移

左移与右移比较类似,是将目标二进制数字向左/右移动相应的位数。

左移补0:1111 1111 << 1 == 1111 1110,换算十进制的话是原来数值的2倍。

左移1 1 1 1 1 1 1 1
<<1
结果1 1 1 1 1 1 1 0

1.6 右移

右移看情况:负数补1,正数补0。需要看符号位。同样,换算为十进制数值变为原来的1/2.

右移1 1 1 1 1 1 1 1
>>1
结果0 1 1 1 1 1 1 1

总结:左乘右除。


2 单片机中常用操作

2.1 不改变其他位时,对某几个位设定值

比如要改变 GPIOA 的状态,可以先对寄存器的值进行 & 清零操作

GPIOA -> CRL &= 0XFFFFFF0F;		// 将第 4-7 位清 0

然后再与需要设置的值进行 或运算

GPIOA -> CRL |= 0X00000040;		// 设置相应位的值,且不改变其他位的值

2.2 移位操作提高代码可读性

以固件库的 GPIO 初始化的函数里一行代码为例

GPIOx -> BSRR = (((uint32_t)0x01) << pinpos);

这个操作就是将 BSRR 寄存器的第 pinpos 位设置为 1。
为什么要通过左移而不是直接设定呢?其实,这是为了提高代码的可读性以及可重用性。这行代码可以直观明了的知道,是将第 pinpos 位设置为 1。

如果写成

GPIOx -> BSRR = 0x0030;

这样的代码就不容易看出,也不好重用了。

类似的代码还有:

GPIOA -> ORT |= 1<<5;		// PA.5 输出高,不改变其他位

这样我们一目了然,5 告诉我们是第 5 位也就是第 6 个端口,1 告诉我们是设置成了 1。

2.3 取反操作使用技巧

SR 寄存器的每一位都代表一个状态,某个时刻我们希望去设置某一位的值为 0,同时其他位都保留位 1,简单的作法是直接给寄存器设置一个值:

TIMx -> SR = 0xFFF7;

这样做法可读性交较差。

看看库函数中代码是如何使用的:

TIMx -> SR = (uint16_t)~TIM_FLAG;

而 TIM_FLAG 是通过宏定义完成的值:

#define TIM_FLAG_Update		((uint16_t)0x0001)#define TIM_FLAG_CC1		((uint16_t)0x0002)

看这个就容易明白,可以直接从宏定义重看出 TIM_FLAG_Update 就是设置的第 0 位了,可读性较强。


Ref: C语言中的逻辑运算符:按位与,按位或,按位异或,取反,左右移位
Ref: STM32 不完全手册 - 立创开源

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/120808.html

相关文章

  • 浅谈JavaScript操作

    摘要:有符号的右移操作符由两个大于符号表示这个操作符的含义就是将数值的位向右移指定的位数同时保留符号位的值正负号标记有符号的右移操作符与左移操作符刚好相反比如向右移动位就是同样的在移位的过程中也会出 位操作符的基本概念 因为ECMAscript中所有数值都是以IEEE-75464格式存储,所以才会诞生了位操作符的概念. 位操作符作用于最基本的层次上,因为数值按位存储,所以位操作符的作用也就是...

    fasss 评论0 收藏0
  • 由left-pad扯到JS中的运算

    摘要:原码补码和反码原码一个数在计算机中是以二进制的形式存在的,其中第一位存放符号正数为负数为。中的位运算在中按位操作符会将其操作数转成补码形式的有符号位整数。原文链接由扯到中的位运算 这个话题的由来是2016年3月份的时候 NPM 社区发生了‘left-pad’事件,不久后社区就有人发布了用来补救的,也是现在大家能用到的 left-pad 库。 最开始这个库的代码是这样的。 module....

    LeoHsiun 评论0 收藏0
  • 操作

    摘要:将任一数值与执行按位与操作,其结果都为。中应用判断奇偶性偶数奇数按位异或规则每一位都不同,结果才为将任一数值与进行异或操作,其结果为。 位运算在算法中很有用,速度可以比四则运算快很多。 To2orTo10 JS中十进制转二进制: (val).toString(2)JS中二进制转十进制: parseInt(val, 2) JS中规定安全整数的范围是-2^53~2^53,所以大于90071...

    caiyongji 评论0 收藏0
  • 请回答c语言-操作符【入门】

    摘要:操作符的两个操作数必须为整数。函数调用用作为函数调用操作符。访问一个结构的成员结构体成员名结构体指针成员名还是熟悉的栗子在之前的博客请回答语言初识语言下入门的结构体出现过的栗子名字图鉴编号身高重量属性类型 ...

    frolc 评论0 收藏0
  • C语言基础操作符详解

    摘要:语言基础之操作符详解操作符的分类算术操作符移位操作符位操作符逻辑操作符逗号表达式表达式求值隐式类型转换算术转换操作符的属性今天就带各位大佬来了解一波语言的操作符。 ...

    snowell 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<