Обработка несколько пинов в разных портах.

Shaman_2010
Offline
Зарегистрирован: 05.11.2018

Добрый день, уважаемые форумчане!

Прошу у Вас совета, кто знает, подскажите. Имеется 26 кнопок, которые подключены напрямую к ножкам МК Мега 2560. Вся проблема в том, что эти ножки расположены в разных портах. 

PA0,PA4,PC1,PC4,PC5,PC6,PC7,PD4,PD5,PE2,PE3,PF7,PG1,
PG2,PH2,PJ2,PJ3,PJ5,PK0,PK1,PK2,PK3,PK4,PK5,PK6,PL7

Существует ли какой-нибдуь красивый способ обработать такую конфигурацию кнопок? Если бы было матричное подключению, то проблем, собственно, бы и не было. Но как красиво обработать такой комплект? Может существуют какие-то макросы, которые позволят компактно вызвать процедуру опроса для каждого пина? Или создать свою таблицу (массив) соответствия пинов элементам таблицы (массива) и таким образом в цикле прогонять?

Заранее, спасибо!

С уважением.

Shaman_2010
Offline
Зарегистрирован: 05.11.2018

Я перефразирую вопрос.

Существует ли способ, грамотно пробежать по данным пинам, находящимся в разных группах, в цикле и вызвать для каждого функцию опроса?

Например в таком виде:

for(byte i = 0; i < 26; i++)  
  {
    if(isPressed(i)){    // i=0 -> PA0, i=1 -> PA4, i=2 -> PC1 и т.д.                 
      // если нажата...
    }
    else
    {
      // если нет...
    }
  }

Заранее, спасибо!

sadman41
Offline
Зарегистрирован: 19.10.2016

Способ с массивом пинов вполне нормальный, если ищется генерализованное решение.

Shaman_2010
Offline
Зарегистрирован: 05.11.2018

Спасибо за ответ! Я только-только начал изучать программирование МК, поэтому не судите строго. Решил реализовать при помощи макросов (никогда до этого их не использовал):

#define IS_PRESSED(PINx, PIN) !((PINx) & (1<<(PIN)))
#define CFG_BUTTONS_DDR(DDRx, PIN) ((DDR##DDRx) |= (1<<(PIN)))
#define CFG_BUTTONS_PORT(PORTx, PIN) ((PORT##PORTx) |= (1<<(PIN)))

#define BUTTONS_COUNT 26

byte butPorts[] = {'A', 'A', 'C', 'C', 'C', 'C', 'C', 'D', 'D', 'E', 'E', 'F', 'G', 'G', 'H', 'J', 'J', 'J', 'K', 'K', 'K', 'K', 'K', 'K', 'K', 'L'};
byte butPins [] = {0, 4, 1, 4, 5, 6, 7, 4, 5, 2, 3, 7, 1, 2, 2, 2, 3, 5, 0, 1, 2, 3, 4, 5, 6, 7};

void setup() {
cfgButtons();
}

void loop() {

}

void cfgButtons() {
for(byte i = 0; i < BUTTONS_COUNT; i++){
CFG_BUTTONS_DDR(butPorts[i], butPins[i]);
CFG_BUTTONS_PORT(butPorts[i], butPins[i]);
}
}

В результате компилятор выдает ошибку:

exit status 1
'DDRbutPorts' was not declared in this scope
 
Если я правильно понимаю, то он сращивает в макросе не так, как я предпологал. Он сращивает DDR с названием массива, а не с элементом массива, который я пытался передать в него. Подскажите, как правильно передать в макрос сам элемент массива? Вообще, возможно ли это?
 
Заранее, спасибо!
sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, вы с козырей-то не заходите. Поищите картинку с распиновкой Arduino Mega2560. Там увидите соответствие выводов МК сквозной нумерации Arduino. Вот эти номера в массив сгружайте и потом уже pinMode(pins[i], INPUT) / digitalRead(pins[i])...  Если этого не хватит, то уже к регистрам можно перейти. Например - хранить в массиве структур указатель на порт и битовую маску для доступа к конкретному выводу (в сущности Arduino так и делает).

