Решение AVR для чистого псевдонима контактов — перечисление битов ввода-вывода

Я работаю в C на устройстве Arduino, где контакты помечены по-разному. Я использую PLAIN C, а не «язык» Arduino.

Каждый вывод определяется своим портом (например, PORTB) и выводом (битом) в порту (например, PB0).

Я хотел бы кратко назвать контакты, чтобы я мог создавать макросы или функции, похожие на то, что использует Arduino:

pin_direction(D2, 1); // D2 as output
set_pin(D2, 0); // write zero to D2
pin_direction(D3, 0); // D3 as input
enable_pullup(D3, 1); // enable D3 pullup

Вместо этого (атм) я должен использовать что-то уродливое вроде этого:

#define D0 0
#define D1 1
#define D2 2
#define D3 3
...
#define D10 2
#define D11 3

#define PORT_D0 PORTD
#define PORT_D1 PORTD
#define PORT_D2 PORTD
#define PORT_D3 PORTD
...
#define PORT_D10 PORTB
#define PORT_D11 PORTB

// the same for PIN_xx and DDR_xx

И тогда я могу использовать макросы для выполнения работы:

#define sbi(port, bit) (port) |= _BV(bit)
#define cbi(port, bit) (port) &= ~ _BV(bit)

sbi(DDR_D2, D2); // D2 to output
cbi(PORT_D2, D2); // D2 to output
sbi(DDR_D3, D3); // D3 as input
sbi(PORT_D3, D3); // D3 pullup enable

Теперь это работает, но это очень грязно. Любая идея, как - без чудовищных накладных расходов на что-то вроде огромного switch - сделать это лучше - больше похоже на мой первый пример? Как-то перечислить все биты, а затем разрешить правильный регистр на лету?

Я использую avr-gcc с avr-libc.


person MightyPork    schedule 21.12.2014    source источник


Ответы (2)


Вот решение, которое я использую.

В моем util.h (общий для всех моих проектов AVR):

#define DDR_REG(port) DDR ## port
#define PORT_REG(port) PORT ## port
#define PIN_REG(port) PIN ## port

#define SET_BIT(port, bit) do { (port) |= (1 << (bit)); } while(0)
#define CLR_BIT(port, bit) do { (port) &= ~(1 << (bit)); } while(0)
#define BIT_IS_SET(port, bit) ((((uint8_t)(port)) >> ((uint8_t)(bit))) & 0x1)

#define IO_SET_INPUT_AUX(port, bit) CLR_BIT(DDR_REG(port), bit)
#define IO_SET_AS_INPUT(io) IO_SET_INPUT_AUX(io)

#define IO_SET_OUTPUT_AUX(port, bit) SET_BIT(DDR_REG(port), bit)
#define IO_SET_AS_OUTPUT(io) IO_SET_OUTPUT_AUX(io)

#define IO_OUTPUT_0_AUX(port, bit) CLR_BIT(PORT_REG(port), bit)
#define IO_OUTPUT_0(io) IO_OUTPUT_0_AUX(io)

#define IO_OUTPUT_1_AUX(port, bit) SET_BIT(PORT_REG(port), bit)
#define IO_OUTPUT_1(io) IO_OUTPUT_1_AUX(io)

#define IO_GET_INPUT_AUX(port, bit) BIT_IS_SET(PIN_REG(port), bit)
#define IO_GET_INPUT(io) IO_GET_INPUT_AUX(io)

В моем файле сопоставления выводов:

#define UPBTN_IO B,7
#define DOWNBTN_IO D,0
#define ENTERBTN_IO D,1
(etc)

В коде:

IO_SET_AS_INPUT(UPBTN_IO);

Это зависит от некоторых забавных битов препроцессора, например, есть только один раунд расширения макроса для параметров макроса.

person Sneftel    schedule 21.12.2014
comment
Это отлично, я немного настрою его и добавлю в свою библиотеку. Спасибо. - person MightyPork; 22.12.2014
comment
Если вам интересно, загляните на github.com /MightyPork/avr-projects/blob/master/devel/lib/pins.h (и файл calc.h). Это абсолютное счастье работать! - person MightyPork; 23.12.2014
comment
@MightyPork Очень мило. Ваше битовое тестирование / настройка более идиоматично, чем мое. Думаю, я украду вашу реализацию обратно. :-) - person Sneftel; 23.12.2014

Вы можете определить макросы, которые расширяются до нескольких токенов, например.

#define PIN_D0    PORTD, 0
#define PIN_D1    PORTD, 1
...
#define PIN_D10   PORTB, 2

Затем используйте их в макросах, таких как:

sbi(PIN_D0);  // expands to sbi(PORTD, 0)

Некоторые служебные макросы, которые могут быть полезны с этими макросами:

#define PORT_OF(port, bit) port
#define BIT_OF(port, bit)  bit

которые можно использовать в таких контекстах, как:

PORT_OF(PIN_D10)  // expands to PORTB
BIT_OF(PIN_D10)   // expands to 2
person Community    schedule 21.12.2014
comment
Это частично решает проблему, но, возможно, это самый чистый способ. Мне по-прежнему понадобятся три разных макроса для каждого контакта ввода-вывода (DDR, PORT, PIN) - person MightyPork; 21.12.2014
comment
Хм, как вы думаете, что вам все еще нужно несколько макросов? Дайте мне пример того, как они будут выглядеть - person ; 22.12.2014
comment
Другой бит для DDR, PORT и PIN-кода, связанный с одним выводом ввода-вывода. Но я думаю, это нормально. - person MightyPork; 22.12.2014