位和字节:开发人员的综合指南
#初学者 #教程 #c #嵌入式

啊,有点操纵。学习开发嵌入式软件时的另一个经典。当我发现我可以保存在数组中的concatenate值时,这使我一生中的一半救了我。这是一件代码:

unsigned long UID = 0;

UID = (tempUID[0] << 24) | (tempUID[1] << 16) | (tempUID[2] << 8) | tempUID[3];

这是位操纵的一个例子。 Tempuid数组在每个索引中都有一个字节。为了使它们连接,您可以使用像这样的位操作。

我知道起初看起来很复杂。但是在这篇文章之后,您将完全知道这是如何工作和感觉的(这是我的情况):

Feeling

什么是操纵?

位操纵是使用位操作员在数字或值中操纵单个位的过程。当您必须进行非常具体的操作时,它非常强大。

不应该与逻辑操作混淆,逻辑操作在布尔值(例如true/false)中。

所以让我们直接进入它!

操作员

有六个不同的运算符,其中最后两个非常相似,可以进行点操作。这些是操作员:

和操作员(&)

按名称中的位和操作员,如果比较位均为“ 1”。

,将位设置为“ 1”。

输入a 输入b 输出
0 0 0
0 1 0
1 0 0
1 1 1

AND Illustration

此操作员用于位掩蔽。使用位掩盖,您可以选择要读取的特定位。这是一个示例:

result = address & 0xF0 // 0xF0 -> 11110000b

使用此掩码(0xf0),右边的前四个位没有可能成为“ 1”的可能性,因为有了和操作员,这两个位都必须为'1'才能获得“ 1”。
因此,如果地址为 10100110 ,则结果将为 10100000

或操作员(|)

如果至少一个位是'1'。

,位或操作员将位设置为“ 1”。
输入a 输入b 输出
0 0 0
0 1 1
1 0 1
1 1 1

OR Illustration

此操作员经常使用多个值或连接值(为了串​​联,您也需要位移动)。

test |= 0x80 // 0x80 -> 10000000
test = test | 0x80 // same result

这将把变量“测试”的第8位设置为“ 1”,而不管“测试”的值如何。

XOR操作员( ^)

位XOR操作员是一个非常有趣的操作员。在我的previous article中,我提到该操作员可以非常强大。 XOR操作员将两个比较的位不相等,将设置为“ 1”。

输入a 输入b 输出
0 0 0
0 1 1
1 0 1
1 1 0

XOR Illustration

XOR操作员有许多不同的用例,例如使用键,切换或更改检测的加密。但是还有更多。我使用了Edge detection的变更检测。在此示例中,我们将要切换值:

value = value ^ 0xFF // 0xFF -> 11111111

“ 1”的每个值都会变成'0',因为1 XOR 1将导致0。

每个值的价值'0'都会变成'1',因为0 xor 1将导致1。

不是操作员(〜)

位不是操作员是最容易理解的操作员。它的作用与XOR上面的示例完全相同。它会倒转。语法非常简单。

输入 输出
0 1
1 0

NOT Illustration

该操作员非常有用;例如,如果您需要初始化一个值倒置的值,则可以使用位非操作员。

value = 0xF0; // 0xF0 -> 11110000

value = ~value;

操作后,值为 00001111

左置操作员(<<)

现在有趣的开始。这些操作员正好做他们所谓的事情。他们转移了!您只需要指定该值应移动多少位。

LEFTSHIFT Illustration

如第一个示例中所述,这对于连接值非常有用。

value = 0x0F << 2; // 0x0F -> 00001111

您有2个输入此操作员。左侧的一个是需要移动的值,右侧指定需要移动多少位。因此,此示例的结果将是 00111100 。您还可以看到,从右侧推入的新位为“ 0”。这是默认的,不能更改。

右置操作员(>>)

右移的位操作员还会移动位。唯一的区别是它向右移动。

RIGHTSHIFT Illustration

另外,该方法可用于串联值。它也派上用场。您可以将一个方向转移一个已知量的值。将其与其他操作员结合起来,使其非常强大。

value = 0x50 >> 2; // 0x50 -> 01010000

我认为您已经可以猜出结果了。如果我们将0x50(01010000)向右移动2,我们将获得 00010100

了解第一个例子

既然理论部分已经完成,我们应该能够理解我做出的位操作的第一个示例。目标是将它们共同串在一起,以获取一个包含所有其他值的值。

unsigned long UID = 0;

UID = (tempUID[0] << 24) | (tempUID[1] << 16) | (tempUID[2] << 8) | tempUID[3];

为了说明这一点,我们为每个数组索引分配一个值:

                    //  HEX     BIN
tempUID[0] = 0xA3;  //  0xA3    10100011
tempUID[1] = 0xFF;  //  0xFF    11111111
tempUID[2] = 0x67;  //  0x67    01100111
tempUID[3] = 0xF0;  //  0xF0    11110000

这个位操纵涉及两个步骤。第一步是移动值,第二步是使用或操作员组合它们。

我们需要按计算中给出的数字移动所有值:

tempUID[0]:     10100011 00000000 00000000 00000000 // shifted by 24
tempUID[1]:              11111111 00000000 00000000 // shifted by 16
tempUID[2]:                       01100111 00000000 // shifted by 8
tempUID[3]:                                11110000 // not shifted

第二步是使用或操作员组合它们:

UID = 10100011 11111111 01100111 11110000

所以,就是这样!当您第一次查看涉及位操纵的计算时,可能会令人困惑。但是,当您将整个过程分为步骤时,它变得更加可理解。

结局

感谢您的阅读!希望您从本文中学到新知识。该系列将很快继续发表有关构建固件的新文章。

随时在下面留下任何评论或问题,我会尽力帮助您!

愿您的代码无漏洞!