├── .gitattributes ├── .github └── workflows │ └── tg-send.yml ├── LICENSE ├── README.md ├── README_EN.md ├── doc └── diagram.png ├── examples ├── class │ └── class.ino ├── stepDemo │ └── stepDemo.ino └── virtual │ └── virtual.ino ├── keywords.txt ├── library.properties └── src └── VirtualButton.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/tg-send.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Telegram Message 3 | on: 4 | release: 5 | types: [published] 6 | jobs: 7 | build: 8 | name: Send Message 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: send telegram message on push 12 | uses: appleboy/telegram-action@master 13 | with: 14 | to: ${{ secrets.TELEGRAM_TO }} 15 | token: ${{ secrets.TELEGRAM_TOKEN }} 16 | disable_web_page_preview: true 17 | message: | 18 | ${{ github.event.repository.name }} v${{ github.event.release.tag_name }} 19 | ${{ github.event.release.body }} 20 | https://github.com/${{ github.repository }} 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Alex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![latest](https://img.shields.io/github/v/release/GyverLibs/VirtualButton.svg?color=brightgreen)](https://github.com/GyverLibs/VirtualButton/releases/latest/download/VirtualButton.zip) 2 | [![Foo](https://img.shields.io/badge/Website-AlexGyver.ru-blue.svg?style=flat-square)](https://alexgyver.ru/) 3 | [![Foo](https://img.shields.io/badge/%E2%82%BD$%E2%82%AC%20%D0%9D%D0%B0%20%D0%BF%D0%B8%D0%B2%D0%BE-%D1%81%20%D1%80%D1%8B%D0%B1%D0%BA%D0%BE%D0%B9-orange.svg?style=flat-square)](https://alexgyver.ru/support_alex/) 4 | [![Foo](https://img.shields.io/badge/README-ENGLISH-blueviolet.svg?style=flat-square)](https://github-com.translate.goog/GyverLibs/VirtualButton?_x_tr_sl=ru&_x_tr_tl=en) 5 | 6 | [![Foo](https://img.shields.io/badge/ПОДПИСАТЬСЯ-НА%20ОБНОВЛЕНИЯ-brightgreen.svg?style=social&logo=telegram&color=blue)](https://t.me/GyverLibs) 7 | 8 | |⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️

