Skip to content

Commit 2eadc61

Browse files
committed
upd
1 parent 3928238 commit 2eadc61

File tree

9 files changed

+272
-83
lines changed

9 files changed

+272
-83
lines changed

README.md

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@
174174
| | VirtButton | VirtEncButton | Button | EncButton |
175175
|-----------------|:----------:|:-------------:|:------:|:---------:|
176176
| read | | | ✔ | |
177-
| readBtn | | | | ✔ |
177+
| readBtn | | | | ✔ |
178+
| tickRaw | ✔ | ✔ | ✔ | ✔ |
178179
| setHoldTimeout | ✔ | ✔ | ✔ | ✔ |
179180
| setStepTimeout | ✔ | ✔ | ✔ | ✔ |
180181
| setClickTimeout | ✔ | ✔ | ✔ | ✔ |
@@ -211,9 +212,11 @@
211212
| setEncReverse | ✔ | ✔ | ✔ | ✔ |
212213
| setEncType | ✔ | ✔ | ✔ | ✔ |
213214
| setEncISR | ✔ | ✔ | ✔ | ✔ |
215+
| clear | ✔ | ✔ | ✔ | ✔ |
214216
| turn | ✔ | ✔ | ✔ | ✔ |
215217
| dir | ✔ | ✔ | ✔ | ✔ |
216218
| tickRaw | ✔ | ✔ | ✔ | ✔ |
219+
| pollEnc | ✔ | ✔ | ✔ | ✔ |
217220
| counter | ✔ | ✔ | ✔ | ✔ |
218221
| setFastTimeout | | | ✔ | ✔ |
219222
| turnH | | | ✔ | ✔ |
@@ -269,6 +272,9 @@ bool tick(VirtButton& b0, VirtButton& b1);
269272
// кнопка нажата в прерывании кнопки
270273
void pressISR();
271274
275+
// обработка кнопки без сброса событий и вызова коллбэка
276+
bool tickRaw(bool s);
277+
272278
// ================== ОПРОС ==================
273279
// кнопка нажата [событие]
274280
bool press();
@@ -355,6 +361,9 @@ void initEnc(bool e0, bool e1);
355361
// инициализация энкодера совмещённым значением
356362
void initEnc(int8_t v);
357363

364+
// сбросить флаги событий
365+
void clear();
366+
358367
// ====================== ОПРОС ======================
359368
// был поворот [событие]
360369
bool turn();
@@ -375,9 +384,14 @@ int8_t tick(bool e0, bool e1);
375384
int8_t tick(int8_t state);
376385
int8_t tick(); // сама обработка в прерывании
377386

378-
// опросить энкодер без установки флагов на поворот (быстрее). Вернёт 1 или -1 при вращении, 0 при остановке
387+
// опросить энкодер без сброса события поворота. Вернёт 1 или -1 при вращении, 0 при остановке
379388
int8_t tickRaw(bool e0, bool e1);
380389
int8_t tickRaw(int8_t state);
390+
int8_t tickRaw(); // сама обработка в прерывании
391+
392+
// опросить энкодер без установки флагов на поворот (быстрее). Вернёт 1 или -1 при вращении, 0 при остановке
393+
int8_t pollEnc(bool e0, bool e1);
394+
int8_t pollEnc(int8_t state);
381395
```
382396
</details>
383397
<details>
@@ -391,6 +405,9 @@ int8_t tickRaw(int8_t state);
391405
// установить таймаут быстрого поворота, мс
392406
void setFastTimeout(uint8_t tout);
393407
408+
// сбросить флаги энкодера и кнопки
409+
void clear();
410+
394411
// ==================== ОПРОС ====================
395412
// нажатый поворот энкодера [событие]
396413
bool turnH();
@@ -419,14 +436,17 @@ uint16_t action();
419436
// ==================== ОБРАБОТКА ====================
420437
// обработка в прерывании (только энкодер). Вернёт 0 в покое, 1 или -1 при повороте
421438
int8_t tickISR(bool e0, bool e1);
422-
423-
// обработка в прерывании (только энкодер). Вернёт 0 в покое, 1 или -1 при повороте
424439
int8_t tickISR(int8_t e01);
425440
426441
// обработка энкодера и кнопки
427442
bool tick(bool e0, bool e1, bool btn);
428443
bool tick(int8_t e01, bool btn);
429444
bool tick(bool btn); // энкодер в прерывании
445+
446+
// обработка энкодера и кнопки без сброса флагов и вызова коллбэка
447+
bool tickRaw(bool e0, bool e1, bool btn);
448+
bool tickRaw(int8_t e01, bool btn);
449+
bool tickRaw(bool btn); // энкодер в прерывании
430450
```
431451
</details>
432452
<details>
@@ -450,6 +470,9 @@ bool read();
450470
451471
// функция обработки, вызывать в loop
452472
bool tick();
473+
474+
// обработка кнопки без сброса событий и вызова коллбэка
475+
bool tickRaw();
453476
```
454477
</details>
455478
<details>
@@ -631,18 +654,93 @@ void loop() {
631654
}
632655
```
633656

