InterruptDrivenButton v0.1.0
Данная библиотека служит для обработки нажатия кнопок в Arduino. Ключевые особенности:
- состояние кпопки отслеживается с помощью прерываний, что, в отличие от простого опроса кнопки в цикле, даёт возможность точно отслеживанить нажатие и отпускание даже при нагруженном процессоре;
- отслеживается серия кликов, удержание кнопки, серия + удержание, а также удержание во время загрузки контроллера;
- поддерживаются нормально замкнутые и нормально разомкнутые кнопки.
При нажатии несколько раз подряд библиотека считает количество кликов и оповещает только после того, как серия кликов завершена. При удержании кнопки библиотека считает количество "тиков" с определённой периодичностью.
Важно: кнопку необходимо цеплять на пин микроконтроллера, который поддерживает прерывания. Для Arduino Uno, Nano и Mini это пины 2 и 3. Для других микроконтроллеров список пинов можно посмотреть здесь.
// конструктор объекта - нормально разомкнутая кнопка
InterruptDrivenButton button1(BTN_PIN);
// конструктор объекта - нормально замкнутая кнопка (второй аргумент - уровень сигнала при нажатии)
InterruptDrivenButton button1(BTN_PIN, LOW);
// вспомогательный макрос для создания функции-коллбэка для отлавливания прерываний (ISR)
DEFINE_IDB_ISR(button1) // создаётся функция void ISR__button1 { button1.onInterrupt(); }
// вспомогательный макрос для возвращения имени функции-коллбэка, созданной в DEFINE_IDB_ISR
IDB_ISR(button1) // вернёт ISR__button1
// инициализация кнопки в runtime, аргумент - имя коллбэк-функции (результат IDB_ISR(button1) )
button1.setup(ISR__callback);
// отработка внутреннего цикла
button1.loop();
// проверяет, есть ли событие от кнопки (типы событий - см. ниже)
// возвращает true или false
// hasEvent вызывать не обязательно, можно сразу дёргать pollEvent,
// но поскольку в большинстве случаев событий от кнопки нет, такая предварительная проверка позволяет слегка оптимизировать алгоритм
button1.hasEvent();
// возвращает последнее событие (если есть)
InterruptDrivenButtonEvent event = button.pollEvent();
Структура InterruptDrivenButtonEvent
содержит 3 поля:
byte type
- тип событияbyte clicks
- количество кликов в серии кликовbyte holdTicks
- количество "тиков" при удержании кнопки
Типы событий кнопки:
IDB_EVENT_NONE
- нет события на данный моментIDB_EVENT_CLICKS
- обнаружена серия кликов, поле clicks содержит количетво кликов. Событие генерируется после того, как серия кликов завершена.IDB_EVENT_HOLD
- кнопка удерживается в данный момент, поле holdTicks содержит количество тиков (периодов с момента начала удержания), поле clicks МОЖЕТ содержать ненулевое количество кликов, если до удержания кнопка была кликнута. Событие генерируется во время удержания кнопки. Пример использования: плавное увеличение/уменьшение яркости лампы.IDB_EVENT_BOOT_HOLD
- кнопка была зажата во время запуска микроконтроллера. Событие генерируется после того, как кнопка была отпущена. Пример использования: сброс EEPROM контроллера.
Настройки временных параметров производится глобально через #define
. Все времена в миллисекундах.
IDB_MIN_CLICK_DURATION
- минимально возможное время клика (промежутка между нажатием и отпусканием кнопки) - простая защита от дребезга контактов. Клики за меньшее время игнорируются. По-умолчанию20ms
IDB_MAX_CLICK_SERIES_WAIT_TIME
- максимальное время между тем, как отпустили кнопку и как нажали снова, чтобы второе нажатие определилось как последовательность. Если второй раз нажали позже - это новое событие. По-умолчанию500ms
IDB_HOLD_MIN_DURATION
- время, которое необходимо зажимать кнопку, чтобы определилось удерживание (holdTicks == 1
). Всё, что меньше, расценивается как клик. По-умолчанию1000ms
IDB_HOLD_TICKS_PERIOD
- периодичность тиков при удержании кнопки. По-умолчанию500ms
IDB_BOOT_HOLD_MAX_MCU_START_TIME
- если в течении этого времени после старта микроконтроллера кнопка будет зажата, будет остлеживатьсяIDB_EVENT_BOOT_HOLD
. По-умолчанию250ms
Примечание: есть защита от срабатывания при обнулении счётика времени.IDB_BOOT_HOLD_MIN_DURATION
- сколько времени нужно ждать, чтобы удержание кнопки при старте микроконтроллера распозналось какIDB_EVENT_BOOT_HOLD
. Если держали меньше - игнорируется. По-умолчанию3000ms
#include <InterruptDrivenButton.h>
InterruptDrivenButton myButton(BTN_PIN);
// вспомогательный макрос для создания ISR коллбэка (без этого не будет работать!)
DEFINE_IDB_ISR(myButton)
void setup() {
// IDB_ISR - ещё один вспомогательный макрос для передачи ISR коллбэка (без этого тоже не будет работать!)
myButton.setup(IDB_ISR(myButton));
}
void loop() {
myButton.loop();
...
if (myButton.hasEvent()) {
InterruptDrivenButtonEvent event = myButton.pollEvent();
if (event.type != IDB_EVENT_NONE) {
// несмотря на то, что hasEvent() == true, всё же стоит проверить обработанное событеи
if (event.type == IDB_EVENT_CLICKS) {
switch (event.clicks) {
case 1:
// 1 клик
break;
case 2:
// 2 клика
break;
case 3:
// 3 клика
break;
.....
}
} else if (event.type == IDB_EVENT_HOLD) {
byte ticks = event.holdTicks; // 1, 2, 3, 4.... постепенно увеличивается при удержании кнопки
byte clicks = event.clicks; // содержит количество кликов если кликали перед удержанием
} else if (event.type == IDB_EVENT_BOOT_HOLD) {
// удерживали кнопку при загрузке
}
}
}
}
На идею вдохновила кнопка GyverButton от Alex Gyver.