我有两个屏蔽,方便(即没有引脚冲突)共享一个端口,我需要能够操作端口上的一些引脚。但是我无法确定我是否正在操作引脚,我只是想根据需要任意设置它们,即在一次操作中我可能会将某些引脚打开而某些引脚关闭。
我知道:
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而不修改低位,因为按位AND与ZERO。我相信这会留下0-3,就像之前设定的一样。
反转此值并将其与现有端口值进行“与”运算将确保这些引脚处于关闭状态并保持其他位不变。我确定这条线不是必需的,为了安全起见我在这里:)
我已将评论留在下面的代码中,以便您尝试了解我在做什么。
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并保持顶部半字节不变。由于我们知道底部半字节是ZERO(从早期的移位),我们可以简单地添加0x0F。 XOR实现了同样的目标。
对于最终的AND操作,我们需要关闭顶部半字节ZERO。因此,没有补充。
我对@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)
对于长篇文章感到抱歉,但我认为这是一个更好的解决方案,尽管它确实使用了另一个变量。
答案 0 :(得分:0)
您和RELAYPORT
的操作会清除高4位。你不应该执行早期的xor操作,而应该只使用补码。
RELAYPORT &= ~stack;
答案 1 :(得分:0)
一些想法......基于我对megaAVR的体验(特别是AT90USB1287)
当您分割端口并将某些位作为输入操作而某些位作为输出时,我建议在写入整个输出端口时要格外小心。 AVR中有很好的BIT指令。如果要编写完整的端口,请记住,写入配置为输入的位会产生影响,即激活(PORTxy<-1
)或取消激活(PORTxy<-0
)内部上拉电阻 - 因此,根据您的硬件,您必须选择用于“不需要”的位(另一个依赖于MCUCR(PUD)。换句话说,寄存器中的(要忽略的)输入位写出不能包含任何随机值,但恰好包含支持内部上拉配置的值。在写入(部分)到端口之前读取PINx
是没有用的。(这用于具有端口硬件的旧处理器比AVR处理器更精细)
在回读PORTx
之前写出NOP
插入PINx
时(由于内部锁定)。
在initRelays()
中我使用常量,因为它编译得更快(单指令)而不是RELAYDDR
的函数,这涉及将RELAYDDR
读回寄存器并写入寄存器到RELAYPORT
。