啊,有点操纵。学习开发嵌入式软件时的另一个经典。当我发现我可以保存在数组中的concatenate值时,这使我一生中的一半救了我。这是一件代码:
unsigned long UID = 0;
UID = (tempUID[0] << 24) | (tempUID[1] << 16) | (tempUID[2] << 8) | tempUID[3];
这是位操纵的一个例子。 Tempuid数组在每个索引中都有一个字节。为了使它们连接,您可以使用像这样的位操作。
我知道起初看起来很复杂。但是在这篇文章之后,您将完全知道这是如何工作和感觉的(这是我的情况):
什么是操纵?
位操纵是使用位操作员在数字或值中操纵单个位的过程。当您必须进行非常具体的操作时,它非常强大。
不应该与逻辑操作混淆,逻辑操作在布尔值(例如true/false)中。
。所以让我们直接进入它!
操作员
有六个不同的运算符,其中最后两个非常相似,可以进行点操作。这些是操作员:
和操作员(&)
按名称中的位和操作员,如果比较位均为“ 1”。
,将位设置为“ 1”。输入a | 输入b | 输出 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
此操作员用于位掩蔽。使用位掩盖,您可以选择要读取的特定位。这是一个示例:
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 |
此操作员经常使用多个值或连接值(为了串联,您也需要位移动)。
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操作员有许多不同的用例,例如使用键,切换或更改检测的加密。但是还有更多。我使用了Edge detection的变更检测。在此示例中,我们将要切换值:
value = value ^ 0xFF // 0xFF -> 11111111
“ 1”的每个值都会变成'0',因为1 XOR 1将导致0。
每个值的价值'0'都会变成'1',因为0 xor 1将导致1。
不是操作员(〜)
位不是操作员是最容易理解的操作员。它的作用与XOR上面的示例完全相同。它会倒转。语法非常简单。
输入 | 输出 |
---|---|
0 | 1 |
1 | 0 |
该操作员非常有用;例如,如果您需要初始化一个值倒置的值,则可以使用位非操作员。
value = 0xF0; // 0xF0 -> 11110000
value = ~value;
操作后,值为 00001111 。
左置操作员(<<)
现在有趣的开始。这些操作员正好做他们所谓的事情。他们转移了!您只需要指定该值应移动多少位。
如第一个示例中所述,这对于连接值非常有用。
value = 0x0F << 2; // 0x0F -> 00001111
您有2个输入此操作员。左侧的一个是需要移动的值,右侧指定需要移动多少位。因此,此示例的结果将是 00111100 。您还可以看到,从右侧推入的新位为“ 0”。这是默认的,不能更改。
右置操作员(>>)
右移的位操作员还会移动位。唯一的区别是它向右移动。
另外,该方法可用于串联值。它也派上用场。您可以将一个方向转移一个已知量的值。将其与其他操作员结合起来,使其非常强大。
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
所以,就是这样!当您第一次查看涉及位操纵的计算时,可能会令人困惑。但是,当您将整个过程分为步骤时,它变得更加可理解。
结局
感谢您的阅读!希望您从本文中学到新知识。该系列将很快继续发表有关构建固件的新文章。
随时在下面留下任何评论或问题,我会尽力帮助您!
愿您的代码无漏洞!