写入端口的示例似乎总是使用端口号作为常量,例如
OCR2A = 180;
如果端口未知,直到运行时如何写入端口。例如,
int port = (buttonPressed) ? 0x3b : 0x3c; portWrite( port, 180 );
我找不到的是功能portWrite()
。这样的事情存在吗?
答案 0 :(得分:3)
直接写入端口寄存器可能会破坏端口的其他设置,有时会对控制器造成永久性损坏。
可以破坏其他设置:是的,您必须知道自己在做什么(例如,您正在操作的端口上有哪些引脚,并且知道您要保留的功能。
可能造成永久性损坏:不是真的,或者更好,不是因为端口操纵。如果将短路接地并将其设置为1,则无论使用端口寄存器还是数字写入,都可能会损坏它。你必须要小心两种方式。
现在,回到你的问题,枚举是一种方式,但由于PORTB,PORTC,PORTD只是值的简称,你可以设置一个变量,然后用它间接访问它。
这种变量的类型是指向字节的易失性指针(volatile表示编译器无法优化写入和读取操作,因为即使在两次操作之间,值也会发生变化):
volatile uint8_t *variablePortRegister;
您只需要使用要更改的寄存器的地址(使用&
符号)加载它:
variablePortRegister = &PORTC;
然后使用指针更改值
PORTC = 0x12;
becomes
(*variablePortRegister) = 0x12;
这是一个简短的例子。要使其正常工作,请在arduino引脚5(PORTD的第5位)上连接带电阻的LED。电路板上的LED(标记为L)连接到引脚13(PORTB的第5位)。
草图将使两个LED中的一个闪烁五次,然后切换到另一个。只使用端口操作指令,您可以发现读取端口的方式与写入端口的方式相同。
volatile uint8_t *myportreg;
unsigned long lastTime;
uint8_t counter;
void setup() {
DDRB |= 0x20;
DDRD |= 0x20;
PORTB = 0;
PORTD = 0;
counter = 99; // trigger the register change immediately
}
void loop() {
if (counter >= 10)
{
counter = 0;
if (myportreg == &PORTD)
myportreg = &PORTB;
else
myportreg = &PORTD;
}
if ((millis() - lastTime) > 500)
{
lastTime = millis();
// change bit 5 of register
*myportreg = 0x20 ^ (*myportreg);
counter++;
}
}
编辑:正如罗伯特指出的那样,只使用你需要的引脚(在这种情况下,端口B和D的第5位)而不是设置整个端口要好得多;通过这种方式,您可以最大限度地降低搞砸其他东西的风此编辑已包含在上面的代码中,因此代码正确
答案 1 :(得分:0)
端口位于一个特定的寄存器中。如果您知道该寄存器以及该特定寄存器中端口的位置,您可以尝试:
register = (1<<port) || register
将端口设置为1和
register = (1<<port)^-1 && register
将端口设置为0。
当然,您需要一个开关来确定寄存器和给定端口名称的寄存器中的端口位。
答案 2 :(得分:-1)
根据文档of port manipulation,不建议直接写入端口寄存器。虽然设置端口状态非常快,有时也很方便但危险。直接写入端口寄存器可能会破坏端口的其他设置,有时会对控制器造成永久性损坏。我认为行动的危险是这种功能缺失的主要原因。
至于具体问题,您需要在端口和寄存器之间实现自己的映射。例如:
typedef enum {
portB,
portC,
portD
} pm;
void portWrite(pm port, char value);
void foo() {
// your previous code here...
pm port = (buttonPressed) ? portD : portB;
portWrite(port, B00110011);
}
void portWrite(pm port, char value) {
switch (port) {
case portB:
PORTB=DDRB|value;
break;
case portC:
PORTC=DDRC|value;
break;
case portD:
PORTD=DDRD|value;
break;
}
}