ОБНОВЛЕНИЯ
- v3.6: добавлен отдельный класс для работы с аналоговыми клавиатурами, см пример analogKeyboardG
- v3.7: исправления от Dryundel:
- Любой таймаут удержания
- Single, Double и Triple теперь не мешают hasClicks и getClicks и работают совместно
- isStep() тоже теперь ничего не мешает и он работает более корректно
- v3.8: исправления от Dryundel
ТЕОРИЯ
На сайте есть отдельный подробный урок по работе с кнопками.
Кнопка – простейший орган управления микроконтроллером. Подключить кнопку к Arduino очень просто, но нужно помнить, что пин должен иметь два стабильных состояния – высокое и низкое, GND или VCC. Для этого пин кнопки подтягивают резистором ~10 кОм противоположно подключению кнопки, т.е. если кнопка подключена второй ногой к GND, пин подтягивают к VCC, и наоборот.
Микроконтроллер имеет “встроенную” подтяжку ног к VCC, что даёт возможность подключать кнопку только к GND и пину, но режим работы пина нужно выбрать INPUT_PULLUP. Я, например, всегда подключаю отладочную кнопку на D3 вот таким образом:
Также можно подключить несколько кнопок к аналоговому пину, получится так называемая аналоговая клавиатура. Значение функции analogRead() будет зависеть от нажатой кнопки.
БИБЛИОТЕКА
Для удобной и многофункциональной работы с кнопкой я написал библиотеку GyverButton. Что она умеет:
- Работа с нормально замкнутыми и нормально разомкнутыми кнопками
- Работа с подключением PULL_UP и PULL_DOWN Опрос кнопки с программным антидребезгом контактов (настраиваемое время)
- Отработка нажатия, удерживания, отпускания, клика по кнопке (+ настройка таймаутов)
- Отработка одиночного, двойного и тройного нажатия (вынесено отдельно)
- Отработка любого количества нажатий кнопки (функция возвращает количество нажатий)
- Функция изменения значения переменной с заданным шагом и заданным интервалом по времени
- Возможность работы с “виртуальными” кнопками (все возможности библиотеки используются для матричных и резистивных клавиатур)
Поддерживаемые платформы: все Arduino (используются стандартные Wiring-функции)
Версия 3.5: значительно увеличена производительность для AVR Ardiuno плат
УСТАНОВКА
- Библиотеку можно найти и установить через менеджер библиотек по названию GyverButton в:
- Arduino IDE (Инструменты/Управлять библиотеками)
- Arduino IDE v2 (вкладка «Library Manager»)
- PlatformIO (PIO Home, вкладка «Libraries»)
- Про ручную установку читай здесь
ДОКУМЕНТАЦИЯ
// Варианты инициализации: // GButton btn; // без привязки к пину (виртуальная кнопка) и без указания типа (по умолч. HIGH_PULL и NORM_OPEN) // GButton btn(пин); // с привязкой к пину и без указания типа (по умолч. HIGH_PULL и NORM_OPEN) // GButton btn(пин, тип подключ.); // с привязкой к пину и указанием типа подключения (HIGH_PULL / LOW_PULL) и без указания типа кнопки (по умолч. NORM_OPEN) // GButton btn(пин, тип подключ., тип кнопки); // с привязкой к пину и указанием типа подключения (HIGH_PULL / LOW_PULL) и типа кнопки (NORM_OPEN / NORM_CLOSE) // GButton btn(BTN_NO_PIN, тип подключ., тип кнопки); // без привязки к пину и указанием типа подключения (HIGH_PULL / LOW_PULL) и типа кнопки (NORM_OPEN / NORM_CLOSE) void setDebounce(uint16_t debounce); // установка времени антидребезга (по умолчанию 80 мс) void setTimeout(uint16_t timeout); // установка таймаута удержания (по умолчанию 300 мс) void setClickTimeout(uint16_t timeout); // установка таймаута между кликами (по умолчанию 500 мс) void setStepTimeout(uint16_t step_timeout); // установка таймаута между инкрементами (по умолчанию 400 мс) void setType(uint8_t type); // установка типа кнопки (HIGH_PULL - подтянута к питанию, LOW_PULL - к gnd) void setDirection(uint8_t dir); // установка направления (разомкнута/замкнута по умолчанию - NORM_OPEN, NORM_CLOSE) void setTickMode(uint8_t tickMode); // (MANUAL / AUTO) ручной или автоматический опрос кнопки функцией tick() // MANUAL - нужно вызывать функцию tick() вручную // AUTO - tick() входит во все остальные функции и опрашивается сама void tick(); // опрос кнопки void tick(boolean state); // опрос внешнего значения (0 нажато, 1 не нажато) (для матричных, резистивных клавиатур и джойстиков) boolean isPress(); // возвращает true при нажатии на кнопку. Сбрасывается после вызова boolean isRelease(); // возвращает true при отпускании кнопки. Сбрасывается после вызова boolean isClick(); // возвращает true при клике. Сбрасывается после вызова boolean isHolded(); // возвращает true при удержании дольше timeout. Сбрасывается после вызова boolean isHold(); // возвращает true при нажатой кнопке, не сбрасывается boolean state(); // возвращает состояние кнопки boolean isSingle(); // возвращает true при одиночном клике. Сбрасывается после вызова boolean isDouble(); // возвращает true при двойном клике. Сбрасывается после вызова boolean isTriple(); // возвращает true при тройном клике. Сбрасывается после вызова boolean hasClicks(); // проверка на наличие кликов. Сбрасывается после вызова uint8_t getClicks(); // вернуть количество кликов uint8_t getHoldClicks();// вернуть количество кликов, предшествующее удерживанию boolean isStep(); // возвращает true по таймеру setStepTimeout, смотри пример void resetStates(); // сбрасывает все is-флаги и счётчики
Инициализация
Объект создаётся следующим образом:
AnalogKey<аналоговый пин, количество кнопок> объект;
Настройка
При помощи метода
.attach(номер, сигнал)
задаются "кнопки" клавиатуры: кнопке под номером номер ставится в соответствие сигнал. Сигнал измеряется предварительно например выводом значений analogRead() в порт.
При помощи .setWindow(размер)
устанавливается точность обработки сигнала кнопок, по умолчанию равен 20. Что это значит? Ожидаемое нажатие кнопки будет обработано, если сигнал с клавиатуры попадает в промежуток (сигнал-размер, сигнал+размер).
Опрос
Метод
.status(номер)
возвращает true
, если нажата кнопка под указанным номером.
Метод .pressed()
возвращает номер нажатой в данный момент кнопки, если таковых нет - возвращает -1
.
Пример
/* Сигналы кнопок 1023 927 856 783 671 632 590 560 504 480 455 440 399 319 255 230 */ #include "AnalogKey.h" // указываем пин и количество кнопок AnalogKey< A0, 16 > keys; void setup() { Serial.begin(9600); // назначаем кнопкам их сигналы keys.attach(0, 1023); keys.attach(1, 927); keys.attach(2, 856); keys.attach(3, 783); keys.attach(4, 671); keys.attach(5, 632); keys.attach(6, 590); keys.attach(7, 560); keys.attach(8, 504); keys.attach(9, 480); keys.attach(10, 455); keys.attach(11, 440); keys.attach(12, 399); keys.attach(13, 319); keys.attach(14, 255); keys.attach(15, 230); } void loop() { // проверяем каждую кнопку в ручном режиме if (keys.status(0)) Serial.println("press 0"); if (keys.status(1)) Serial.println("press 1"); if (keys.status(2)) Serial.println("press 2"); if (keys.status(3)) Serial.println("press 3"); if (keys.status(4)) Serial.println("press 4"); if (keys.status(5)) Serial.println("press 5"); if (keys.status(6)) Serial.println("press 6"); // или выводим номер текущей нажатой (-1 значит ни одна не нажата) if (keys.pressed() != -1) Serial.println(keys.pressed()); delay(10); }
Интеграция с GyverButton
Для работы с GButton достаточно передавать в "тик" статус конкретных кнопок, таким образом аналоговую клавиатуру можно обрабатывать со всеми фишками GyverButton.
// новый пример работы с аналоговой клавиатурой /* Сигналы кнопок 1023 927 856 783 671 632 590 560 504 480 455 440 399 319 255 230 */ #include "AnalogKey.h" // указываем пин и количество кнопок AnalogKey< A0, 3 > keys; #include GButton btn1, btn2, btn3; void setup() { Serial.begin(9600); // указываем сигналы кнопок аналоговой клавы keys.attach(0, 1023); keys.attach(1, 927); keys.attach(2, 856); } void loop() { // тикаем кнопки как статусы аналоговых btn1.tick(keys.status(0)); btn2.tick(keys.status(1)); btn3.tick(keys.status(2)); if (btn1.isClick()) Serial.println("click 0"); if (btn2.isClick()) Serial.println("click 1"); if (btn3.isClick()) Serial.println("click 2"); if (btn1.isHolded()) Serial.println("click 0"); if (btn2.isHolded()) Serial.println("hold 1"); if (btn3.isHolded()) Serial.println("hold 2"); }
ПРИМЕРЫ
Остальные примеры смотри в папке examples библиотеки, также примеры можно открыть из Arduino IDE/Файл/Примеры
// Пример использования библиотеки GyverButton, все возможности в одном скетче. #define BTN_PIN 3 // кнопка подключена сюда (BTN_PIN --- КНОПКА --- GND) #include "GyverButton.h" GButton butt1(BTN_PIN); // Варианты инициализации: // GButton btn; // без привязки к пину (виртуальная кнопка) и без указания типа (по умолч. HIGH_PULL и NORM_OPEN) // GButton btn(пин); // с привязкой к пину и без указания типа (по умолч. HIGH_PULL и NORM_OPEN) // GButton btn(пин, тип подключ.); // с привязкой к пину и указанием типа подключения (HIGH_PULL / LOW_PULL) и без указания типа кнопки (по умолч. NORM_OPEN) // GButton btn(пин, тип подключ., тип кнопки); // с привязкой к пину и указанием типа подключения (HIGH_PULL / LOW_PULL) и типа кнопки (NORM_OPEN / NORM_CLOSE) // GButton btn(BTN_NO_BTN_PIN, тип подключ., тип кнопки); // без привязки к пину и указанием типа подключения (HIGH_PULL / LOW_PULL) и типа кнопки (NORM_OPEN / NORM_CLOSE) int value = 0; void setup() { Serial.begin(9600); butt1.setDebounce(50); // настройка антидребезга (по умолчанию 80 мс) butt1.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) butt1.setClickTimeout(600); // настройка таймаута между кликами (по умолчанию 300 мс) // HIGH_PULL - кнопка подключена к GND, пин подтянут к VCC (BTN_PIN --- КНОПКА --- GND) // LOW_PULL - кнопка подключена к VCC, пин подтянут к GND // по умолчанию стоит HIGH_PULL butt1.setType(HIGH_PULL); // NORM_OPEN - нормально-разомкнутая кнопка // NORM_CLOSE - нормально-замкнутая кнопка // по умолчанию стоит NORM_OPEN butt1.setDirection(NORM_OPEN); } void loop() { butt1.tick(); // обязательная функция отработки. Должна постоянно опрашиваться if (butt1.isClick()) Serial.println("Click"); // проверка на один клик if (butt1.isSingle()) Serial.println("Single"); // проверка на один клик if (butt1.isDouble()) Serial.println("Double"); // проверка на двойной клик if (butt1.isTriple()) Serial.println("Triple"); // проверка на тройной клик if (butt1.hasClicks()) // проверка на наличие нажатий Serial.println(butt1.getClicks()); // получить (и вывести) число нажатий if (butt1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс) if (butt1.isRelease()) Serial.println("Release"); // отпускание кнопки (+ дебаунс) if (butt1.isHolded()) Serial.println("Holded"); // проверка на удержание if (butt1.isHold()) { // если кнопка удерживается Serial.print("Holding "); // выводим пока удерживается Serial.println(butt1.getHoldClicks()); // можно вывести количество кликов перед удержанием! } //if (butt1.state()) Serial.println("Hold"); // возвращает состояние кнопки if (butt1.isStep()) { // если кнопка была удержана (это для инкремента) value++; // увеличивать/уменьшать переменную value с шагом и интервалом Serial.println(value); // для примера выведем в порт } }
// Пример использования библиотеки GyverButton, все возможности в одном скетче. // автоматический тик #define BTN_PIN 3 // кнопка подключена сюда (BTN_PIN --- КНОПКА --- GND) #include "GyverButton.h" GButton butt1(BTN_PIN); // GButton butt1(BTN_PIN, HIGH_PULL, NORM_OPEN); // можно инициализировать так int value = 0; void setup() { Serial.begin(9600); butt1.setDebounce(90); // настройка антидребезга (по умолчанию 80 мс) butt1.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) // HIGH_PULL - кнопка подключена к GND, пин подтянут к VCC (BTN_PIN --- КНОПКА --- GND) // LOW_PULL - кнопка подключена к VCC, пин подтянут к GND // по умолчанию стоит HIGH_PULL butt1.setType(HIGH_PULL); // NORM_OPEN - нормально-разомкнутая кнопка // NORM_CLOSE - нормально-замкнутая кнопка // по умолчанию стоит NORM_OPEN butt1.setDirection(NORM_OPEN); // MANUAL - нужно вызывать функцию tick() вручную // AUTO - tick() входит во все остальные функции и опрашивается сама! butt1.setTickMode(AUTO); } void loop() { // butt1.tick(); // НЕ НУЖНА, в этом режиме (AUTO) она входит в каждую функцию if (butt1.isClick()) Serial.println("Click"); // проверка на один клик if (butt1.isSingle()) Serial.println("Single"); // проверка на один клик if (butt1.isDouble()) Serial.println("Double"); // проверка на двойной клик if (butt1.isTriple()) Serial.println("Triple"); // проверка на тройной клик if (butt1.hasClicks()) // проверка на наличие нажатий Serial.println(butt1.getClicks()); // получить (и вывести) число нажатий if (butt1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс) if (butt1.isRelease()) Serial.println("Release"); // отпускание кнопки (+ дебаунс) if (butt1.isHolded()) Serial.println("Holded"); // проверка на удержание if (butt1.isHold()) Serial.println("Holding"); // проверка на удержание //if (butt1.state()) Serial.println("Hold"); // возвращает состояние кнопки if (butt1.isStep()) { // если кнопка была удержана (это для инкремента) value++; // увеличивать/уменьшать переменную value с шагом и интервалом Serial.println(value); // для примера выведем в порт } }
// ловим степ с накликиванием #define BTN_PIN 0 // кнопка подключена сюда (BTN_PIN --- КНОПКА --- GND) #include "GyverButton.h" GButton butt1(BTN_PIN); void setup() { Serial.begin(9600); } void loop() { butt1.tick(); // удержание if (butt1.isStep()) { Serial.println("0x"); } // один клик + удержание if (butt1.isStep(1)) { Serial.println("1x"); } // два клика + удержание if (butt1.isStep(2)) { Serial.println("2x"); } }
// Пример использования библиотеки GyverButton, 1- 2- 3- нажатие #define BTN_PIN 3 // кнопка подключена сюда (BTN_PIN --- КНОПКА --- GND) #include "GyverButton.h" GButton butt1(BTN_PIN); void setup() { Serial.begin(9600); } void loop() { butt1.tick(); // обязательная функция отработки. Должна постоянно опрашиваться if (butt1.isSingle()) Serial.println("Single"); // проверка на один клик if (butt1.isDouble()) Serial.println("Double"); // проверка на двойной клик if (butt1.isTriple()) Serial.println("Triple"); // проверка на тройной клик }
// Пример использования библиотеки GyverButton // опрос 5 кнопок в ручном режиме // кнопки подключены к земле (PIN --- КНОПКА --- GND) #define BTN1 3 #define BTN2 4 #define BTN3 5 #define BTN4 6 #define BTN5 7 #include "GyverButton.h" GButton butt1(BTN1); GButton butt2(BTN2); GButton butt3(BTN3); GButton butt4(BTN4); GButton butt5(BTN5); void setup() { Serial.begin(9600); } void loop() { // тик в ручном режиме butt1.tick(); butt2.tick(); butt3.tick(); butt4.tick(); butt5.tick(); // проверяем одиночный клик if (butt1.isClick()) Serial.println("Button 1"); if (butt2.isClick()) Serial.println("Button 2"); if (butt3.isClick()) Serial.println("Button 3"); if (butt4.isClick()) Serial.println("Button 4"); if (butt5.isClick()) Serial.println("Button 5"); }
// Пример использования библиотеки GyverButton // опрос 5 кнопок в автоматическом режиме // кнопки подключены к земле (PIN --- КНОПКА --- GND) #define BTN1 3 #define BTN2 4 #define BTN3 5 #define BTN4 6 #define BTN5 7 #include "GyverButton.h" GButton butt1(BTN1); GButton butt2(BTN2); GButton butt3(BTN3); GButton butt4(BTN4); GButton butt5(BTN5); void setup() { Serial.begin(9600); // устанавливаем опрос на автоматический butt1.setTickMode(AUTO); butt2.setTickMode(AUTO); butt3.setTickMode(AUTO); butt4.setTickMode(AUTO); butt5.setTickMode(AUTO); } void loop() { // проверяем одиночный клик // tick уже сидит внутри опроса if (butt1.isClick()) Serial.println("Button 1"); if (butt2.isClick()) Serial.println("Button 2"); if (butt3.isClick()) Serial.println("Button 3"); if (butt4.isClick()) Serial.println("Button 4"); if (butt5.isClick()) Serial.println("Button 5"); }
// Пример использования библиотеки GyverButton с аналоговой клавиатурой // аналоговая клавиатура подключена на А7 // Схему смотри на странице библиотеки https://alexgyver.ru/gyverbutton/ // также она есть в папке с примером #include "GyverButton.h" // создаём кнопки без привязки к пину GButton myButt1; GButton myButt2; GButton myButt3; void setup() { Serial.begin(9600); // меняем тип на LOW_PULL, потому что по умолчанию стоит HIGH_PULL myButt1.setType(LOW_PULL); myButt2.setType(LOW_PULL); myButt3.setType(LOW_PULL); } void loop() { // читаем значение int analog = analogRead(7); // для начала нужно вывести и запомнить значение для каждой кнопки //Serial.println(analog); // проверяем у каждой кнопки свой диапазон (+- 20 от полученного значения) myButt1.tick(analog < 860 && analog > 820); myButt2.tick(analog < 740 && analog > 700); myButt3.tick(analog < 650 && analog > 600); // проверка на удержание, например if (myButt1.isHolded()) { Serial.println("hold 1"); } if (myButt2.isHolded()) { Serial.println("hold 2"); } if (myButt3.isHolded()) { Serial.println("hold 3"); } delay(10); // задержка тут не нужна, чисто для вывода }
// Пример использования библиотеки GyverButton, все возможности в одном скетче. // Дополнительный опрос по аппаратному прерыванию #define BTN_PIN 3 // кнопка подключена сюда (BTN_PIN --- КНОПКА --- GND) #include "GyverButton.h" GButton butt1(BTN_PIN); int value = 0; void setup() { Serial.begin(9600); attachInterrupt(1, isr, CHANGE); butt1.setDebounce(80); // настройка антидребезга (по умолчанию 80 мс) butt1.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) } void isr() { butt1.tick(); // опрашиваем в прерывании, чтобы поймать нажатие в любом случае } void loop() { butt1.tick(); // опрашиваем в скетче, иначе не будут работать проверки по времени! if (butt1.isClick()) Serial.println("Click"); // проверка на один клик if (butt1.isSingle()) Serial.println("Single"); // проверка на один клик if (butt1.isDouble()) Serial.println("Double"); // проверка на двойной клик if (butt1.isTriple()) Serial.println("Triple"); // проверка на тройной клик if (butt1.hasClicks()) // проверка на наличие нажатий Serial.println(butt1.getClicks()); // получить (и вывести) число нажатий if (butt1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс) if (butt1.isRelease()) Serial.println("Release"); // отпускание кнопки (+ дебаунс) if (butt1.isHolded()) Serial.println("Holded"); // проверка на удержание //if (butt1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки if (butt1.isStep()) { // если кнопка была удержана (это для инкремента) value++; // увеличивать/уменьшать переменную value с шагом и интервалом Serial.println(value); // для примера выведем в порт } }
/* Пример использования библиотеки GyverButton, управляем переменной value при помощи двух кнопок Конструкция с isIncr делает увеличение/уменьшение переменной при нажатой кнопке с шагом по времени */ #define BTN1 2 // кнопка подключена сюда (PIN --- КНОПКА --- GND) #define BTN2 3 // кнопка подключена сюда (PIN --- КНОПКА --- GND) #include "GyverButton.h" GButton butt1(BTN1); GButton butt2(BTN2); int value = 0; void setup() { Serial.begin(9600); } void loop() { butt1.tick(); // обязательная функция отработки. Должна постоянно опрашиваться butt2.tick(); // обязательная функция отработки. Должна постоянно опрашиваться if (butt1.isClick()) { // одиночное нажатие value++; // инкремент Serial.println(value); // для примера выведем в порт } if (butt2.isClick()) { // одиночное нажатие value--; // декремент Serial.println(value); // для примера выведем в порт } if (butt1.isStep()) { // обработчик удержания с шагами value++; // увеличивать/уменьшать переменную value с шагом и интервалом! Serial.println(value); // для примера выведем в порт } if (butt2.isStep()) { // обработчик удержания с шагами value--; // увеличивать/уменьшать переменную value с шагом и интервалом! Serial.println(value); // для примера выведем в порт } }
ВИДЕО
ПОДДЕРЖАТЬ
Вы можете поддержать меня за создание доступных проектов с открытым исходным кодом, полный список реквизитов есть вот здесь.