Передача порта в качестве переменной — AVR

Можно ли использовать порт AVR в качестве переменной, которую можно передавать?

Например

LED myLed(PORTA,7);   //myLED hooked to PORTA, Pin 7

Я хотел бы, чтобы светодиод мог принимать любую комбинацию PORT / Pin, поэтому я бы не стал жестко кодировать ее.

Обратите внимание, что порты определены как:

#define PINA  _SFR_IO8(0x00)
#define DDRA  _SFR_IO8(0x01)
#define PORTA _SFR_IO8(0x02)

Символ PORTA разрешается в (* (volatile uint8_t *) ((0x02) + 0x20))

Я считаю, что это позволило бы мне сделать что-то вроде следующего, но я не уверен, понадобится ли мне ключевое слово volatile или нет, и будет ли оно работать так, как ожидалось

class LED{
public:
LED(volatile uint8_t* port, uint8_t pin);
{
Port=port;
Pin=pin;
}
void write(bool val)
{
if(val) (*Port) |= 1 << Pin;
else    (*Port) &= ~(1 << Pin);
}

private:
uint8_t  Pin
volatile uint8_t* Port;
}

Наконец, есть ли способ установить порт / вывод как выход из конструктора светодиодов?
Это будет связано с поиском относительного регистра DDR # для данного номера порта.
Могу ли я предположить &DDR # всегда будет &ПОРТ # -1?

4

Решение

Макросы регистров в основном являются указателями на область памяти, где находится соответствующий регистр, так что да, вы можете использовать uint8_t volatile *, Однако компилятор не будет генерировать наиболее эффективный код таким способом — он будет использовать косвенную адресацию вместо прямой записи.

Это то, что я делаю вместо этого, используя avrlib.

#include <avrlib/porta.hpp>
#include <avrlib/pin.hpp>
using namespace avrlib;

typedef pin<porta, 4> led_pin;

Тогда вы можете использовать led_pin typedef, например

led_pin::set();
5

Другие решения

Порты — это не что иное, как адреса ввода / вывода, поэтому все, что вам нужно сделать, это передать адрес порта ввода / вывода вашему конструктору LED:

LED *light = new LED(&PORTA, 4);

Почему это работает? PORTA разрешает, как вы уже упоминали, разыменование указателя:

(*(volatile uint8_t *)((0x02) + 0x20))

Таким образом, добавление адреса оператора впереди создает

&(*(volatile uint8_t *)((0x02) + 0x20))

который может быть упрощен до

(volatile uint8_t *)((0x02) + 0x20)
0