在本教程中,我们将学习嵌入式编程中的一个重要概念,即位操作或位级操作。C编程语言中的位操作符是这些操作的基础。我将向您展示如何在微控制器编程中使用位操作符进行简单的位操作。
重要提示:在微控制器编程中,使用位运算符需要具备二进制和十六进制的先验知识。
简介
如果你熟悉微控制器,那么你可能知道微控制器编程中的位操作符。在一个8位单片机8051例如,一组8个引脚组合成一个端口。将引脚分组到端口的原因是为了使编程更容易,因为您可以在端口级别上操作8个引脚。
但是如果你想控制一个端口的单个引脚呢?然后你必须在微控制器编程中使用位运算符。使用六个位操作符,您可以执行一些重要的位操作,如设置位、清除位、切换位、测试位、提取位和监控位。
位运算符基础
现在,让我们开始了解一些位运算符的基础知识。顾名思义,位运算符用于在位级别操作数据。位运算符可以用于整数,不能应用于其他数据类型,如float或double(至少不能直接应用)。
十进制整数被转换为二进制,即1和0的序列,位运算符从LSB(最右边的最低有效位)开始逐位运算,直到MSB(最左边的最高有效位)。
不同类型的位运算符
基本上,位运算符有六种类型。它们是:
- 按位或-用' | '表示
- 位与-用“&”表示
- 位XOR -用' ^ '表示
- 位NOT -用' ~ '表示
- 按位右移-用' >> '表示
- 按位左移-用' << '表示
在详细了解这些操作符之前,让我们快速看一下按位的AND、OR和XOR操作符的真值表。下表显示了具有两个操作数的按位AND、OR和XOR操作符的真值表。
OP1 | 《凤凰社》第2章 | Op1 | op2(或) | Op1和op2(和) | Op1 ^ op2 (xor) |
0 |
0 | 0 | 0 | 0 |
0 |
1 | 1 | 0 | 1 |
1 |
0 | 1 | 0 | 1 |
1 |
1 | 1 | 1 | 0 |
现在让我们仔细看看嵌入式C编程中使用的所有六种位运算符。
位或- '|”
位或用符号'表示。|”。当任何位与1 oror时,位或的结果为' 1 ',而位或的结果与位与0 oror时的结果相同。考虑两个4位数A = 1100和B = 1001。这两个数的位或值如下:
一些位置- > |
3. | 2 | 1 | 0 |
一个= 1100 |
1 | 1 | 0 | 0 |
B = 1001 |
1 | 0 | 0 | 1 |
一个|B |
1 | 1 | 0 | 1 |
一个数字的LSB中的每个位都与另一个数字中的相应位是or。例如,0thA的位是0thB的位是1。0 | 1 = 1。这必须对所有位重复。
位和- '&”
位的AND由符号“&”表示。仅当两个操作数都为1时,位与运算的结果为' 1 '。否则,按位AND的结果为0。考虑前面例子中相同的两个4位数,即A = 1100和B = 1001。这两个数字的与位分别为:
一个= 1100 |
1 | 1 | 0 | 0 |
B = 1001 |
1 | 0 | 0 | 1 |
A和B |
1 | 0 | 0 | 0 |
位异或- '^”
位XOR是Exclusive OR的缩写,用符号“^”表示。位异或是单片机编程中的一个重要运算符。
当一个位的XORed和0,那么结果等于位本身,即,如果0是XORed和0,那么结果是0,如果1是XORed和0,那么结果是1。
当一个位的XORed和1,那么结果是切换的,例如,如果0是XORed和1,那么结果是1,如果1是XORed和1,那么结果是0。
考虑前面例子中相同的两个4位数,即A = 1100和B = 1001。这两个数的位异或如下:
一个= 1100 |
1 | 1 | 0 | 0 |
B = 1001 |
1 | 0 | 0 | 1 |
A ^ |
0 | 1 | 0 | 1 |
位NOT——”~”
按位NOT由符号' ~ '表示,是串中唯一的一元按位操作符,即它只需要一个操作数(而所有其他的按位操作符都需要两个操作数)。
位NOT运算符也称为否定或补充。因为它是一元运算符,所以0的位NOT为1,1的位NOT为0。
现在,考虑一个4位数a = 1011。这个数字的位NOT是0100。
一个= 1011 |
1 | 0 | 1 | 1 |
~一个 |
0 | 1 | 0 | 0 |
按位移位操作符(左移' << '和右移' >> ')
最后,有两个移位操作符,即左移位和右移位,它们分别用' << '和' >> '表示。首先让我们理解左移算符。左移操作表示如下:
操作数< < n
这意味着将'操作数'的位向左移动' n '指定的位数。最左边的' n '位将被丢弃,而' n '个零将被添加到右边。例如,考虑下面的例子。
11101100 << 2将导致10110000
类似地,右移运算表示如下:
操作数> > n
考虑下面的右移例子。
10010111 >> 4将产生00001001
微控制器编程中的位运算符
现在我们已经了解了C语言中的位运算符,现在让我们了解如何在微控制器编程中使用这些位运算符。为了演示的目的,我使用一个8位微控制器作为例子。但同样的实现也可以应用于32位微控制器。
在使用微控制器时,我们经常修改、读取和更新它的寄存器。但是直接给寄存器赋值是一个不好的做法。例如,如果你记得在8051,有一个SFR称为IE(中断启用的缩写)寄存器。
单个中断可以通过设置或清除IE SFR中的位来启用或禁用。我们必须以这样一种方式执行这个操作,即只有选定的位必须受到影响,而所有其他位必须保持其预期状态。位操作在这种情况下非常有用。让我来解释一些我们在微控制器编程中实现的常见的位操作。
设置一些
第一个操作是设置位,即使位为1。例如,考虑以下名为REG的8位数据。
REG = 10001111
如果我们想设置6th位,然后我们可以简单地执行以下操作。
首先,左移1 * 6,即1 << 6。这将导致01000000。现在将这个值与REG的值OR并将它赋值给REG。
Reg = Reg | 01000000;
REG的最终值是11001111。以上操作可以在一行中实现,如下所示:
Reg = Reg | (1 << 6);
或者简化为
Reg | = (1 << 6);//设置位6
通过这种方式,我们可以在不干扰其他位的情况下设置所需的位。
清理一点
现在,假设你想清空5thREG = 10110000。首先,左移1 * 5,即1 << 5。结果是00100000。现在,对该值执行按位NOT操作。
~(00100000) = 11011111。
最后,在这个值和REG的值之间按位执行AND(&)操作。
Reg &(11011111) = 10110000 & 11011111 = 100100000。只有5th清除。整个操作可以在一行中实现,如下所示:
Reg & = ~ (1 << 5);//清除位5
系紧一点
现在,让我们看一个切换位的例子,例如,如果位为0,则将其设为1,如果位为1,则设为0。如果您还记得按位异或操作符,则可以使用该操作符执行此任务。
考虑REG的值为00110010。现在,如果你想切换4th位,然后简单地异或4th用1。为此,首先左移1 * 4,即1 << 4,然后用REG进行异或。
Reg ^ = (1 << 4);//切换位4
以上三个按位操作与位操作相关,即位是设置、清除或切换的。后面的三个操作与比特的状态有关,不修改比特。
测试有点
现在,考虑这样一种情况,你需要根据位的值执行一些操作,例如,如果位是0,那么执行一组指令,如果位是1,那么执行另一组指令。在这里,我们实际上是在测试位的值。
if (REG & (1 << 5) != 0)
{
...
...
}
在上面的例子中,if语句只在5thREG的位为1。
提取一点
使用与测试位类似的方法,我们可以从数据中提取一个位或一组位。例如,设REG = 11010101。现在,如果您想提取位置上的单个位,例如3。
然后,我们可以提取3理查德·道金斯位转换为另一个变量(让我们称为EXTD),如下所示。
Extd = reg & (1 << 3);
现在,如果我们想提取一组比特,比如从3到6。首先,我们要屏蔽3到6的比特。因此,掩码值为01111000。
然后,我们可以使用两种方法提取所需的比特。
方法我
Extd = (reg & 01111000) >> 3;
方法二
Extd = (reg >> 3) & 1111;
监控一点
在微控制器编程中通常使用的最后一个按位操作是位监控。这在嵌入式编程中是非常重要的,因为我们经常需要检查或监视微控制器寄存器中某些位的状态。例如,中断标志位,通常是由硬件设置的,必须被监视并与ISR执行一起进行。
如果您想要监视一点,则输入3理查德·道金斯位从0变为1,那么可以使用以下代码。
while (REG & (1 << 3))
{
...
...
}
类似地,如果您想监视3中从1到0的变化理查德·道金斯位,然后可以使用以下代码。
while (~(REG & (1 << 3)))
{
...
...
}
结论
在本教程中,我们已经了解了位运算符的基础知识,也了解了如何在微控制器编程中使用这些位运算符。嵌入式编程中的位操作提供了一种快速获取结果的方法,并提高了代码的性能(这是通过硬件实现的)。在您的嵌入式应用程序中尽可能频繁地使用这些位操作。
2反应
多么伟大的位运算符文章啊!!这解释得很好。
我一直在找这个,现在我找到了。太棒了!