【发布时间】:2014-01-12 06:55:13
【问题描述】:
我有两个方便的屏蔽(即没有引脚冲突)共享一个端口,我需要能够仅操作端口上的一些引脚。但是我不能确定我是在打开还是关闭引脚,我只是想在需要时任意设置它们,即在一次操作中我可能会打开一些引脚和关闭一些引脚。
我知道:
PORTX |= B11110000 // turns on bits 4-7
PORTX &= B11000011 // turns off bits 2-5
PORTX ^= B00111111 // toggles bits 0-5
我的挑战是只打开和关闭一些引脚,而其他引脚保持不变。
我已经达到了预期的结果,并且就我认为我以安全的方式完成它而言,我想确认它实际上是安全的,并且我是否以正确(最佳)的方式进行了处理,或者我能以更简单的方式实现这一目标吗?
首先,我使用的是 PORTD,引脚 4-7。我将这些引脚设置为输出,然后将它们全部设置为低电平,以确保我的程序从它们(4x 继电器)全部关闭开始。
void initRelays(){
RELAYDDR |= B11110000;
RELAYPORT &= ~RELAYDDR;
}
我相信 tis 会在不修改低位的情况下将引脚 4-7 设置为关闭,因为按位与为零。我相信这将保留之前设置的 0-3 位。
将此值取反并将其与现有端口值进行与运算,将确保这些引脚处于关闭状态,而其他位保持不变。我确定这条线不是必需的,为了安全起见,我把它放在这里:)
我在下面的代码中留下了 cmets,以便您尝试了解我在做什么。
void relayPush(byte stack){
// stack has bit 1 to relay 1 (pin 4), thru bit 4 to relay 4 (pin 7)
// take stack and isolate the four bottom bits (the information we want to convert)
stack &= B00001111; // (1) I think this line is probably not required
// now shift to the position we need
stack <<= 4; // (2)
// OR the new stack with the PORT
// (this turns on any relays set in stack)
RELAYPORT |= stack; // (3)
// we need to NOT modify the bottom bits of the port
// mark those with a '1' so as to not turn them off
// bottom of stack mask = 0x0f
// XOR stack and mask
stack ^= 0x0f; // (4)
// AND new stack and port to turn off appropriate relays
RELAYPORT &= stack; // (5)
}
我知道我已经在两个 PORT 操作中完成了它,我可以通过使用临时变量来完成它,这不是主要问题,因为它只是在第一个实例中打开所有需要打开的东西,然后关闭所有东西这在第二种情况下是必需的。
是否错过了一种更简单的方法?
编辑:我看过@Ignacio 所说的关于更改最终操作的内容,这就是我想出的:
0011 0011 current port assignment
xxxx 1010 current stack assignment (we only want the lower nibble)
1010 0011 desired result
0011 0011 current port
xxxx 1010 current stack
0000 1111 step 1 - apply this mask to stack
0000 1010 resultant stack
1010 0000 step 2 - stack << 4
0011 0011 PORT
1010 0000 STACK
1010 0011 step 3 - resultant PORT (port OR stack)
0000 1111 (MASK for step 4)
1010 0000 stack at step 4
1010 1111 step 4 - resultant stack (mask XOR stack)
1010 0011 port from step 3
1010 1111 stack from step 4
1010 0011 port AND stack (desired result)
/// changing steps 4 and 5 to drop XOR, and applying complement
1010 0000 stack prior to step 4
0101 1111 ~stack
1010 0011 port from step 3
0000 0011 stack AND port (not the desired result)
总结:
需要 XOR 将底部半字节填充到 B00001111 并保持顶部半字节不变。因为我们知道底部半字节是零(来自之前的移位),我们可以简单地添加 0x0F。 XOR 实现了同样的目的。
对于最终的 AND 操作,我们需要关闭顶部半字节零。因此,没有补充。
我对@Ignacio 的评论中的新想法:
0011 0011 current port
xxxx 1010 current stack
1010 0000 shifted stack
0000 0011 temp = port AND 0x0F
1010 0011 stack OR temp (desired result)
抱歉,这篇文章很长,但我认为这是一个更好的解决方案,尽管它确实使用了另一个变量。
【问题讨论】:
-
Arduino UNO - ATMega328P
标签: arduino bit-manipulation avr