657+
Если библиотека используется с подключенным обработчиком событий `attach()` (см. ниже), то можно вызывать `tick()` где угодно и сколько угодно раз, события будут обработаны в обработчике:
658+
```cpp
659+
void cb() {
660+
switch (btn.action()) {
661+
// ...
662+
}
663+
}
664+
665+
void setup() {
666+
btn.attach(cb);
667+
}
668+
669+
void loop() {
670+
btn.tick();
671+
// ...
672+
btn.tick();
673+
// ...
674+
btn.tick();
675+
}
676+
```
677+
634678
#### "Загруженная" программа
635679
Библиотека EncButton - **асинхронная**: она не ждёт, пока закончится обработка кнопки, а позволяет программе выполняться дальше. Это означает, что для корректной работы библиотеки основной цикл программы должен выполняться как можно быстрее и не содержать задержек и других "глухих" циклов внутри себя. Для обеспечения правильной обработки кнопки не рекомендуется иметь в основном цикле задержки длительностью более 50-100 мс. Несколько советов:
636-
- Новичкам: изучите цикл уроков [Как написать скетч](https://alexgyver.ru/lessons/how-to-sketch/)
637-
- Пишите асинхронный код в `loop()`
680+
- Новичкам: изучить цикл уроков [как написать скетч](https://alexgyver.ru/lessons/how-to-sketch/)
681+
- Писать асинхронный код в `loop()`
638682
- Любую синхронную конструкцию на `delay()` можно сделать асинхронной при помощи `millis()`
639-
- Если в вашей программе *каждая* итерация главного цикла выполняется дольше 50-100мс - в большинстве случаев программа написана неправильно, за исключением каких-то особых случаев
640-
- Подключите кнопку на аппаратное прерывание (см. ниже)
641-
- Избегайте выполнения "тяжёлых" участков кода, пока идёт обработка кнопки, например поместив их в условие `if (!button.busy()) { тяжёлый код }`
642-
- Если оптимизировать основной цикл невозможно - вызывайте обработчик в другом "потоке":
683+
- Если в программе *каждая* итерация главного цикла выполняется дольше 50-100мс - в большинстве случаев программа написана неправильно, за исключением каких-то особых случаев
684+
- Подключить кнопку на аппаратное прерывание (см. ниже)
685+
- Избегать выполнения "тяжёлых" участков кода, пока идёт обработка кнопки, например поместив их в условие `if (!button.busy()) { тяжёлый код }`
686+
- Если оптимизировать основной цикл невозможно - вызывать тикер в другом "потоке" и использовать функцию-обработчик:
643687
- В прерывании таймера с периодом ~50мс или чаще
644688
- На другом ядре (например ESP32)
645689
- В другом таске FreeRTOS
690+
- Внутри `yield()` (внутри `delay()`)
691+
692+
#### Раздельная обработка
693+
> Имеет смысл только при ручном опросе событий! При подключенной функции-обработчике достаточно вызывать обычный `tick()` между тяжёлыми участками программы
694+
695+
Также в загруженной программе можно разделить обработку и сброс событий: вместо `tick()` использовать `tickRaw()` между тяжёлыми участками кода и ручной сброс `clear()`. Порядок следующий:
696+
- Опросить действия (click, press, turn...)
697+
- Вызвать `clear()`
698+
- Вызывать `tickRaw()` между тяжёлыми участками кода
699+
700+
```cpp
701+
void loop() {
702+
if (btn.click()) ...
703+
if (btn.press()) ...
704+
if (btn.step()) ...
705+
706+
btn.clear();
707+
708+
// ...
709+
btn.tickRaw();
710+
// ...
711+
btn.tickRaw();
712+
// ...
713+
btn.tickRaw();
714+
// ...
715+
}
716+
```
717+
Это позволит опрашивать кнопку/энкодер в не очень хорошо написанной программе, где основной цикл завален тяжёлым кодом. Внутри `tickRaw()` накапливаются события, которые раз в цикл разбираются, а затем вручную сбрасываются.
718+
719+
> В этом сценарии буферизация энкодера в прерывании не работает и не обрабатываются все события `releaseXxx`
720+
721+
#### Обработка внутри delay
722+
Если сложно избавиться от `delay()` внутри главного цикла программы, то на некоторых платформах можно поместить свой код внутри него. Таким образом можно получить даже обработку энкодера в цикле с дилеями без использования прерываний:
723+
```cpp
724+
// вставка кода в delay
725+
void yield() {
726+
eb.tickRaw();
727+
}
728+
729+
void loop() {
730+
if (eb.click()) ...
731+
if (btn.turn()) ...
732+
733+
eb.clear();
734+
735+
// ...
736+
delay(10);
737+
// ...
738+
delay(50);
739+
// ...
740+
}
741+
```
742+
743+
> В этом сценарии буферизация энкодера в прерывании не работает и не обрабатываются все события `releaseXxx`
646744
647745
#### Обработка кнопки
648746
Библиотека обрабатывает кнопку следующим образом:
@@ -1411,6 +1509,9 @@ void loop() {
14111509
- Сильно оптимизирована скорость работы action() (общий обработчик)
14121510
- Добавлено подключение внешней функции-обработчика событий
14131511
- Добавлена обработка кнопки в прерывании - pressISR()
1512+
- v3.2
1513+
- Добавлены функции tickRaw() и clear() для всех классов. Позволяет проводить раздельную обработку (см. доку)
1514+
- Улучшена обработка кнопки с использованием прерываний
14141515
14151516
<a id="feedback"></a>
14161517
## Баги и обратная связь

keywords.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ waiting KEYWORD2
4949
busy KEYWORD2
5050
action KEYWORD2
5151
attach KEYWORD2
52-
5352
pressISR KEYWORD2
5453

5554
setEncReverse KEYWORD2
@@ -68,6 +67,7 @@ encHolding KEYWORD2
6867
dir KEYWORD2
6968
fast KEYWORD2
7069

70+
pollEnc KEYWORD2
7171
init KEYWORD2
7272
tickRaw KEYWORD2
7373
tickISR KEYWORD2

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=EncButton
2-
version=3.1
2+
version=3.2
33
author=AlexGyver <[email protected]>
44
maintainer=AlexGyver <[email protected]>
55
sentence=Light and powerful library for button and encoder operation for Arduino

src/core/Button.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class Button : public VirtButton {
2828
return VirtButton::tick(EBread(pin));
2929
}
3030

31+
// обработка кнопки без сброса событий и вызова коллбэка
32+
bool tickRaw() {
33+
return VirtButton::tickRaw(EBread(pin));
34+
}
35+
3136
private:
3237
uint8_t pin;
3338
};
@@ -56,5 +61,10 @@ class ButtonT : public VirtButton {
5661
return VirtButton::tick(EBread(PIN));
5762
}
5863

64+
// обработка кнопки без сброса событий и вызова коллбэка
65+
bool tickRaw() {
66+
return VirtButton::tickRaw(EBread(PIN));
67+
}
68+
5969
private:
6070
};

src/core/EncButton.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,17 @@ class EncButton : public VirtEncButton {
3131
}
3232

3333
// функция обработки, вызывать в loop
34-
int8_t tick() {
34+
bool tick() {
3535
if (read_ef(EB_EISR)) return VirtEncButton::tick(EBread(b));
3636
else return VirtEncButton::tick(readEnc(), EBread(b));
3737
}
3838

39+
// функция обработки без сброса событий
40+
bool tickRaw() {
41+
if (read_ef(EB_EISR)) return VirtEncButton::tickRaw(EBread(b));
42+
else return VirtEncButton::tickRaw(readEnc(), EBread(b));
43+
}
44+
3945
// ====================== READ ======================
4046
// прочитать значение кнопки
4147
bool readBtn() {
@@ -77,11 +83,17 @@ class EncButtonT : public VirtEncButton {
7783
}
7884

7985
// функция обработки, вызывать в loop
80-
int8_t tick() {
86+
bool tick() {
8187
if (read_ef(EB_EISR)) return VirtEncButton::tick(EBread(BTN));
8288
else return VirtEncButton::tick(readEnc(), EBread(BTN));
8389
}
8490

91+
// функция обработки без сброса событий
92+
bool tickRaw() {
93+
if (read_ef(EB_EISR)) return VirtEncButton::tickRaw(EBread(BTN));
94+
else return VirtEncButton::tickRaw(readEnc(), EBread(BTN));
95+
}
96+
8597
// ====================== READ ======================
8698
// прочитать значение кнопки
8799
bool readBtn() {

src/core/Encoder.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ class Encoder : public VirtEncoder {
3232
else return VirtEncoder::tick(readEnc());
3333
}
3434

35+
// обработка без сброса события поворота
36+
int8_t tickRaw() {
37+
if (read_ef(EB_EISR)) return VirtEncoder::tickRaw();
38+
else return VirtEncoder::tickRaw(readEnc());
39+
}
40+
3541
private:
3642
uint8_t e0, e1;
3743

@@ -56,7 +62,7 @@ class EncoderT : public VirtEncoder {
5662
pinMode(ENCB, mode);
5763
initEnc(readEnc());
5864
}
59-
65+
6066
// функция обработки для вызова в прерывании энкодера
6167
int8_t tickISR() {
6268
return VirtEncoder::tickISR(readEnc());
@@ -68,6 +74,12 @@ class EncoderT : public VirtEncoder {
6874
else return VirtEncoder::tick(readEnc());
6975
}
7076

77+
// обработка без сброса события поворота
78+
int8_t tickRaw() {
79+
if (read_ef(EB_EISR)) return VirtEncoder::tickRaw();
80+
else return VirtEncoder::tickRaw(readEnc());
81+
}
82+
7183
// прочитать значение энкодера
7284
int8_t readEnc() {
7385
return EBread(ENCA) | (EBread(ENCB) << 1);

0 commit comments

Comments
 (0)