├── .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 | [](https://github.com/GyverLibs/VirtualButton/releases/latest/download/VirtualButton.zip)
2 | [](https://alexgyver.ru/)
3 | [](https://alexgyver.ru/support_alex/)
4 | [](https://github-com.translate.goog/GyverLibs/VirtualButton?_x_tr_sl=ru&_x_tr_tl=en)
5 |
6 | [](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 | 
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
--------------------------------------------------------------------------------