【问题标题】:In Arduino, how do you write to port when port is a variable?在 Arduino 中,当端口是变量时,如何写入端口?
【发布时间】:2017-01-01 10:01:13
【问题描述】:

写入端口的示例似乎总是使用端口号作为常量,例如,

OCR2A = 180;

当端口在运行时未知时,如何写入端口。例如,

int 端口 = (buttonPressed) ? 0x3b:0x3c; 端口写入(端口,180);

我找不到函数portWrite()。有这样的东西吗?

【问题讨论】:

标签: arduino embedded


【解决方案1】:

罗伯特的回答有一些不准确的断言和不完整的答案。

直接写入端口寄存器可能会破坏端口的其他设置,有时还会对控制器造成永久性损坏。

可能会破坏其他设置:确实,您必须知道自己在做什么(例如,您正在操作的端口上有哪些引脚,并且知道您要保留哪些功能。

可能造成永久性损坏:不是真的,或者最好不是因为端口操纵。如果将短路接地,然后将其设置为输出为 1,则无论您使用的是端口寄存器还是数字写入器,都可能会损坏它。你必须在这两个方面都小心。

现在,回到您的问题,枚举是一种方式,但由于 PORTB、PORTC、PORTD 只是值的简称,您可以设置一个变量,然后使用它来间接访问它。

这种变量的类型是一个指向字节的 volatile 指针(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 位)而不是设置整个端口;通过这种方式,您可以最大限度地减少搞砸其他事情的风险。上面的代码中已经包含了这个编辑,所以代码是正确的

【讨论】:

  • 确实是更好的答案。要破坏可能更少的设置,您可以使用 DDRC 寄存器。在您的示例中分配 myportreg 时需要保存其状态,并在实际写入端口时使用该值。
  • @RobertNavado 我同意你使用端口 C,但通常当我必须使用端口操作时是因为我需要 8 位。我不明白您的意思是“在分配时保存其状态并在写入时使用值”。
  • 您可能不想使用所有可用位,并且并非所有软件包都包含每个端口的所有 8 位。零件的配置可能不同。有时您需要同时设置 3 位,而数字位写入太慢。我可以找到几个原因。每个端口都有 DDRx 寄存器,您可以使用它来确保安全。你不必。恕我直言,通用和完整的答案应该考虑到这一点。
  • @RobertNavado 您可以将 DDRx 寄存器用于... 什么? DDRx 寄存器用于设置方向(字节中的每个 1 是设置为输出的引脚,每个 0 是输入)。我将代码更改为仅设置所需的引脚方向,而不是整个端口,但您不能使用 DDRx 寄存器作为 PORTx 的替代或“更安全版本”。我同意你应该只使用你需要的引脚,我将在答案中指定它,但这是你的意思吗?
  • @RobertNavado 好的,我修改了代码以反映这一点(这是完全合理的:只修改你使用的)。谢谢
【解决方案2】:

端口在一个特定的寄存器中。如果您知道该特定寄存器中的寄存器和端口的位置,您可以试试这个:

register = (1<<port) || register

将端口设置为 1 和

register = (1<<port)^-1 && register

将端口设置为 0。

当然,在给定端口名称的情况下,您将需要一个开关来确定寄存器和寄存器中的端口位。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多