17
18
19
20
21
22
23
24
25
26
27
register8_t reserved_0x0E;
register8_t reserved_0x0F;
register8_t PIN0CTRL; /* Pin 0 Control Register */
register8_t PIN1CTRL; /* Pin 1 Control Register */
register8_t PIN2CTRL; /* Pin 2 Control Register */
register8_t PIN3CTRL; /* Pin 3 Control Register */
register8_t PIN4CTRL; /* Pin 4 Control Register */
register8_t PIN5CTRL; /* Pin 5 Control Register */
register8_t PIN6CTRL; /* Pin 6 Control Register */
register8_t PIN7CTRL; /* Pin 7 Control Register */
} PORT_t;
Чтобы изолировать класс Pin от конкретной реализации портов ввода-вывода
введём дополнительный уровень абстракции. Добавление нового уровня
абстракции вовсе не обязательно влечёт за собой какие-то накладные
расходы.
С классом описывающим порт ввода-вывода у нас возникает та-же проблема,
что и с классом Pin: как связать класс с конкретными регистрами? Можно
конечно попытаться сделать это с помощью перечислений и частичной
специализации, но в данном случае это всё-таки лучше сделать с помощью
препроцессора:
1
2
3
4
#define MAKE_PORT(portName, ddrName, pinName, className, ID) \
class className{\
...
};
Теперь объявим портов на все случаи жизни:
1
2
3
4
5
6
7
#ifdef PORTA
MAKE_PORT(PORTA, DDRA, PINA, Porta, 'A')
#endif
...
#ifdef PORT
MAKE_PORT(PORTR, DDRR, PINR, Portr, 'R')
#endif
Проанализировав реализацию портов ввода-вывода различных семейств МК
составим минимальный интерфейс для эффективного управления портами
(управление режимами подтяжки пока опустим):
1 // Псевдоним для типа данных порта.