**ВНИМАНИЕ, БИБЛИОТЕКА УСТАРЕЛА! ИСПОЛЬЗУЙ БИБЛИОТЕКУ [EncButton](https://github.com/GyverLibs/EncButton), ОНА ЛЕГЧЕ И ИМЕЕТ БОЛЬШЕ ВОЗМОЖНОСТЕЙ**

⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️| 9 | | --- | 10 | 11 | # VirtualButton 12 | Библиотека с логикой обработки кнопки (виртуальная кнопка) 13 | - Очень лёгкий оптимизированный код 14 | - Множество сценариев использования 15 | - Позволяет расширить функционал других библиотек 16 | - Обработка: 17 | - Антидребезг 18 | - Нажатие 19 | - Отпускание 20 | - Клик 21 | - Несколько кликов 22 | - Счётчик кликов 23 | - Удержание 24 | - Импульсное удержание 25 | - Действия с предварительными кликами 26 | 27 | ### Совместимость 28 | Совместима со всеми Arduino платформами (используются Arduino-функции) 29 | 30 | ## Содержание 31 | - [Установка](#install) 32 | - [Инициализация](#init) 33 | - [Использование](#usage) 34 | - [Пример](#example) 35 | - [Версии](#versions) 36 | - [Баги и обратная связь](#feedback) 37 | 38 | 39 | ## Установка 40 | - Библиотеку можно найти по названию **VirtualButton** и установить через менеджер библиотек в: 41 | - Arduino IDE 42 | - Arduino IDE v2 43 | - PlatformIO 44 | - [Скачать библиотеку](https://github.com/GyverLibs/VirtualButton/archive/refs/heads/main.zip) .zip архивом для ручной установки: 45 | - Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64) 46 | - Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32) 47 | - Распаковать и положить в *Документы/Arduino/libraries/* 48 | - (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив 49 | - Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA) 50 | ### Обновление 51 | - Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи 52 | - Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить" 53 | - Вручную: **удалить папку со старой версией**, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам! 54 | 55 | 56 | ## Инициализация 57 | ```cpp 58 | VButton btn; 59 | ``` 60 | 61 | 62 | ## Использование 63 | ### Описание методов 64 | ```cpp 65 | // =================== ОПРОС =================== 66 | // опрос, вернёт true если статус кнопки изменился. Принимает состояние кнопки (1 - нажата) 67 | bool poll(bool s); 68 | 69 | bool press(); // кнопка нажата 70 | bool release(); // кнопка отпущена 71 | bool click(); // клик по кнопке 72 | 73 | bool held(); // кнопка удержана 74 | bool held(uint8_t clk); // кнопка удержана с предварительным накликиванием 75 | 76 | bool hold(); // кнопка удерживается 77 | bool hold(uint8_t clk); // кнопка удерживается с предварительным накликиванием 78 | 79 | bool step(); // режим импульсного удержания 80 | bool step(uint8_t clk); // режим импульсного удержания с предварительным накликиванием 81 | 82 | bool releaseStep(); // кнопка отпущена после импульсного удержания 83 | bool releaseStep(uint8_t clk); // кнопка отпущена после импульсного удержания с предварительным накликиванием 84 | 85 | bool hasClicks(uint8_t num); // имеются клики 86 | uint8_t hasClicks(); // имеются клики 87 | 88 | bool timeout(uint16_t tout); // с момента отпускания кнопки прошло указанное время, миллисекунд 89 | 90 | uint8_t clicks; // счётчик кликов 91 | 92 | // ================= НАСТРОЙКИ ================= 93 | // таймаут удержания кнопки для hold(), 32.. 8100 мс (по умолч. 1000 мс) 94 | void setHoldTimeout(uint16_t tout); 95 | 96 | // период импульсов step(), 32.. 8100 мс (по умолч. 500 мс) 97 | void setStepTimeout(uint16_t tout); 98 | 99 | // ================= СИСТЕМНОЕ ================= 100 | bool busy(); // вернёт true, если всё ещё нужно вызывать poll для опроса таймаутов 101 | void reset(); // сбросить все флаги 102 | 103 | // ============= ДЕФАЙНЫ НАСТРОЕК ============= 104 | // дефайнить ПЕРЕД ПОДКЛЮЧЕНИЕМ БИБЛИОТЕКИ, показаны значения по умолчанию 105 | #define VB_DEB 50 // дебаунс кнопки, мс 106 | #define VB_CLICK 400 // таймаут накликивания кнопки, мс 107 | ``` 108 | 109 | ### Логика работы 110 | *Для использования кнопки на пинах МК без написания лишнего кода используй библиотеку [EncButton](https://github.com/GyverLibs/EncButton)* 111 | 112 | В метод `poll(state)` нужно как можно чаще передавать текущее состояние кнопки: `1` - нажата, `0` - отпущена. На основе этого 113 | библиотека будет обрабатывать таймауты и режимы нажатий, а затем "сигналить" при помощи набора функций (см. ниже). Большинство 114 | функций имеют механизм однократного срабатывания, т.е. один раз возвращают `true` при наступлении события, а затем возвращают `false` 115 | до повторного наступления события. 116 | 117 | - `press()` - кнопка была нажата. *[однократно вернёт true]* 118 | - `release()` - кнопка была отпущена. *[однократно вернёт true]* 119 | - `timeout(tout)` - с момента отпускания кнопки прошло указанное время, миллисекунд. *[однократно вернёт true]* 120 | - `click()` - кнопка была кликнута, т.е. нажата и отпущена до таймаута удержания. *[однократно вернёт true]* 121 | - `held()` - кнопка была удержана дольше таймаута удержания. *[однократно вернёт true]* 122 | - `held(clicks)` - то же самое, но функция принимает количество кликов, сделанных до удержания. Примечание: held() без аргумента перехватит вызов! См. пример *preClicks*. *[однократно вернёт true]* 123 | - `hold()` - кнопка была удержана дольше таймаута удержания. *[возвращает true, пока удерживается]* 124 | - `hold(clicks)` - то же самое, но функция принимает количество кликов, сделанных до удержания. Примечание: hold() без аргумента перехватит вызов! См. пример *preClicks*. *[возвращает true, пока удерживается]* 125 | - `step()` - режим "импульсного удержания": после удержания кнопки дольше таймаута данная функция *[возвращает true с периодом VB_STEP]*. Удобно использовать для пошагового изменения переменных: `if (btn.step()) val++;`. 126 | - `step(clicks)` - то же самое, но функция принимает количество кликов, сделанных до удержания. Примечание: step() без аргумента перехватит вызов! См. пример *StepMode* и *preClicks*. 127 | - `releaseStep()` - кнопка была отпущена после импульсного удержания. Может использоваться для изменения знака инкремента переменной. См. пример *StepMode*. *[однократно вернёт true]* 128 | - `releaseStep(clicks)` - то же самое, но функция принимает количество кликов, сделанных до удержания. Примечание: releaseStep() без аргумента перехватит вызов! См. пример *StepMode* и *preClicks*. *[однократно вернёт true]* 129 | - `hasClicks(clicks)` - было сделано указанное количество кликов с периодом менее *VB_CLICK*. *[однократно вернёт true]* 130 | - `hasClicks()` - вернёт количество кликов, сделанных с периодом менее *VB_CLICK*. В противном случае вернёт 0. 131 | - `uint8_t clicks` - публичная переменная, хранит количество сделанных кликов с периодом менее *VB_CLICK*. Сбрасывается в 0 после нового клика. 132 | 133 | ![diagram](/doc/diagram.png) 134 | 135 | Пример: 136 | ```cpp 137 | void loop() { 138 | btn.poll(digitalRead(PIN)); 139 | if (btn.click()) Serial.println("Click!"); 140 | if (btn.held()) Serial.println("Held!"); 141 | } 142 | ``` 143 | 144 | ### Оптимизация 145 | Чтобы лишний раз не опрашивать "сигнальные" функции, можно поместить их в условие: метод `poll()` возвращает `true`, когда статус кнопки изменился: 146 | ```cpp 147 | void loop() { 148 | if (btn.poll(digitalRead(PIN))) { 149 | if (btn.click()) Serial.println("Click!"); 150 | if (btn.held()) Serial.println("Held!"); 151 | } 152 | } 153 | ``` 154 | 155 | ### Наследование 156 | Библиотека задумана как инструмент для разработчика. С её помощью можно расширить функциональность кнопки, опрашиваемой любым способом: 157 | - Напрямую с пина МК 158 | - Сдвиговый регистр 159 | - Матричная клавиатура 160 | - Резистивная клавиатура 161 | - Резистивно-матричная клавиатура 162 | - Ёмкостная кнопка 163 | - И так далее 164 | 165 | Пример реализации класса кнопки, который опрашивает пин стандартными средствами, но использует все возможности VirtualButton: 166 | ```cpp 167 | class MyBtn : public VButton { 168 | public: 169 | MyBtn(uint8_t pin) { 170 | _pin = pin; 171 | pinMode(_pin, INPUT_PULLUP); 172 | } 173 | bool tick() { 174 | return poll(!digitalRead(_pin)); 175 | } 176 | uint8_t _pin; 177 | }; 178 | ``` 179 | 180 | Тут мы реализовали метод `tick()`, который будет опрашивать пин и передавать в `VButton`. Классу доступны все возможности VirtualButton: 181 | 182 | ```cpp 183 | MyBtn btn(3); 184 | 185 | void loop() { 186 | btn.tick(); 187 | 188 | if (btn.press()) Serial.println("press"); 189 | if (btn.click()) Serial.println("click"); 190 | if (btn.release()) Serial.println("release"); 191 | // ....... 192 | } 193 | ``` 194 | 195 | 196 | ## Примеры 197 | Остальные примеры смотри в **examples**! 198 | 199 | 200 | ## Версии 201 | - v1.0 - релиз 202 | - v1.1 - добавлен механизм "таймаута" 203 | 204 | 205 | ## Баги и обратная связь 206 | При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru) 207 | Библиотека открыта для доработки и ваших **Pull Request**'ов! 208 | 209 | При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать: 210 | - Версия библиотеки 211 | - Какой используется МК 212 | - Версия SDK (для ESP) 213 | - Версия Arduino IDE 214 | - Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде 215 | - Какой код загружался, какая работа от него ожидалась и как он работает в реальности 216 | - В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код 217 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | This is an automatic translation, may be incorrect in some places. See sources and examples! 2 | 3 | Cranberry# VirtualButton 4 | Library with button processing logic (virtual button) for Arduino -------------------------------------------------------------------------------- /doc/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GyverLibs/VirtualButton/2ed0adebe32d6b49129503b99eef657a313cf755/doc/diagram.png -------------------------------------------------------------------------------- /examples/class/class.ino: -------------------------------------------------------------------------------- 1 | // пример работы библиотеки в другом классе 2 | // для примера пусть класс опрашивает пин 3 | #include 4 | 5 | struct MyBtn : public VButton { 6 | MyBtn(uint8_t pin) { 7 | _pin = pin; 8 | pinMode(_pin, INPUT_PULLUP); 9 | } 10 | bool tick() { 11 | return poll(!digitalRead(_pin)); 12 | } 13 | uint8_t _pin; 14 | }; 15 | 16 | MyBtn btn(3); 17 | 18 | void setup() { 19 | Serial.begin(9600); 20 | } 21 | 22 | void loop() { 23 | btn.tick(); 24 | 25 | if (btn.press()) Serial.println("press"); 26 | if (btn.click()) Serial.println("click"); 27 | if (btn.release()) Serial.println("release"); 28 | 29 | if (btn.held()) Serial.println("held"); // однократно вернёт true при удержании 30 | //if (btn.hold()) Serial.println("hold"); // будет постоянно возвращать true после удержания 31 | if (btn.step()) Serial.println("step"); // импульсное удержание 32 | 33 | // проверка на количество кликов 34 | if (btn.hasClicks(1)) Serial.println("action 1 clicks"); 35 | if (btn.hasClicks(2)) Serial.println("action 2 clicks"); 36 | if (btn.hasClicks(3)) Serial.println("action 3 clicks"); 37 | if (btn.hasClicks(5)) Serial.println("action 5 clicks"); 38 | 39 | // вывести количество кликов 40 | if (btn.hasClicks()) { 41 | Serial.print("has clicks "); 42 | Serial.println(btn.clicks); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/stepDemo/stepDemo.ino: -------------------------------------------------------------------------------- 1 | // пример работы как с виртуальной кнопкой 2 | // кнопка подключена на D3 и GND 3 | // будем передавать состояние кнопки вручную 4 | #define BTN_PIN 3 5 | 6 | #include 7 | VButton btn; 8 | 9 | void setup() { 10 | Serial.begin(9600); 11 | // подтянем внутренней подтяжкой 12 | pinMode(BTN_PIN, INPUT_PULLUP); 13 | } 14 | 15 | int val_a, val_b, val_c; 16 | int8_t step_a = 1; 17 | int8_t step_b = 5; 18 | int8_t step_c = 10; 19 | 20 | void loop() { 21 | // передаём значение пина в poll 22 | // 1 - кнопка нажата, 0 - не нажата 23 | // поэтому инверсия 24 | btn.poll(!digitalRead(BTN_PIN)); 25 | 26 | // передаём количество предварительных кликов 27 | if (btn.step(1)) { 28 | val_a += step_a; 29 | Serial.print("val_a: "); 30 | Serial.println(val_a); 31 | } 32 | if (btn.step(2)) { 33 | val_b += step_b; 34 | Serial.print("val_b: "); 35 | Serial.println(val_b); 36 | } 37 | if (btn.step(3)) { 38 | val_c += step_c; 39 | Serial.print("val_c: "); 40 | Serial.println(val_c); 41 | } 42 | 43 | // разворачиваем шаг для изменения в обратную сторону 44 | // передаём количество предварительных кликов 45 | if (btn.releaseStep(1)) step_a = -step_a; 46 | if (btn.releaseStep(2)) step_b = -step_b; 47 | if (btn.releaseStep(3)) step_c = -step_c; 48 | } 49 | -------------------------------------------------------------------------------- /examples/virtual/virtual.ino: -------------------------------------------------------------------------------- 1 | // пример работы как с виртуальной кнопкой 2 | // кнопка подключена на D3 и GND 3 | // будем передавать состояние кнопки вручную 4 | #define BTN_PIN 3 5 | 6 | #include 7 | VButton btn; 8 | 9 | void setup() { 10 | Serial.begin(9600); 11 | // подтянем внутренней подтяжкой 12 | pinMode(BTN_PIN, INPUT_PULLUP); 13 | } 14 | 15 | void loop() { 16 | // передаём значение пина в poll 17 | // 1 - кнопка нажата, 0 - не нажата 18 | // поэтому инверсия 19 | btn.poll(!digitalRead(BTN_PIN)); 20 | 21 | if (btn.press()) Serial.println("press"); 22 | if (btn.click()) Serial.println("click"); 23 | if (btn.release()) Serial.println("release"); 24 | 25 | if (btn.held()) Serial.println("held"); // однократно вернёт true при удержании 26 | //if (btn.hold()) Serial.println("hold"); // будет постоянно возвращать true после удержания 27 | if (btn.step()) Serial.println("step"); // импульсное удержание 28 | 29 | // проверка на количество кликов 30 | if (btn.hasClicks(1)) Serial.println("action 1 clicks"); 31 | if (btn.hasClicks(2)) Serial.println("action 2 clicks"); 32 | if (btn.hasClicks(3)) Serial.println("action 3 clicks"); 33 | if (btn.hasClicks(5)) Serial.println("action 5 clicks"); 34 | 35 | // прошло 5 секунд с момента отпускания кнопки 36 | if (btn.timeout(5000)) Serial.println("timeout"); 37 | 38 | // вывести количество кликов 39 | if (btn.hasClicks()) { 40 | Serial.print("has clicks "); 41 | Serial.println(btn.clicks); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For VirtualButton 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | VirtualButton KEYWORD1 9 | VButton KEYWORD1 10 | 11 | VB_DEB KEYWORD1 12 | VB_CLICK KEYWORD1 13 | 14 | ####################################### 15 | # Methods and Functions (KEYWORD2) 16 | ####################################### 17 | setHoldTimeout KEYWORD2 18 | setStepTimeout KEYWORD2 19 | poll KEYWORD2 20 | busy KEYWORD2 21 | reset KEYWORD2 22 | press KEYWORD2 23 | release KEYWORD2 24 | click KEYWORD2 25 | held KEYWORD2 26 | hold KEYWORD2 27 | step KEYWORD2 28 | releaseStep KEYWORD2 29 | hasClicks KEYWORD2 30 | timeout KEYWORD2 31 | 32 | ####################################### 33 | # Constants (LITERAL1) 34 | ####################################### -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=VirtualButton 2 | version=1.1 3 | author=AlexGyver 4 | maintainer=AlexGyver 5 | sentence=Library for advanced button operation for Arduino 6 | paragraph=Library for advanced button operation for Arduino 7 | category=Sensors 8 | url=https://github.com/GyverLibs/VirtualButton 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/VirtualButton.h: -------------------------------------------------------------------------------- 1 | /* 2 | Библиотека с логикой обработки кнопки (виртуальная кнопка) 3 | Документация: 4 | GitHub: https://github.com/GyverLibs/VirtualButton 5 | Возможности: 6 | - Очень лёгкий оптимизированный код 7 | - Множество сценариев использования 8 | - Позволяет расширить функционал других библиотек 9 | - Обработка: 10 | - Антидребезг 11 | - Нажатие 12 | - Отпускание 13 | - Клик 14 | - Несколько кликов 15 | - Счётчик кликов 16 | - Удержание 17 | - Импульсное удержание 18 | - Действия с предварительными кликами 19 | 20 | AlexGyver, alex@alexgyver.ru 21 | https://alexgyver.ru/ 22 | MIT License 23 | 24 | v1.1 - добавлен механизм "таймаута" 25 | */ 26 | 27 | #ifndef _VirtualButton_h 28 | #define _VirtualButton_h 29 | 30 | // ========= НАСТРОЙКИ (можно передефайнить из скетча) ========== 31 | #define _VB_DEB 50 // дебаунс кнопки, мс 32 | #define _VB_CLICK 400 // таймаут накликивания, мс 33 | 34 | // =========== НЕ ТРОГАЙ ============ 35 | #include 36 | 37 | #ifndef VB_DEB 38 | #define VB_DEB _VB_DEB 39 | #endif 40 | #ifndef VB_CLICK 41 | #define VB_CLICK _VB_CLICK 42 | #endif 43 | 44 | // ======================================= CLASS ======================================= 45 | class VButton { 46 | public: 47 | // таймаут удержания кнопки для hold(), 32.. 8100 мс (по умолч. 1000 мс) 48 | void setHoldTimeout(uint16_t tout) { 49 | _holdT = tout >> 5; 50 | } 51 | 52 | // период импульсов step(), 32.. 8100 мс (по умолч. 500 мс) 53 | void setStepTimeout(uint16_t tout) { 54 | _stepT = tout >> 5; 55 | } 56 | 57 | // опрос, вернёт true если статус кнопки изменился. Принимает состояние кнопки (1 - нажата) 58 | bool poll(bool s) { 59 | uint16_t prev = _flags; 60 | if (s || readF(9)) pollBtn(s); // опрос если кнопка нажата или не вышли таймауты 61 | return (prev != _flags); 62 | } 63 | 64 | // сбросить все флаги 65 | void reset() { 66 | _flags = 0; 67 | } 68 | 69 | // ======================================= BTN ======================================= 70 | bool busy() { return readF(9); } // вернёт true, если всё ещё нужно вызывать tick для опроса таймаутов 71 | bool press() { return checkF(3); } // кнопка нажата 72 | bool release() { return checkF(10); } // кнопка отпущена 73 | bool click() { return checkF(0); } // клик по кнопке 74 | 75 | bool held() { return checkF(1); } // кнопка удержана 76 | bool hold() { return readF(4); } // кнопка удерживается 77 | bool step() { return checkF(2); } // режим импульсного удержания 78 | bool releaseStep() { return checkF(12); } // кнопка отпущена после импульсного удержания 79 | 80 | bool held(uint8_t clk) { return (clicks == clk) ? checkF(1) : 0; } // кнопка удержана с предварительным накликиванием 81 | bool hold(uint8_t clk) { return (clicks == clk) ? readF(4) : 0; } // кнопка удерживается с предварительным накликиванием 82 | bool step(uint8_t clk) { return (clicks == clk) ? checkF(2) : 0; } // режим импульсного удержания с предварительным накликиванием 83 | bool releaseStep(uint8_t clk) { return (clicks == clk) ? checkF(12) : 0; } // кнопка отпущена после импульсного удержания с предварительным накликиванием 84 | 85 | bool hasClicks(uint8_t num) { return (clicks == num && checkF(7)) ? 1 : 0; } // имеются клики 86 | uint8_t hasClicks() { return checkF(6) ? clicks : 0; } // имеются клики 87 | 88 | // с момента отпускания кнопки прошло указанное время, миллисекунд 89 | bool timeout(uint16_t tout) { return ((uint16_t)(millis() & 0xFFFF) - _debTmr > tout && checkF(15)); } 90 | 91 | uint8_t clicks = 0; // счётчик кликов 92 | 93 | private: 94 | // ===================================== POOL BTN ===================================== 95 | void pollBtn(bool state) { 96 | uint16_t ms = millis() & 0xFFFF; 97 | uint16_t debounce = ms - _debTmr; 98 | if (state) { // кнопка нажата 99 | setF(9); // busy флаг 100 | if (!readF(8)) { // и не была нажата ранее 101 | if (readF(14)) { // ждём дебаунс 102 | if (debounce > VB_DEB) { // прошел дебаунс 103 | _flags |= 0b100001000; // set 8 3 кнопка нажата 104 | _debTmr = ms; // сброс таймаутов 105 | } 106 | } else { // первое нажатие 107 | setF(14); // запомнили что хотим нажать 108 | if (debounce > VB_CLICK || readF(5)) { // кнопка нажата после VB_CLICK 109 | clicks = 0; // сбросить счётчик и флаг кликов 110 | _flags &= ~0b0011000011101111; // clear 0 1 2 3 5 6 7 12 13 111 | } 112 | _debTmr = ms; 113 | } 114 | } else { // кнопка уже была нажата 115 | if (!readF(4)) { // и удержание ещё не зафиксировано 116 | if (debounce >= (uint16_t)(_holdT << 5)) { // прошло больше удержания 117 | _flags |= 0b00110010; // set 1 4 5 запомнили что удерживается и отключаем сигнал о кликах 118 | _debTmr = ms; // сброс таймаута 119 | } 120 | } else { // удержание зафиксировано 121 | if (debounce > (uint16_t)(_stepT << 5)) { // таймер степа 122 | _flags |= 0b0010000000000100; // set 2 13 step 123 | _debTmr = ms; // сброс таймаута 124 | } 125 | } 126 | } 127 | } else { // кнопка не нажата 128 | if (readF(8)) { // но была нажата 129 | if (debounce > VB_DEB) { 130 | if (!readF(4)) { // не удерживали - это клик 131 | setF(0); // click 132 | clicks++; 133 | } 134 | _flags &= ~0b100010000; // clear 8 4 135 | _debTmr = ms; // сброс таймаута 136 | _flags |= (1 << 10) | (1 << 15); // set 10 15 137 | if (checkF(13)) setF(12); // кнопка отпущена после step 138 | } 139 | } else if (clicks && !readF(5)) { // есть клики 140 | if (debounce > VB_CLICK) _flags |= 0b11100000; // set 5 6 7 (клики) 141 | } else clrF(9); // снимаем busy флаг 142 | checkF(14); // сброс ожидания нажатия 143 | } 144 | } 145 | 146 | // ===================================== MISC ===================================== 147 | bool checkF(const uint8_t val) { return readF(val) ? clrF(val), 1 : 0; } 148 | inline void setF(const uint8_t x) __attribute__((always_inline)) {_flags |= 1 << x;} 149 | inline void clrF(const uint8_t x) __attribute__((always_inline)) {_flags &= ~(1 << x);} 150 | inline bool readF(const uint8_t x) __attribute__((always_inline)) {return _flags & (1 << x);} 151 | 152 | uint16_t _flags = 0; 153 | uint8_t _holdT = 1000 >> 5; 154 | uint8_t _stepT = 500 >> 5; 155 | uint16_t _debTmr = 0; 156 | 157 | // flags 158 | // 0 - click 159 | // 1 - held 160 | // 2 - step 161 | // 3 - press 162 | // 4 - hold 163 | // 5 - clicks flag 164 | // 6 - clicks get 165 | // 7 - clicks get num 166 | // 8 - флаг кнопки 167 | // 9 - busy flag 168 | // 10 - btn released 169 | // 11 - btn level 170 | // 12 - btn released after step 171 | // 13 - step flag 172 | // 14 - deb flag 173 | // 15 - timeout 174 | }; 175 | #endif --------------------------------------------------------------------------------