А компилятор правильно ругается. ## - это не для рантайма, а для препроцессинга. Сначала решеточками строки в исходнике слепляются, а потом только уже начинается непосредственно компиляция. Ну и, естественно, что там слеплено - как функция/переменная не объявлено.

b707
Offline
Зарегистрирован: 26.05.2017

Shaman_2010, насколько я знаю, в Ардуино ИДЕ пины Мега обозначены целыми числами, типа 42 или 50. Почему бы просто не создать массив целых типа int или byte, без всяких PA1  и PB4?

Shaman_2010
Offline
Зарегистрирован: 05.11.2018

sadman41 пишет:

Ну, вы с козырей-то не заходите. Поищите картинку с распиновкой Arduino Mega2560. Там увидите соответствие выводов МК сквозной нумерации Arduino. Вот эти номера в массив сгружайте и потом уже pinMode(pins[i], INPUT) / digitalRead(pins[i])...  Если этого не хватит, то уже к регистрам можно перейти. Например - хранить в массиве структур указатель на порт и битовую маску для доступа к конкретному выводу (в сущности Arduino так и делает).

А компилятор правильно ругается. ## - это не для рантайма, а для препроцессинга. Сначала решеточками строки в исходнике слепляются, а потом только уже начинается непосредственно компиляция. Ну и, естественно, что там слеплено - как функция/переменная не объявлено.

Спасибо за ответ! Да, в том то и дело, что, по моему, не все пины, которые я привел выше, имеют сквозную нумерацию, поэтому я сразу перешел к работе с регистрами... И по макросам, да, я уже понял, что дал маху с ними, спасибо! )

b707 пишет:

Shaman_2010, насколько я знаю, в Ардуино ИДЕ пины Мега обозначены целыми числами, типа 42 или 50. Почему бы просто не создать массив целых типа int или byte, без всяких PA1  и PB4?

Дело в том, что не все пины имеют сквозную нумерацию Arduino. По моему...

Shaman_2010
Offline
Зарегистрирован: 05.11.2018

Решил задачу следующим образом:

#define BUTTONS_COUNT 26

volatile uint8_t *butDDR[] = {&DDRA, &DDRA, &DDRC, &DDRC, &DDRC, &DDRC, &DDRC, &DDRD, &DDRD, &DDRE, &DDRE, &DDRF, &DDRG, &DDRG, &DDRH, &DDRJ, &DDRJ, &DDRJ, &DDRK, &DDRK, &DDRK, &DDRK, &DDRK, &DDRK, &DDRK, &DDRL};
volatile uint8_t *butPORT[] = {&PORTA, &PORTA, &PORTC, &PORTC, &PORTC, &PORTC, &PORTC, &PORTD, &PORTD, &PORTE, &PORTE, &PORTF, &PORTG, &PORTG, &PORTH, &PORTJ, &PORTJ, &PORTJ, &PORTK, &PORTK, &PORTK, &PORTK, &PORTK, &PORTK, &PORTK, &PORTL};
volatile uint8_t *butPIN[] = {&PINA, &PINA, &PINC, &PINC, &PINC, &PINC, &PINC, &PIND, &PIND, &PINE, &PINE, &PINF, &PING, &PING, &PINH, &PINJ, &PINJ, &PINJ, &PINK, &PINK, &PINK, &PINK, &PINK, &PINK, &PINK, &PINL};
byte butPins [] = {0, 4, 1, 4, 5, 6, 7, 4, 5, 2, 3, 7, 1, 2, 2, 2, 3, 5, 0, 1, 2, 3, 4, 5, 6, 7};

void setup() {
  Serial.begin(9600);
  cfgButtons();
}

void loop() {
  delay(1000);
  Serial.println(isButPressed(0));  
}

void cfgButtons() {
  for(byte i = 0; i < BUTTONS_COUNT; i++){
    (*(butDDR[i])) |= (1 << butPins[i]);
    (*(butPORT[i])) |= (1 << butPins[i]);
  }
}

bool isButPressed(byte butNum) {
  if(butNum >= BUTTONS_COUNT) {return false;}
  return ((*(butPIN[butNum])) & (1 << butPins[butNum])) ? false : true;
}

Громоздко выглядит, конечно, но работает. Надо будет и правда подумать на счет структур. Если есть советы по улучшению - буду признателен!

Заранее спасибо!