add lib
This commit is contained in:
parent
eb1a420979
commit
59a740b947
21
libraries/GyverEncoder/LICENSE
Normal file
21
libraries/GyverEncoder/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Alex
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
149
libraries/GyverEncoder/README.md
Normal file
149
libraries/GyverEncoder/README.md
Normal file
@ -0,0 +1,149 @@
|
||||

|
||||

|
||||
# GyverEncoder
|
||||
Библиотека для расширенной работы с энкодером
|
||||
**ВНИМАНИЕ, БИБЛИОТЕКА УСТАРЕЛА! ИСПОЛЬЗУЙ БИБЛИОТЕКУ [EncButton](https://github.com/GyverLibs/EncButton)**
|
||||
- Отработка поворота энкодера
|
||||
- Отработка "нажатого поворота"
|
||||
- Отработка "быстрого поворота"
|
||||
- Несколько алгоритмов опроса энкодера
|
||||
- Выбор подтяжки подключения энкодера
|
||||
- Работа с двумя типами экнодеров
|
||||
- Работа с внешним энкодером (через расширитель пинов и т.п.)
|
||||
- Отработка нажатия/удержания кнопки с антидребезгом
|
||||
|
||||
### Совместимость
|
||||
Совместима со всеми Arduino платформами (используются Arduino-функции)
|
||||
|
||||
### Документация
|
||||
К библиотеке есть [расширенная документация](https://alexgyver.ru/encoder/)
|
||||
|
||||
## Содержание
|
||||
- [Установка](#install)
|
||||
- [Инициализация](#init)
|
||||
- [Использование](#usage)
|
||||
- [Пример](#example)
|
||||
- [Версии](#versions)
|
||||
- [Баги и обратная связь](#feedback)
|
||||
|
||||
<a id="install"></a>
|
||||
## Установка
|
||||
- Библиотеку можно найти по названию **GyverEncoder** и установить через менеджер библиотек в:
|
||||
- Arduino IDE
|
||||
- Arduino IDE v2
|
||||
- PlatformIO
|
||||
- [Скачать библиотеку](https://github.com/GyverLibs/GyverEncoder/archive/refs/heads/main.zip) .zip архивом для ручной установки:
|
||||
- Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64)
|
||||
- Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32)
|
||||
- Распаковать и положить в *Документы/Arduino/libraries/*
|
||||
- (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив
|
||||
- Читай более подробную инструкцию по установке библиотек [здесь](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)
|
||||
|
||||
<a id="init"></a>
|
||||
## Инициализация
|
||||
```cpp
|
||||
Encoder enc; // не привязан к пину
|
||||
Encoder enc(пин CLK, пин DT); // энкодер без кнопки (ускоренный опрос)
|
||||
Encoder enc(пин CLK, пин DT, пин SW); // энкодер с кнопкой
|
||||
Encoder enc(пин CLK, пин DT, пин SW, тип); // энкодер с кнопкой и указанием типа
|
||||
Encoder enc(пин CLK, пин DT, ENC_NO_BUTTON, тип); // энкодер без кнопкой и с указанием типа
|
||||
```
|
||||
|
||||
<a id="usage"></a>
|
||||
## Использование
|
||||
```cpp
|
||||
void tick(); // опрос энкодера, нужно вызывать постоянно или в прерывании
|
||||
void setType(boolean type); // TYPE1 / TYPE2 - тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
||||
void setTickMode(boolean tickMode); // MANUAL / AUTO - ручной или автоматический опрос энкодера функцией tick(). (по умолчанию ручной)
|
||||
void setDirection(boolean direction); // NORM / REVERSE - направление вращения энкодера
|
||||
void setFastTimeout(int timeout); // установка таймаута быстрого поворота
|
||||
void setPinMode(bool mode); // тип подключения энкодера, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
|
||||
void setBtnPinMode(bool mode); // тип подключения кнопки, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
|
||||
|
||||
boolean isTurn(); // возвращает true при любом повороте, сама сбрасывается в false
|
||||
boolean isRight(); // возвращает true при повороте направо, сама сбрасывается в false
|
||||
boolean isLeft(); // возвращает true при повороте налево, сама сбрасывается в false
|
||||
boolean isRightH(); // возвращает true при удержании кнопки и повороте направо, сама сбрасывается в false
|
||||
boolean isLeftH(); // возвращает true при удержании кнопки и повороте налево, сама сбрасывается в false
|
||||
boolean isFastR(); // возвращает true при быстром повороте
|
||||
boolean isFastL(); // возвращает true при быстром повороте
|
||||
|
||||
boolean isPress(); // возвращает true при нажатии кнопки, сама сбрасывается в false
|
||||
boolean isRelease(); // возвращает true при отпускании кнопки, сама сбрасывается в false
|
||||
boolean isClick(); // возвращает true при нажатии и отпускании кнопки, сама сбрасывается в false
|
||||
boolean isHolded(); // возвращает true при удержании кнопки, сама сбрасывается в false
|
||||
boolean isHold(); // возвращает true при удержании кнопки, НЕ СБРАСЫВАЕТСЯ
|
||||
boolean isSingle(); // возвращает true при одиночном клике (после таймаута), сама сбрасывается в false
|
||||
boolean isDouble(); // возвращает true при двойном клике, сама сбрасывается в false
|
||||
void resetStates(); // сбрасывает все is-флаги
|
||||
```
|
||||
|
||||
<a id="example"></a>
|
||||
## Пример
|
||||
Остальные примеры смотри в **examples**!
|
||||
```cpp
|
||||
#define CLK 2
|
||||
#define DT 3
|
||||
#define SW 4
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
Encoder enc1(CLK, DT, SW); // для работы c кнопкой
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
enc1.setType(TYPE2);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
||||
enc1.tick();
|
||||
|
||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
||||
// ваш код
|
||||
}
|
||||
|
||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
||||
if (enc1.isLeft()) Serial.println("Left");
|
||||
|
||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
||||
|
||||
//if (enc1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
|
||||
//if (enc1.isRelease()) Serial.println("Release"); // то же самое, что isClick
|
||||
|
||||
if (enc1.isClick()) Serial.println("Click"); // одиночный клик
|
||||
if (enc1.isSingle()) Serial.println("Single"); // одиночный клик (с таймаутом для двойного)
|
||||
if (enc1.isDouble()) Serial.println("Double"); // двойной клик
|
||||
|
||||
|
||||
if (enc1.isHolded()) Serial.println("Holded"); // если была удержана и энк не поворачивался
|
||||
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
|
||||
}
|
||||
```
|
||||
|
||||
<a id="versions"></a>
|
||||
## Версии
|
||||
- v3.6 от 16.09.2019 - Возвращены дефайны настроек
|
||||
- v4.0 от 13.11.2019
|
||||
- Оптимизирован код
|
||||
- Исправлены баги
|
||||
- Добавлены другие алгоритмы опроса
|
||||
- Добавлена возможность полностью убрать кнопку (экономия памяти)
|
||||
- Добавлена возможность подключения внешнего энкодера
|
||||
- Добавлена настройка подтяжки пинов
|
||||
- v4.1: Исправлено изменение подтяжек
|
||||
- v4.2
|
||||
- Добавлена поддержка TYPE1 для алгоритма PRECISE_ALGORITHM
|
||||
- Добавлена отработка двойного клика: isSingle / isDouble
|
||||
- v4.3: Исправлено ложное isSingle
|
||||
- v4.4: Добавлен метод resetStates, сбрасывает все is-флаги и счётчики
|
||||
- v4.5: Улучшен алгоритм BINARY_ALGORITHM (спасибо Ярославу Курусу)
|
||||
- v4.6: BINARY_ALGORITHM пофикшен для TYPE1, добавлена isReleaseHold
|
||||
- v4.7: Исправлен случайный нажатый поворот в BINARY_ALGORITHM
|
||||
- v4.8: увеличена производительность для AVR Arduino
|
||||
- v4.9: быстрый поворот отключен если кнопка удерживается
|
||||
|
||||
<a id="feedback"></a>
|
||||
## Баги и обратная связь
|
||||
При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru)
|
||||
Библиотека открыта для доработки и ваших **Pull Request**'ов!
|
||||
@ -0,0 +1,61 @@
|
||||
// пример с прерываниями pinChangeInterrupt (прерывания на любом пине)
|
||||
// только для ATmega328 (UNO, Nano, Pro Mini)
|
||||
|
||||
#define SW 0
|
||||
#define DT 2
|
||||
#define CLK 3
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
Encoder enc1(CLK, DT, SW);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// настроить PCINT
|
||||
attachPCINT(CLK);
|
||||
attachPCINT(DT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
enc1.tick(); // оставляем тут для работы "временных" функций и антидребезга
|
||||
|
||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
||||
if (enc1.isLeft()) Serial.println("Left");
|
||||
|
||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
||||
}
|
||||
|
||||
// функция для настройки PCINT для ATmega328 (UNO, Nano, Pro Mini)
|
||||
uint8_t attachPCINT(uint8_t pin) {
|
||||
if (pin < 8) { // D0-D7 // PCINT2
|
||||
PCICR |= (1 << PCIE2);
|
||||
PCMSK2 |= (1 << pin);
|
||||
return 2;
|
||||
}
|
||||
else if (pin > 13) { //A0-A5 // PCINT1
|
||||
PCICR |= (1 << PCIE1);
|
||||
PCMSK1 |= (1 << pin - 14);
|
||||
return 1;
|
||||
}
|
||||
else { // D8-D13 // PCINT0
|
||||
PCICR |= (1 << PCIE0);
|
||||
PCMSK0 |= (1 << pin - 8);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Векторы PCINT, нужно кинуть сюда тики
|
||||
// не обязательно в каждый вектор, достаточно в тот, который задействован
|
||||
// пины 0-7: PCINT2
|
||||
// пины 8-13: PCINT0
|
||||
// пины A0-A5: PCINT1
|
||||
ISR(PCINT0_vect) {
|
||||
//enc1.tick();
|
||||
}
|
||||
ISR(PCINT1_vect) {
|
||||
//enc1.tick();
|
||||
}
|
||||
ISR(PCINT2_vect) {
|
||||
enc1.tick();
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/*
|
||||
В последнее время китайцы стали делать одинаковые модули (ку 40)
|
||||
с разными типами энкодеров - полный период и полпериода.
|
||||
Если ваш энкодер ведёт себя странно (один тик считает за два поворота),
|
||||
то смените тип энкодера
|
||||
*/
|
||||
|
||||
#define CLK 4
|
||||
#define DT 3
|
||||
#define SW 2
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
Encoder enc1(CLK, DT, SW);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
enc1.setType(TYPE2); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
||||
enc1.tick();
|
||||
|
||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
||||
if (enc1.isLeft()) Serial.println("Left");
|
||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
#define CLK 6
|
||||
#define DT 5
|
||||
#define SW 4
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
Encoder enc1(CLK, DT, SW);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
enc1.setTickMode(AUTO);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// enc1.tick(); // не нужна, в этом режиме (AUTO) она входит в каждую функцию!
|
||||
|
||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
||||
// ваш код
|
||||
}
|
||||
|
||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
||||
if (enc1.isLeft()) Serial.println("Left");
|
||||
|
||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
||||
|
||||
if (enc1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
|
||||
if (enc1.isRelease()) Serial.println("Release"); // отпускание кнопки (+ дебаунс)
|
||||
if (enc1.isHolded()) Serial.println("Holded"); // если была удержана и энк не поворачивался
|
||||
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
#define CLK 2
|
||||
#define DT 3
|
||||
#define SW 4
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
//Encoder enc1(CLK, DT); // для работы без кнопки
|
||||
Encoder enc1(CLK, DT, SW); // для работы c кнопкой
|
||||
//Encoder enc1(CLK, DT, SW, TYPE2); // для работы c кнопкой и сразу выбираем тип
|
||||
//Encoder enc1(CLK, DT, ENC_NO_BUTTON, TYPE2); // для работы без кнопки и сразу выбираем тип
|
||||
|
||||
// Варианты инициализации:
|
||||
// Encoder enc; // не привязан к пину
|
||||
// Encoder enc(пин CLK, пин DT); // энкодер без кнопки (ускоренный опрос)
|
||||
// Encoder enc(пин CLK, пин DT, пин SW); // энкодер с кнопкой
|
||||
// Encoder enc(пин CLK, пин DT, пин SW, тип); // энкодер с кнопкой и указанием типа
|
||||
// Encoder enc(пин CLK, пин DT, ENC_NO_BUTTON, тип); // энкодер без кнопкой и с указанием типа
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
enc1.setType(TYPE2);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
||||
enc1.tick();
|
||||
|
||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
||||
// ваш код
|
||||
}
|
||||
|
||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
||||
if (enc1.isLeft()) Serial.println("Left");
|
||||
|
||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
||||
|
||||
//if (enc1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
|
||||
//if (enc1.isRelease()) Serial.println("Release"); // то же самое, что isClick
|
||||
|
||||
if (enc1.isClick()) Serial.println("Click"); // одиночный клик
|
||||
if (enc1.isSingle()) Serial.println("Single"); // одиночный клик (с таймаутом для двойного)
|
||||
if (enc1.isDouble()) Serial.println("Double"); // двойной клик
|
||||
|
||||
|
||||
if (enc1.isHolded()) Serial.println("Holded"); // если была удержана и энк не поворачивался
|
||||
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
#define CLK 2
|
||||
#define DT 3
|
||||
#define SW 4
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
Encoder enc1(CLK, DT, SW);
|
||||
|
||||
int value = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
enc1.setType(TYPE1); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип\=
|
||||
enc1.setFastTimeout(40); // таймаут на скорость isFastR. По умолч. 50
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
||||
enc1.tick();
|
||||
|
||||
if (enc1.isRight()) value++; // если был поворот направо, увеличиваем на 1
|
||||
if (enc1.isLeft()) value--; // если был поворот налево, уменьшаем на 1
|
||||
|
||||
if (enc1.isRightH()) value += 5; // если было удержание + поворот направо, увеличиваем на 5
|
||||
if (enc1.isLeftH()) value -= 5; // если было удержание + поворот налево, уменьшаем на 5
|
||||
|
||||
if (enc1.isFastR()) value += 10; // если был быстрый поворот направо, увеличиваем на 10
|
||||
if (enc1.isFastL()) value -= 10; // если был быстрый поворот налево, уменьшаем на 10
|
||||
|
||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
||||
Serial.println(value); // выводим значение при повороте
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
Пример работы с энкодером с прерыванием. Максимальная чёткость работы
|
||||
в любом быдлокоде!
|
||||
*/
|
||||
|
||||
#define CLK 2
|
||||
#define DT 3
|
||||
#define SW 4
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
Encoder enc1(CLK, DT, SW);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
attachInterrupt(0, isrCLK, CHANGE); // прерывание на 2 пине! CLK у энка
|
||||
attachInterrupt(1, isrDT, CHANGE); // прерывание на 3 пине! DT у энка
|
||||
}
|
||||
|
||||
void isrCLK() {
|
||||
enc1.tick(); // отработка в прерывании
|
||||
}
|
||||
void isrDT() {
|
||||
enc1.tick(); // отработка в прерывании
|
||||
}
|
||||
|
||||
void loop() {
|
||||
enc1.tick();
|
||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
||||
if (enc1.isLeft()) Serial.println("Left");
|
||||
|
||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
// подключаем "внешний" энкодер, для работы с расширителями пинов например
|
||||
|
||||
#define SW 0
|
||||
#define DT 2
|
||||
#define CLK 3
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
Encoder enc1;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
enc1.setType(TYPE2);
|
||||
pinMode(SW, INPUT_PULLUP);
|
||||
pinMode(CLK, INPUT);
|
||||
pinMode(DT, INPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// подаём значения напрямую в tick()
|
||||
// можно подавать лог. величины с любых расширителей пинов!!!
|
||||
// Здесь в качестве примера digitalRead
|
||||
enc1.tick(digitalRead(CLK), digitalRead(DT), !digitalRead(SW));
|
||||
|
||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
||||
// ваш код
|
||||
}
|
||||
|
||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
||||
if (enc1.isLeft()) Serial.println("Left");
|
||||
|
||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
||||
|
||||
if (enc1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
|
||||
if (enc1.isClick()) Serial.println("Click"); // отпускание кнопки (+ дебаунс)
|
||||
//if (enc1.isRelease()) Serial.println("Release"); // то же самое, что isClick
|
||||
|
||||
if (enc1.isHolded()) Serial.println("Holded"); // если была удержана и энк не поворачивался
|
||||
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
|
||||
}
|
||||
31
libraries/GyverEncoder/examples/timer_isr/timer_isr.ino
Normal file
31
libraries/GyverEncoder/examples/timer_isr/timer_isr.ino
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Отработка по прерыванию таймера
|
||||
*/
|
||||
|
||||
#define CLK 7
|
||||
#define DT 8
|
||||
#define SW 9
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
#include "TimerOne.h"
|
||||
Encoder enc1(CLK, DT, SW);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
enc1.setType(TYPE2); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
||||
|
||||
Timer1.initialize(1000); // установка таймера на каждые 1000 микросекунд (= 1 мс)
|
||||
Timer1.attachInterrupt(timerIsr); // запуск таймера
|
||||
}
|
||||
|
||||
void timerIsr() { // прерывание таймера
|
||||
enc1.tick(); // отработка теперь находится здесь
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
||||
if (enc1.isLeft()) Serial.println("Left");
|
||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
// два энкодера
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
Encoder enc1(4, 3, 2);
|
||||
Encoder enc2(7, 6, 5);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
||||
enc1.tick();
|
||||
enc2.tick();
|
||||
|
||||
if (enc1.isLeft()) Serial.println("enc 1 left");
|
||||
if (enc1.isRight()) Serial.println("enc 1 right");
|
||||
if (enc2.isLeft()) Serial.println("enc 2 left");
|
||||
if (enc2.isRight()) Serial.println("enc 2 right");
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
#define CLK 7
|
||||
#define DT 8
|
||||
#define SW 9
|
||||
|
||||
#include "GyverEncoder.h"
|
||||
//Encoder enc1(CLK, DT); // для работы без кнопки
|
||||
Encoder enc1(CLK, DT, SW); // для работы c кнопкой
|
||||
//Encoder enc1(CLK, DT, SW, TYPE2); // для работы c кнопкой и сразу выбираем тип
|
||||
//Encoder enc1(CLK, DT, ENC_NO_BUTTON, TYPE2); // для работы без кнопки и сразу выбираем тип
|
||||
|
||||
int value = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
enc1.setType(TYPE2); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
||||
enc1.tick();
|
||||
|
||||
if (enc1.isRight()) value++; // если был поворот направо, увеличиваем на 1
|
||||
if (enc1.isLeft()) value--; // если был поворот налево, уменьшаем на 1
|
||||
|
||||
if (enc1.isRightH()) value += 5; // если было удержание + поворот направо, увеличиваем на 5
|
||||
if (enc1.isLeftH()) value -= 5; // если было удержание + поворот налево, уменьшаем на 5
|
||||
|
||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
||||
Serial.println(value); // выводим значение при повороте
|
||||
}
|
||||
}
|
||||
52
libraries/GyverEncoder/keywords.txt
Normal file
52
libraries/GyverEncoder/keywords.txt
Normal file
@ -0,0 +1,52 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For GyverEncoder
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Encoder KEYWORD1
|
||||
GyverEncoder KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
tick KEYWORD2
|
||||
setType KEYWORD2
|
||||
setDirection KEYWORD2
|
||||
setFastTimeout KEYWORD2
|
||||
setPinMode KEYWORD2
|
||||
setBtnPinMode KEYWORD2
|
||||
isTurn KEYWORD2
|
||||
isRight KEYWORD2
|
||||
isLeft KEYWORD2
|
||||
isRightH KEYWORD2
|
||||
isLeftH KEYWORD2
|
||||
isFastR KEYWORD2
|
||||
isFastL KEYWORD2
|
||||
|
||||
isPress KEYWORD2
|
||||
isRelease KEYWORD2
|
||||
isReleaseHold KEYWORD2
|
||||
isClick KEYWORD2
|
||||
isSingle KEYWORD2
|
||||
isDouble KEYWORD2
|
||||
isHolded KEYWORD2
|
||||
isHold KEYWORD2
|
||||
resetStates KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
TYPE1 LITERAL1
|
||||
TYPE2 LITERAL1
|
||||
MANUAL LITERAL1
|
||||
AUTO LITERAL1
|
||||
NORM LITERAL1
|
||||
REVERSE LITERAL1
|
||||
HIGH_PULL LITERAL1
|
||||
LOW_PULL LITERAL1
|
||||
ENC_NO_BUTTON LITERAL1
|
||||
9
libraries/GyverEncoder/library.properties
Normal file
9
libraries/GyverEncoder/library.properties
Normal file
@ -0,0 +1,9 @@
|
||||
name=GyverEncoder
|
||||
version=4.9
|
||||
author=AlexGyver <alex@alexgyver.ru>
|
||||
maintainer=AlexGyver <alex@alexgyver.ru>
|
||||
sentence=Advanced encoder control library
|
||||
paragraph=Advanced encoder control library
|
||||
category=Sensors
|
||||
url=https://github.com/GyverLibs/GyverEncoder
|
||||
architectures=*
|
||||
352
libraries/GyverEncoder/src/GyverEncoder.cpp
Normal file
352
libraries/GyverEncoder/src/GyverEncoder.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
#include "GyverEncoder.h"
|
||||
|
||||
#if defined(PRECISE_ALGORITHM)
|
||||
const int8_t KNOBDIR[] = {
|
||||
0, -1, 1, 0,
|
||||
1, 0, 0, -1,
|
||||
-1, 0, 0, 1,
|
||||
0, 1, -1, 0,
|
||||
};
|
||||
int8_t encPos = 0;
|
||||
#endif
|
||||
|
||||
// ================= CONSTRUCTOR =================
|
||||
Encoder::Encoder() {
|
||||
flags.use_button = true;
|
||||
}
|
||||
|
||||
Encoder::Encoder(uint8_t clk, uint8_t dt, int8_t sw, bool type) {
|
||||
_CLK = clk;
|
||||
_DT = dt;
|
||||
if (sw != -1) {
|
||||
_SW = sw;
|
||||
flags.use_button = true;
|
||||
} else {
|
||||
flags.use_button = false;
|
||||
}
|
||||
flags.enc_type = type;
|
||||
|
||||
#if defined(__AVR__)
|
||||
_pin_reg_CLK = portInputRegister(digitalPinToPort(_CLK));
|
||||
_bit_mask_CLK = digitalPinToBitMask(_CLK);
|
||||
_pin_reg_DT = portInputRegister(digitalPinToPort(_DT));
|
||||
_bit_mask_DT = digitalPinToBitMask(_DT);
|
||||
if (sw != -1) {
|
||||
_pin_reg_SW = portInputRegister(digitalPinToPort(_SW));
|
||||
_bit_mask_SW = digitalPinToBitMask(_SW);
|
||||
}
|
||||
#endif
|
||||
|
||||
pinMode(_CLK, (DEFAULT_ENC_PULL ? INPUT : INPUT_PULLUP));
|
||||
pinMode(_DT, (DEFAULT_ENC_PULL ? INPUT : INPUT_PULLUP));
|
||||
if (flags.use_button) pinMode(_SW, (DEFAULT_BTN_PULL ? INPUT : INPUT_PULLUP));
|
||||
flags.invBtn = (DEFAULT_BTN_PULL == HIGH_PULL) ? true : false;
|
||||
|
||||
#if defined(FAST_ALGORITHM)
|
||||
prevState = _readCLK();
|
||||
#else
|
||||
prevState = _readCLK() | (_readDT() << 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ================= SET =================
|
||||
void Encoder::setDirection(bool direction) {
|
||||
if (direction) {
|
||||
uint8_t buf = _CLK;
|
||||
_CLK = _DT;
|
||||
_DT = buf;
|
||||
}
|
||||
}
|
||||
void Encoder::setPinMode(bool mode) {
|
||||
pinMode(_CLK, (mode) ? INPUT : INPUT_PULLUP);
|
||||
pinMode(_DT, (mode) ? INPUT : INPUT_PULLUP);
|
||||
}
|
||||
void Encoder::setBtnPinMode(bool mode) {
|
||||
pinMode(_SW, (mode) ? INPUT : INPUT_PULLUP);
|
||||
flags.invBtn = (mode) ? 0 : 1;
|
||||
}
|
||||
void Encoder::setType(bool type) {
|
||||
flags.enc_type = type;
|
||||
}
|
||||
void Encoder::setTickMode(bool tickMode) {
|
||||
flags.enc_tick_mode = tickMode;
|
||||
}
|
||||
void Encoder::setFastTimeout(uint16_t timeout) {
|
||||
_fast_timeout = timeout;
|
||||
}
|
||||
|
||||
// ================= IS =================
|
||||
// повороты
|
||||
boolean Encoder::isTurn() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isTurn_f) {
|
||||
flags.isTurn_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isRight() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (encState == 2) {
|
||||
encState = 0;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isLeft() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (encState == 1) {
|
||||
encState = 0;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isRightH() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (encState == 4) {
|
||||
encState = 0;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isLeftH() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (encState == 3) {
|
||||
encState = 0;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isFastR() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isFastR_f) {
|
||||
flags.isFastR_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isFastL() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isFastL_f) {
|
||||
flags.isFastL_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
// кнопка
|
||||
boolean Encoder::isPress() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isPress_f) {
|
||||
flags.isPress_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isRelease() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isRelease_f) {
|
||||
flags.isRelease_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isReleaseHold() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isReleaseHold_f) {
|
||||
flags.isReleaseHold_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isClick() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isRelease_f) {
|
||||
flags.isRelease_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isHolded() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.hold_flag && flags.isHolded_f) {
|
||||
flags.isHolded_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isSingle() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isSingle_f) {
|
||||
flags.isSingle_f = false;
|
||||
flags.isDouble_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isDouble() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
if (flags.isDouble_f) {
|
||||
flags.isDouble_f = false;
|
||||
flags.isSingle_f = false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
boolean Encoder::isHold() {
|
||||
if (flags.enc_tick_mode) Encoder::tick();
|
||||
return (SW_state);
|
||||
}
|
||||
|
||||
void Encoder::resetStates() {
|
||||
encState = 0;
|
||||
flags.isTurn_f = false;
|
||||
flags.isFastR_f = false;
|
||||
flags.isFastL_f = false;
|
||||
flags.isPress_f = false;
|
||||
flags.isRelease_f = false;
|
||||
flags.isReleaseHold_f = false;
|
||||
flags.isHolded_f = false;
|
||||
flags.isSingle_f = false;
|
||||
flags.isDouble_f = false;
|
||||
}
|
||||
|
||||
// ================= TICK =================
|
||||
void Encoder::tick(bool clk, bool dt, bool sw) {
|
||||
extTick = true;
|
||||
flags.extCLK = clk;
|
||||
flags.extDT = dt;
|
||||
flags.extSW = sw;
|
||||
Encoder::tick();
|
||||
extTick = false;
|
||||
}
|
||||
|
||||
void Encoder::tick() {
|
||||
uint32_t thisMls = millis();
|
||||
uint32_t debounceDelta = thisMls - debounce_timer;
|
||||
|
||||
#ifdef ENC_WITH_BUTTON
|
||||
if (flags.use_button) {
|
||||
if (!extTick) SW_state = _readSW() ^ flags.invBtn; // читаем состояние кнопки SW
|
||||
else SW_state = flags.extSW;
|
||||
|
||||
if (SW_state && !flags.butt_flag && (debounceDelta > ENC_DEBOUNCE_BUTTON)) {
|
||||
flags.butt_flag = true;
|
||||
flags.turn_flag = false;
|
||||
debounce_timer = thisMls;
|
||||
debounceDelta = 0;
|
||||
flags.isPress_f = true;
|
||||
flags.isHolded_f = true;
|
||||
flags.doubleAllow = true;
|
||||
}
|
||||
if (!SW_state && flags.butt_flag && (debounceDelta > ENC_DEBOUNCE_BUTTON)) {
|
||||
if (!flags.turn_flag && !flags.hold_flag) { // если кнопка отпущена и ручка не поворачивалась
|
||||
flags.turn_flag = false;
|
||||
flags.isRelease_f = true;
|
||||
}
|
||||
if (debounceDelta > ENC_HOLD_TIMEOUT) flags.isReleaseHold_f = true;
|
||||
flags.butt_flag = false;
|
||||
debounce_timer = thisMls;
|
||||
debounceDelta = 0;
|
||||
flags.hold_flag = false;
|
||||
|
||||
if (flags.doubleAllow && !flags.doubleFlag) {
|
||||
flags.doubleFlag = true;
|
||||
flags.countFlag = false;
|
||||
} else {
|
||||
flags.countFlag = true;
|
||||
}
|
||||
}
|
||||
if (flags.doubleFlag && debounceDelta > ENC_DOUBLE_TIMEOUT) {
|
||||
if (!flags.turn_flag) {
|
||||
if (!flags.countFlag) flags.isSingle_f = true;
|
||||
else flags.isDouble_f = true;
|
||||
}
|
||||
flags.doubleFlag = false;
|
||||
}
|
||||
if (flags.butt_flag && debounceDelta > ENC_HOLD_TIMEOUT && !flags.turn_flag) {
|
||||
if (SW_state) {
|
||||
flags.hold_flag = true;
|
||||
flags.doubleAllow = false;
|
||||
} else {
|
||||
flags.butt_flag = false;
|
||||
flags.hold_flag = false;
|
||||
debounce_timer = thisMls;
|
||||
debounceDelta = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FAST_ALGORITHM)
|
||||
uint8_t curState = (extTick) ? (flags.extCLK) : (_readCLK());
|
||||
|
||||
if (curState != prevState
|
||||
#if (ENC_DEBOUNCE_TURN > 0)
|
||||
&& (debounceDelta > ENC_DEBOUNCE_TURN)
|
||||
#endif
|
||||
) {
|
||||
encState = 0;
|
||||
turnFlag = !turnFlag;
|
||||
if (turnFlag || !flags.enc_type) {
|
||||
if (( (extTick) ? (flags.extDT) : _readDT() ) != prevState) {
|
||||
encState = 1;
|
||||
} else {
|
||||
encState = 2;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(BINARY_ALGORITHM)
|
||||
uint8_t curState = (extTick) ? (flags.extCLK | (flags.extDT << 1)) : (_readCLK() | (_readDT() << 1));
|
||||
|
||||
if (curState != prevState
|
||||
#if (ENC_DEBOUNCE_TURN > 0)
|
||||
&& (debounceDelta > ENC_DEBOUNCE_TURN)
|
||||
#endif
|
||||
) {
|
||||
encState = 0;
|
||||
if (flags.rst_flag) {
|
||||
if (curState == 0b11) {
|
||||
flags.rst_flag = 0;
|
||||
//encState = 3-prevState;
|
||||
switch (prevState) {
|
||||
case 0b10: encState = 1; break; // 2 - 1
|
||||
case 0b01: encState = 2; break; // 1 - 2
|
||||
}
|
||||
} else if (!flags.enc_type && (curState == 0b00)) {
|
||||
flags.rst_flag = 0;
|
||||
//encState = prevState;
|
||||
switch (prevState) {
|
||||
case 0b01: encState = 1; break;
|
||||
case 0b10: encState = 2; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (curState == 0b00 || (!flags.enc_type && curState == 0b11)) flags.rst_flag = 1;
|
||||
|
||||
#elif defined(PRECISE_ALGORITHM)
|
||||
uint8_t curState = (extTick) ? (flags.extCLK | (flags.extDT << 1)) : (_readCLK() | (_readDT() << 1));
|
||||
|
||||
if (curState != prevState
|
||||
#if (ENC_DEBOUNCE_TURN > 0)
|
||||
&& (debounceDelta > ENC_DEBOUNCE_TURN)
|
||||
#endif
|
||||
) {
|
||||
encState = 0;
|
||||
encPos += KNOBDIR[curState | (prevState << 2)];
|
||||
if (flags.enc_type) {
|
||||
if (curState == 0x3 && encPos != 0) {
|
||||
encState = (encPos == 4) ? 1 : 2;
|
||||
encPos = 0;
|
||||
}
|
||||
} else {
|
||||
if ((curState == 0x3 || !curState) && encPos != 0) {
|
||||
encState = (encPos == 2) ? 1 : 2;
|
||||
encPos = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (encState != 0) {
|
||||
flags.isTurn_f = true;
|
||||
if (!SW_state && thisMls - fast_timer < _fast_timeout) {
|
||||
if (encState == 1) flags.isFastL_f = true;
|
||||
else if (encState == 2) flags.isFastR_f = true;
|
||||
fast_timer = thisMls;
|
||||
} else fast_timer = thisMls;
|
||||
#ifdef ENC_WITH_BUTTON
|
||||
if (flags.use_button && SW_state) encState += 2;
|
||||
#endif
|
||||
}
|
||||
prevState = curState;
|
||||
flags.turn_flag = true;
|
||||
debounce_timer = thisMls;
|
||||
debounceDelta = 0;
|
||||
}
|
||||
}
|
||||
175
libraries/GyverEncoder/src/GyverEncoder.h
Normal file
175
libraries/GyverEncoder/src/GyverEncoder.h
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
GyverEncoder - библиотека для расширенной работы с энкодером
|
||||
ВНИМАНИЕ, БИБЛИОТЕКА УСТАРЕЛА! ИСПОЛЬЗУЙ БИБЛИОТЕКУ EncButton https://github.com/GyverLibs/EncButton
|
||||
Документация: https://alexgyver.ru/encoder/
|
||||
GitHub: https://github.com/GyverLibs/GyverEncoder
|
||||
Возможности:
|
||||
- Отработка поворота энкодера
|
||||
- Отработка "нажатого поворота"
|
||||
- Отработка "быстрого поворота"
|
||||
- Несколько алгоритмов опроса энкодера
|
||||
- Выбор подтяжки подключения энкодера
|
||||
- Работа с двумя типами экнодеров
|
||||
- Работа с внешним энкодером (через расширитель пинов и т.п.)
|
||||
- Отработка нажатия/удержания кнопки с антидребезгом
|
||||
|
||||
Версии:
|
||||
v3.6 от 16.09.2019 - Возвращены дефайны настроек
|
||||
v4.0 от 13.11.2019
|
||||
- Оптимизирован код
|
||||
- Исправлены баги
|
||||
- Добавлены другие алгоритмы опроса
|
||||
- Добавлена возможность полностью убрать кнопку (экономия памяти)
|
||||
- Добавлена возможность подключения внешнего энкодера
|
||||
- Добавлена настройка подтяжки пинов
|
||||
|
||||
v4.1: Исправлено изменение подтяжек
|
||||
|
||||
v4.2
|
||||
- Добавлена поддержка TYPE1 для алгоритма PRECISE_ALGORITHM
|
||||
- Добавлена отработка двойного клика: isSingle / isDouble
|
||||
|
||||
v4.3: Исправлено ложное isSingle
|
||||
v4.4: Добавлен метод resetStates, сбрасывает все is-флаги и счётчики
|
||||
v4.5: Улучшен алгоритм BINARY_ALGORITHM (спасибо Ярославу Курусу)
|
||||
v4.6: BINARY_ALGORITHM пофикшен для TYPE1, добавлена isReleaseHold
|
||||
v4.7: Исправлен случайный нажатый поворот в BINARY_ALGORITHM
|
||||
v4.8: увеличена производительность для AVR Arduino
|
||||
v4.9: быстрый поворот отключен если кнопка удерживается
|
||||
*/
|
||||
|
||||
#ifndef GyverEncoder_h
|
||||
#define GyverEncoder_h
|
||||
#include <Arduino.h>
|
||||
|
||||
// ========= КОНСТАНТЫ ==========
|
||||
#define ENC_NO_BUTTON -1 // константа для работы без пина
|
||||
#define TYPE1 0 // полушаговый энкодер
|
||||
#define TYPE2 1 // полношаговый
|
||||
#define NORM 0 // направление вращения обычное
|
||||
#define REVERSE 1 // обратное
|
||||
#define MANUAL 0 // нужно вызывать функцию tick() вручную
|
||||
#define AUTO 1 // tick() входит во все остальные функции и опрашивается сама!
|
||||
#define HIGH_PULL 0 // внутренняя подтяжка к питанию (pinMode INPUT_PULLUP)
|
||||
#define LOW_PULL 1 // внешняя подтяжка к GND (pinMode INPUT)
|
||||
|
||||
// =========== НАСТРОЙКИ ===========
|
||||
// закомментируй строку, чтобы полностью убрать отработку кнопки из кода
|
||||
#define ENC_WITH_BUTTON
|
||||
|
||||
// тип подключения энкодера по умолчанию (LOW_PULL или HIGH_PULL)
|
||||
//#define DEFAULT_ENC_PULL LOW_PULL
|
||||
#define DEFAULT_ENC_PULL HIGH_PULL
|
||||
|
||||
// тип подключения кнопки энкодера по умолчанию (LOW_PULL или HIGH_PULL)
|
||||
//#define DEFAULT_BTN_PULL LOW_PULL
|
||||
#define DEFAULT_BTN_PULL HIGH_PULL
|
||||
|
||||
// алгоритмы опроса энкодера (раскомментировать нужный)
|
||||
//#define FAST_ALGORITHM // тик 10 мкс, быстрый, не справляется с люфтами
|
||||
#define BINARY_ALGORITHM // тик 14 мкс, лучше справляется с люфтами
|
||||
//#define PRECISE_ALGORITHM // тик 16 мкс, работает даже с убитым энкодером (по мотивам https://github.com/mathertel/RotaryEncoder)
|
||||
|
||||
// настройка антидребезга энкодера, кнопки, таймаута удержания и таймаута двойного клика
|
||||
#define ENC_DEBOUNCE_TURN 0
|
||||
#define ENC_DEBOUNCE_BUTTON 80
|
||||
#define ENC_HOLD_TIMEOUT 700
|
||||
#define ENC_DOUBLE_TIMEOUT 300
|
||||
|
||||
#if defined(__AVR__)
|
||||
#define _readCLK() bool(*_pin_reg_CLK & _bit_mask_CLK)
|
||||
#define _readDT() bool(*_pin_reg_DT & _bit_mask_DT)
|
||||
#define _readSW() bool(*_pin_reg_SW & _bit_mask_SW)
|
||||
#else
|
||||
#define _readCLK() digitalRead(_CLK)
|
||||
#define _readDT() digitalRead(_DT)
|
||||
#define _readSW() digitalRead(_SW)
|
||||
#endif
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct
|
||||
{
|
||||
bool hold_flag: 1;
|
||||
bool butt_flag: 1;
|
||||
bool turn_flag: 1;
|
||||
bool isTurn_f: 1;
|
||||
bool isPress_f: 1;
|
||||
bool isRelease_f: 1;
|
||||
bool isReleaseHold_f: 1;
|
||||
bool isHolded_f: 1;
|
||||
bool isFastR_f: 1;
|
||||
bool isFastL_f: 1;
|
||||
bool enc_tick_mode: 1;
|
||||
bool enc_type: 1;
|
||||
bool use_button : 1;
|
||||
bool extCLK : 1;
|
||||
bool extDT : 1;
|
||||
bool extSW : 1;
|
||||
bool invBtn : 1;
|
||||
bool isSingle_f : 1;
|
||||
bool isDouble_f : 1;
|
||||
bool countFlag : 1;
|
||||
bool doubleFlag : 1;
|
||||
bool doubleAllow : 1;
|
||||
bool rst_flag : 1;
|
||||
} GyverEncoderFlags;
|
||||
#pragma pack(pop)
|
||||
|
||||
// Варианты инициализации:
|
||||
// Encoder enc; // не привязан к пину
|
||||
// Encoder enc(пин CLK, пин DT); // энкодер без кнопки (ускоренный опрос)
|
||||
// Encoder enc(пин CLK, пин DT, пин SW); // энкодер с кнопкой
|
||||
// Encoder enc(пин CLK, пин DT, пин SW, тип); // энкодер с кнопкой и указанием типа
|
||||
// Encoder enc(пин CLK, пин DT, ENC_NO_BUTTON, тип); // энкодер без кнопкой и с указанием типа
|
||||
|
||||
class Encoder {
|
||||
public:
|
||||
Encoder(); // для непривязанного к пинам энкодера
|
||||
Encoder(uint8_t clk, uint8_t dt, int8_t sw = -1, bool type = false); // CLK, DT, SW, тип (TYPE1 / TYPE2) TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
||||
|
||||
void tick(); // опрос энкодера, нужно вызывать постоянно или в прерывании
|
||||
void tick(bool clk, bool dt, bool sw = 0); // опрос "внешнего" энкодера
|
||||
void setType(bool type); // TYPE1 / TYPE2 - тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
||||
void setPinMode(bool mode); // тип подключения энкодера, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
|
||||
void setBtnPinMode(bool mode); // тип подключения кнопки, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
|
||||
void setTickMode(bool tickMode); // MANUAL / AUTO - ручной или автоматический опрос энкодера функцией tick(). (по умолчанию ручной)
|
||||
void setDirection(bool direction); // NORM / REVERSE - направление вращения энкодера
|
||||
void setFastTimeout(uint16_t timeout); // установка таймаута быстрого поворота
|
||||
|
||||
boolean isTurn(); // возвращает true при любом повороте, сама сбрасывается в false
|
||||
boolean isRight(); // возвращает true при повороте направо, сама сбрасывается в false
|
||||
boolean isLeft(); // возвращает true при повороте налево, сама сбрасывается в false
|
||||
boolean isRightH(); // возвращает true при удержании кнопки и повороте направо, сама сбрасывается в false
|
||||
boolean isLeftH(); // возвращает true при удержании кнопки и повороте налево, сама сбрасывается в false
|
||||
boolean isFastR(); // возвращает true при быстром повороте
|
||||
boolean isFastL(); // возвращает true при быстром повороте
|
||||
|
||||
boolean isPress(); // возвращает true при нажатии кнопки, сама сбрасывается в false
|
||||
boolean isRelease(); // возвращает true при отпускании кнопки, сама сбрасывается в false
|
||||
boolean isReleaseHold(); // возвращает true при отпускании кнопки после удержания, сама сбрасывается в false
|
||||
boolean isClick(); // возвращает true при нажатии и отпускании кнопки, сама сбрасывается в false
|
||||
boolean isHolded(); // возвращает true при удержании кнопки, сама сбрасывается в false
|
||||
boolean isHold(); // возвращает true при удержании кнопки, НЕ СБРАСЫВАЕТСЯ
|
||||
boolean isSingle(); // возвращает true при одиночном клике (после таймаута), сама сбрасывается в false
|
||||
boolean isDouble(); // возвращает true при двойном клике, сама сбрасывается в false
|
||||
|
||||
void resetStates(); // сбрасывает все is-флаги и счётчики
|
||||
|
||||
private:
|
||||
GyverEncoderFlags flags;
|
||||
uint8_t _fast_timeout = 50; // таймаут быстрого поворота
|
||||
uint8_t prevState = 0;
|
||||
uint8_t encState = 0; // 0 не крутился, 1 лево, 2 право, 3 лево нажат, 4 право нажат
|
||||
uint32_t debounce_timer = 0, fast_timer = 0;
|
||||
uint8_t _CLK = 0, _DT = 0, _SW = 0;
|
||||
bool turnFlag = false, extTick = false, SW_state = false;
|
||||
#if defined(__AVR__)
|
||||
volatile uint8_t *_pin_reg_CLK;
|
||||
volatile uint8_t _bit_mask_CLK;
|
||||
volatile uint8_t *_pin_reg_DT;
|
||||
volatile uint8_t _bit_mask_DT;
|
||||
volatile uint8_t *_pin_reg_SW;
|
||||
volatile uint8_t _bit_mask_SW;
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user