Можно ли получить, какой вывод сгенерировал прерывание?

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

Что-то вроде:

void ISREncoders()
{
  int pin = GetCurentInterruptPin(); // <============= это
  int dataPin = dataPins[pin];
  int data = DigitalRead(dataPin);
  if(data == HIGH)
  {
    encoders[pin] += 1;
  }
  else
  {
    encoders[pin] -= 1;
  }
}

Возможно ли это?


Как упоминалось в ответе, это невозможно. Тем не менее, после просмотра некоторых библиотек кодировщиков, использующих прерывание, выяснилось, что они делают следующее:

Класс Encoder содержит несколько жестко закодированных статических методов ISR.

Когда вы создаете новые объекты, он увеличивает внутренний счетчик и устанавливает правильный метод ISR для прерывания.

Это, безусловно, лучшее доступное решение, но оно совсем не масштабируемо, например, если у вас есть воображаемая плата с тысячей контактов, которая обрабатывает тысячи энкодеров, вам придется жестко закодировать каждый метод ISR.

, 👍2

Обсуждение

сохраните список состояний контактов прерывания ... сравните список при прерывании ... в любом случае, ваш вопрос - это общий вопрос программирования ... в вашем вопросе нет компонента Arduino, @jsotola

«два тактовых контакта находятся в ВЫСОКОМ состоянии»… в вашем мышлении есть ошибка (хотя и не связанная с вашим вопросом)… ваше мышление должно быть «переходом двух тактовых контактов из НИЗКОГО в ВЫСОКОЕ состояние (или наоборот)», @jsotola

я сказал сравнить список при прерывании... не опрашивайте постоянно... проверяйте состояние всех выводов при получении прерывания... в любом случае, аппаратно можно определить, какой вывод сгенерировал прерывание, но это будет зависеть от аппаратного обеспечения ... вы ничего не сказали об используемом аппаратном обеспечении, @jsotola


1 ответ


Лучший ответ:

2

Невозможно узнать, какое прерывание вызвало ISR. Флаг INTFx сбрасывается при вызове процедуры прерывания, поэтому вы теряете эту информацию (а это позор).

Самое близкое, что вы могли бы сделать, это иметь отдельный ISR для каждого вывода, который просто вызывает общую процедуру с параметром, указывающим, через какой ISR он был выполнен. Это добавит некоторую дополнительную задержку, поскольку он должен сделать дополнительный вызов функции, но это можно несколько смягчить, пометив общую функцию как always_inline, что означает, что компилятор продублирует ее и поместит в код, из которого он вызывается. Это уменьшает задержку, но увеличивает размер кода.

static ISREncoder(uint8_t pin) __attribute__ ((always_inline)) {
    // Делаем что-то с переменной `pin`
}

void ISR0() { ISREncoder(2); }
void ISR1() { ISREncoder(3); }
,