Используйте ISR внутри библиотеки более элегантно
В данный момент я пытаюсь создать библиотеку, которая использует attachInterrupt(?,?,RISING)
для чтения датчика. Статья Ника Гэммона о вызове ISR из класса мне очень помогла, но его "Склеивающие процедуры" становится довольно уродливым с более чем 30 потенциальными контактами прерывания на ESP32, которым нужен собственный static void
. У кого-нибудь есть более изящная идея, как сделать это "Склеивание"?
@Adrian Immer, 👍2
Обсуждение1 ответ
Лучший ответ:
Что касается эффективности, я бы посоветовал Крислу использовать
низкоуровневые прерывания платформы, если это вообще возможно. Это, однако, приходит
за счет переносимости: вам потребуется специализированная реализация
для каждой платформы, которую вы хотите поддерживать. Если вы не хотите или не можете
поддерживать весь этот специфичный для платформы код, attachInterrupt()
может быть
разумный вариант.
Тогда вам абсолютно необходимы все эти процедуры склеивания: поскольку система прерываний вызывает ваши обработчики без параметров, вы не будете возможность обмениваться обработчиками между прерываниями, и в итоге вы получаете столько обработчики прерываний, которые вы собираетесь использовать.
Однако существует элегантный способ создания всех этих специализированных функции, не записывая их явно: вы можете попросить компилятор напишите их для вас на основе предоставленного вами шаблона.
Ниже представлена версия кода примера Ника Гэммона, модифицированная для использования класс шаблона. Обратите внимание, что вам не обязательно нужен класс для использования шаблоны: вы можете использовать функции-шаблоны в качестве обработчиков прерываний, если который подходит для вашего варианта использования.
template <uint8_t pin>
class myClass
{
static volatile bool switchChanged;
public:
static void begin()
{
pinMode(pin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pin),
switchPressed, FALLING);
}
static void switchPressed()
{
switchChanged = true;
}
};
template <uint8_t pin>
volatile bool myClass<pin>::switchChanged;
myClass<2> foo;
myClass<3> bar;
void setup()
{
foo.begin();
bar.begin();
}
void loop(){}
Также обратите внимание, что myClass<2>
и myClass<3>
– это два разных класса:
на самом деле у вас есть разные классы для каждого вывода. Это значит, что
foo::switchChanged
и bar::switchChanged
— это два разных класса
элементы, хотя оба являются статическими
. Поскольку вы должны (в принципе)
иметь не более одного экземпляра каждого класса, специфичного для вывода, вы можете сделать
все в классе static
.
Главное предостережение этого метода заключается в том, что номера контактов теперь должны быть константы времени компиляции. Большим преимуществом является то, что у вас будет класс, созданный для каждого фактически используемого прерывания: нет необходимости в массив из 32 экземпляров на ESP32, если только несколько контактов прерывания будут фактически использоваться.
Большое спасибо! Это работает блестяще для меня. В основном я понял то же, что и вы, но остался один вопрос: почему мы должны инициализировать наш частный volatile bool myClass<pin>::switchChanged;
вне определения класса?, @Adrian Immer
Это не инициализация, это определение. Члены статического класса _декларируются_ в определении класса, но должны быть _определены_ вне его. В противном случае вы получите ошибку времени компоновки «_undefined ссылка на myClass<(unsigned char)2>::switchChanged
_» (и то же самое для myClass<3>
)., @Edgar Bonet
- Какие Arduino поддерживают ATOMIC_BLOCK?
- Прерывания внутри класса, связанные с функцией класса
- Как объявить указатель на библиотеку arduino neopixels, чтобы настроить его в функции настройки с помощью динамических переменных?
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Ошибка: "недопустимое использование нестатической функции-члена" при вызове функции из моего собственного класса-метода
- Почему необходимо использовать ключевое слово volatile для глобальных переменных при обработке прерываний в ардуино?
- Массив динамического размера в качестве члена класса
- Как перебрать объекты или передать объект функции?
Можете ли вы дать более подробную информацию о типах прерываний, которые вы хотите обрабатывать? Тип платы? В общем, вам понадобится одна связующая функция _на прерывание_, не обязательно одна на прерывание _pin_. Это может иметь значение, если несколько выводов имеют общее прерывание, как в случае с прерываниями смены контакта на AVR., @Edgar Bonet
Библиотека «Arduino», специфичная для ESP32, немного проблематична. Строго говоря, ESP32 — это вообще не Arduino., @DataFiddler
Как насчет перехода на более низкий уровень?
attachInterrupt()
использует разные типы прерываний в зависимости от используемого вывода. Большинство чипов имеют только 1 или 2 внешних контакта прерывания, поэтому все остальное выполняется с помощью прерываний смены контакта, которые охватывают весь порт, то есть 1 прерывание для группы из 8 контактов. Вы можете настроить эти прерывания непосредственно через их управляющие регистры. Хотя я не уверен, как это организовано на ESP., @chrisl