Ардуино УНО. Кнопка энкодера повешена на прерывание. В приведенном скетче, естественно, ее нажатие приводит к увеличению переменной button. Подскажите, как в “теле” прерывания можно отследить однократный и двойной клик? Есть ли ссылка, где посмотреть? Если кто поделится кусочком скетча - умру от счастья. Но лучше первый вариант (хочу разобраться). Заранее спасибо!
// Библиотека кнопок - https://github.com/kakmyc-github/kakmyc_btn
#include "Arduino.h"
#include "kakmyc_btn.h"
#define _bounce_time 50
#define _long_press 1500
#define _wait_multiclick 300
// функции класса Btn(обработчик кнопок)
byte kakmyc_btn::read() {
uint16_t _millis = millis();
!_state ? button = digitalRead(_pin) : button = !digitalRead(_pin); // в зависимости от того, что в конструкторе настраиваем кнопку
if (!button) {
num = 0; // если кнопка отпущена, выдаем результат 0
}
if (button && !pressFlag) { // если кнопка нажата и флаг опущен
pressTime = _millis - start_press; // считаем время нажатия кнопки
if (pressTime >= _long_press) { // если длительность нажатия больше 1,5 сек
pressFlag = 1; // поднимаем флаг
num = 255; // значение кнопки long
pressTime = 0; // сбрасываем длительность нажатия
}
}
if (!button) { // если кнопка отпущена
start_press = _millis; // сбрасываем время нажатия
pressFlag = 0; // опускаем флаг
}
if (!button && !pressFlag) { // если кнопка и флаг отпущены
if (pressTime > _bounce_time && pressTime < _long_press) { // а время нажатия больше 50мс, но меньше 1,5сек
press_one++; // увеличиваем счетчик количества нажатий
if (press_one > _val) press_one = _val; // ограничиваем значение счетчика
pressTime = 0; // сбрасываем длительность нажатия
double_press = _millis; // запускаем таймер ожидания следующего нажатия
}
}
if (press_one) { // если было короткое нажатие
if (_millis - double_press >= _wait_multiclick) { // ждем 0,3сек
pressTime = 0; // сбрасываем длительность нажатия
num = press_one; // значение кнопки приравниваем к количеству нажатий
press_one = 0; // сбрасываем количество нажатий
}
}
_num = num; // для одиночного вывода результата, используем временную переменную
num = 0; // обнудяем основную переменную значения кнопки
return _num; // возвращаем значение кнопки
}
//функция конструктора класса
/*в конструкторе указываем:
номер пина
тип сигнала (лог0/лог1)
максимальное количество отслеживаемых кликов*/
kakmyc_btn::kakmyc_btn(byte pin, byte state, byte val) {
_pin = pin; // передаем внутренней переменной номер пина
//!state?_state=2:_state=0; // в зависимости от выбранного типа сигнала меняем значение переменной
_state = state;
_val = val; // передаем внутренней переменной количество кликов
pinMode(pin, _state); // конфигурируем пин согласно типа сигнала
}
Только в прерывании переменные volatile должны быть…
Как то я себе слабо представляю обработку двойного клика по прерыванию.
Это тогда нужно таймер аппаратный заводить по первому клику, а по достижению счета вывод делать был второй клик или нет.
В общем сомнительная затея.
Даже представить не могу зачем может понадобиться данный функционал.
BOOM, такое в прерываниях не прокатит.
Событие одиночного клика будет обрабатывать некорректно.
Это в цикле мы вызовем при следующем проходе опрос, а в прерывании опрос будет только при следующем заходе в прерывание.
Т.е. при одиночном нажатии результата не будет никакого.
А нужен ли двойной клик? Особенно если есть действия которые нужно делать мгновенно по первому нажатию? Двойной слик в винде имеет логику - никогда его не пользуют сразу, только по подготовленному предварительно объекту. Т.е. идёт первый одиночный создание фокуса, затем в зависимости от одинарного или двойного выполняются те или иные действия. В смысле действий сразу, без фокуса, проще реагировать на длинное и короткое нажатие в зависимости от желаемой реакции. Нужно просто продумать логику управления.
Ни к чему не призываю. Просто мысли.
Я ж спросил может не двойной а длинный? Чем хуже? А реализация проще и логика работы железки легче обслуживается. Или виндовая мышь уже условные рефлексы привила?
Логика различения двойного-одинарного сложнее, но вполне реализуется.
Главное что надо сделать - это вкладывать в прерывание только регистрацию события, а не его обработку.
Код в прерывании только взводит признак того, что сейчас была нажата кнопка.
Код в loop же постоянно проверяет этот признак и обнаружив сбрасывает и переходит в режим отслеживания числа нажатий. В этом режиме каждый раз до истечения таймаута он увеличивает счётчик нажатий (другая переменная) и снова отсрачивает (слово то какое!) таймер. И, наконец, когда таймер превысит лимит переходит к обработке нажатия - количество нажатий будет лежать в переменной и их может быть хоть 255. Так и надо в инструкции написать: если нажав первый раз вы передумали и хотите отменить нажатие всего лишь кликайте по кнопке еще 255 раз, байтовый счётчик обнулится и получится великолепное нажатие ноль раз. Тот самый случай когда красивый алгоритм помогает юзабилити.
Я всё пытаюсь протолкнуть мысль, что если есть двойной торойной и более клик, то придётся отслеживать всё до конца, что бы понять какой клик был и что с ним делать. Т.е. если нужен коротенький одинарный, то система всё равно должна ждать до до конца самого длинного клика или давать что типа - клик! ой нет! двойной! о! тройной…
Сначала клик (если таймер не запущен, запускаем), потом клик и даблклик. Если таймер отработал, а даблклика не последовало, то отрабатываем одиночный, иначе - двойной (таймер останавливаем принудительно)