制作一个"虚拟端口",由Arduino上的多个端口组成

fel*_*unz 6 port microcontroller arduino arduino-c++

我开始在Arduino上使用端口,而不是手动将每个引脚设置为低电平或高电平.这非常有用且速度更快.我正在进行一个项目,我需要至少一个完整端口(8位)和至少一个串行端口.

我想使用Arduino UNO,但它只有一个完整的端口,端口D. PD0和PD1用于串行通信.这意味着我不能使用端口D.

我想知道是否有可能将多个端口合并为"虚拟端口".最后我想要这样的东西:

PORTX = 0b11111111; // the first 2 bits are PB0/PB1 and bit 3-8 are PD3-PD8
Run Code Online (Sandbox Code Playgroud)

这有可能吗?

Tom*_*ken 1

我会说“是”这是可能的,但可能不是你想要的方式(或者也许我只是不知道该怎么做^^)

首先,这些PORTS是来自 Atmel 的宏。您的 Arduino-Uno 基于 AtMega328p,因此使用 AVR 工具链以及所有PORTS底层工具。如果您要在没有 arduino-bootloader 和所有奇特的 arduino-library-stuff 的情况下对微控制器进行编程,您将通过这种方式对所有 GPIO 进行寻址。

如果您查看 Atmel-AVR 工具链(arduino 位于其顶部)的代码,您会发现它们PORTS是在微控制器内的内部 IO 寄存器中定义的iom328p.h,并且只是微控制器内的内部 IO 寄存器的地址。

因此,仅仅声明一个虚拟端口并不那么容易(也许使用一种类似于std::mmap()但我从未尝试过的内存映射)。

无论如何,你是一名程序员,所以几乎所有事情都有一个解决方案;)我个人建议,创建你自己的Port类:

  • 这个类保存您Pins作为成员所需的内容,并且您有一个设置器,它根据您传递给它的编号覆盖您的成员 Pin 图
  • (此代码并不意味着是“完美”的解决方案,只是快速提示方向)

我建议您继续使用 arduino-library 来实现这种方法。如果你用 plain 来做PORTS,你可能会在某个地方弄乱一些东西。因此,例如,如果您初始化 SerialPort 然后执行类似的操作PORTD |= (1<<PD0),您将无法接收任何数据并且不知道为什么。

class MyPort
{
private:
  uint8_t m_pin[8];
public:
  MyPort(uint8_t pins[8])
  {
    for(int i=0; i<8; ++i)
    {
      m_pin[i] = pins[i];       //copy from constructor-argument into member-variable
      pinMode(pins[i], OUTPUT); //setting pin as OUTPUT
    }
  }

  void operator =(uint8_t val)
  {
    for(int i=0; i<8; ++i)
    {
      digitalWrite(m_pin[i], (val >> i)&1);
    }
  }
};

//            B0,B1,D2,D3,D4,D5,D6,D7
//             v  v  v  v  v  v  v  v
uint8_t pins[]{8, 9, 2, 3, 4, 5, 6, 7};
MyPort PORTX(pins);

void setup()
{
  PORTX = 0b11001100;
}

void loop()
{
  // put your main code here, to run repeatedly:
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您也想在自己的端口上按位寻址,则还必须覆盖其他运算符