Подключение энкодера к Arduino. GyverEncoder v4.9

ОБНОВЛЕНИЯ


  • v4.7: Исправлен случайный нажатый поворот в BINARY_ALGORITHM
  • v4.8: увеличена производительность для AVR Arduino
  • v4.9: быстрый поворот отключен если кнопка удерживается

ТЕОРИЯ


Энкодер (от англ. encode – преобразовывать) – это устройство для преобразования угловых положений или линейных перемещений в цифровой сигнал, т.е. энкодер – это датчик угла или линейного перемещения, соответственно есть крутильные и линейные энкодеры. Принцип работы энкодера заключается в преобразовании механического перемещения в электрические сигналы, у обычного инкрементального энкодера, который мы будем рассматривать, этот сигнал представляет собой два квадратных сигнала (при равномерном вращении), сдвинутых по фазе на 90 градусов.

Самым хорошим модулем с энкодером на Aliexpress является вот такой, на круглой  плате:

Энкодер: aliexpress, aliexpress, aliexpress, искать

ПОДКЛЮЧЕНИЕ


Подключается модуль энкодера очень просто: питание на питание (GND и VCC), логические пины CLKDT (тактовые выводы энкодера) и SW (вывод кнопки) на любые пины Arduino (D или A). У круглых модулей выводы энкодера подписаны как S1 и S2, а вывод кнопки как Key, подключаются точно так же. От порядка подключения тактовых выводов энкодера зависит “направление” его работы, но это можно поправить в программе.

У модулей энкодера тактовые выводы подтянуты к питанию и дают низкий сигнал при срабатывании, также на них стоят RC цепи для гашения дребезга. Вывод кнопки никуда не подтянут! Промышленный энкодер подключается точно так же, чёрный и красный провода у него питание, остальные – тактовые выходы.

У модулей энкодеров тактовые выходы и кнопка подтянуты к питанию, у круглого модуля также стоят RC цепи для аппаратного подавления дребезга контактов, у KY-40 (прямоугольный) распаяна только подтяжка. Если нужно подключить “голый” энкодер к плате – в целом можно подключить напрямую без обвязки, как на схеме ниже, моя библиотека отработает и подтяжку средствами микроконтроллера (INPUT_PULLUP), и программный антидребезг. Но рекомендуется всё-таки делать RC цепи для кнопки и для тактовых выходов энкодера.

Бывает два типа энкодеров, я назвал их одноимпульсные и двухимпульсные, тип энкодера можно определить по внешнему виду самого энкодера:

Чем отличаются энкодеры на практике: если опрашивать одноимпульсный энкодер как двухимпульсный, то для отработки одного тика нужно повернуть рукоятку на два тика. Если опрашивать двухимпульсный как одноимпульсный, то для отработки одного тика нужно повернуть рукоятку на два тика. То есть при неправильном использовании причина сразу видна.

КОД


Если вам важна не функциональность библиотеки, а максимальная скорость работы с энкодером и минимальное время его опроса, предлагаю следующий код. Здесь используется аппаратное прерывание (одно на один энкодер), для увеличения скорости выполнения прерывания используется функция bitRead вместо digitalRead (скорость выполнения разнится в десятки раз). Также в этом коде предусмотрен выбор типа энкодера соответствующей настройкой. Отработка энкодера идёт параллельно выполнению скетча, переменная encCounter меняет своё значение при повороте рукоятки и выводится через порт.

/*
 Максимально быстрый универсальный код для обработки энкодера
 Работает на перывании (используется одно)
 Тут код построен на bitRead(PIND..) - только для Arduino NANO!
*/
#define ENC_A 2       // пин энкодера
#define ENC_B 4       // пин энкодера
#define ENC_TYPE 1    // тип энкодера, 0 или 1
volatile int encCounter;
volatile boolean state0, lastState, turnFlag;
void setup() {
  Serial.begin(9600);
  attachInterrupt(0, int0, CHANGE);
}
void int0() {
  state0 = bitRead(PIND, ENC_A);
  if (state0 != lastState) {
#if (ENC_TYPE == 1)
    turnFlag = !turnFlag;
    if (turnFlag)
      encCounter += (bitRead(PIND, ENC_B) != lastState) ? -1 : 1;
#else
    encCounter += (bitRead(PIND, ENC_B) != lastState) ? -1 : 1;
#endif
    lastState = state0;
  }
}
void loop() {
  Serial.println(encCounter);
  delay(100);
}
/*
  Максимально быстрый универсальный код для обработки энкодера
  Работает на перывании (используется одно)
  Тут код построен на digitalRead, что делает его универсальным для всех плат Arduino
*/
#define ENC_A 2       // пин энкодера
#define ENC_B 4       // пин энкодера
#define ENC_TYPE 1    // тип энкодера, 0 или 1
volatile int encCounter;
volatile boolean state0, lastState, turnFlag;
void setup() {
  Serial.begin(9600);
  attachInterrupt(0, int0, CHANGE);
}
void int0() {
  state0 = digitalRead(ENC_A);
  if (state0 != lastState) {
#if (ENC_TYPE == 1)
    turnFlag = !turnFlag;
    if (turnFlag)
      encCounter += (digitalRead(ENC_B) != lastState) ? -1 : 1;
#else
    encCounter += (digitalRead(ENC_B) != lastState) ? -1 : 1;
#endif
    lastState = state0;
  }
}
void loop() {
  Serial.println(encCounter);
  delay(100);
}
// алгоритм с "таблицей", позволяющий увеличить точность энкодера
// в 4 раза, работает максимально чётко даже с плохими энкодерами.
// Для увеличения скорости опроса используйте PCINT и чтение из PINn
#define CLK 3
#define DT 2
long pos = 0;
byte lastState = 0;
const int8_t increment[16] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
void setup() {
  Serial.begin(9600);
}
void loop() {
  byte state = digitalRead(CLK) | (digitalRead(DT) << 1);
  if (state != lastState) {
    pos += increment[state | (lastState << 2)];
    lastState = state;
    Serial.println(pos);
  }
}
#define ENC_A 2       // пин энкодера
#define ENC_B 3       // пин энкодера
volatile int encCounter;
volatile boolean flag, resetFlag;
volatile byte curState, prevState;
void setup() {
  Serial.begin(115200);
  attachInterrupt(0, int0, CHANGE);
  attachInterrupt(1, int0, CHANGE);
}
void int0() {
  encTick();
}

// алгоритм со сбросом от Ярослава Куруса
void encTick() {
  curState = digitalRead(ENC_A) | digitalRead(ENC_B) << 1;  // digitalRead хорошо бы заменить чем-нибудь более быстрым
  if (resetFlag && curState == 0b11) {
    if (prevState == 0b10) encCounter++;
    if (prevState == 0b01) encCounter--;
    resetFlag = 0;
    flag = true;
  }
  if (curState == 0b00) resetFlag = 1;
  prevState = curState;
}
void loop() {
  if (flag) {
    Serial.println(encCounter);
    flag = 0;
  }
}
volatile int counter = 0;   // счётчик
volatile bool encFlag = 0;  // флаг поворота

void setup() {
  Serial.begin(9600);
  attachInterrupt(0, encIsr, CHANGE);
  attachInterrupt(1, encIsr, CHANGE);
}

void loop() {
  if (encFlag) {
    Serial.println(counter);
    encFlag = 0;
  }
}

volatile byte reset = 0, last = 0;
void encIsr() {  
  byte state = (PIND & 0b1100) >> 2;  // D2 + D3
  if (reset && state == 0b11) {
    int prevCount = counter;
    if (last == 0b10) counter++;
    else if (last == 0b01) counter--;
    if (prevCount != counter) encFlag = 1;    
    reset = 0;
  }
  if (!state) reset = 1;
  last = state;
}

БИБЛИОТЕКА


GyverEncoder v4.9

Я не нашёл в интернете нормальных библиотек для энкодера с хорошей функциональностью, поэтому написал свою, GyverEncoder. Что умеет:

  • Отработка поворота рукоятки энкодера
    • Обычный поворот
    • “Нажатый поворот”
    • “Быстрый” поворот
  • Три алгоритма опроса энкодера
    • Быстрый – но не справляется с люфтами
    • Бинарный – медленнее, лучше справляется с люфтами
    • Высокоточный – ещё медленнее, но работает даже с убитым энкодером
  • Возможность работы с “виртуальным” энкодером – через расширитель пинов или ещё как
  • Работа с двумя типами энкодеров (тип 1 и 2, см. выше)
  • Работа с кнопкой энкодера:
    • Отработка нажатия
    • Клика
    • Двойного клика
    • Удержания
    • Антидребезг контактов
    • Возможность полностью убрать код кнопки для быстродействия

Поддерживаемые платформы: все Arduino (используются стандартные Wiring-функции)

УСТАНОВКА


  • Библиотеку можно найти и установить через менеджер библиотек по названию GyverEncoder в:
    • Arduino IDE (Инструменты/Управлять библиотеками)
    • Arduino IDE v2 (вкладка «Library Manager»)
    • PlatformIO (PIO Home, вкладка «Libraries»)
  • Про ручную установку читай здесь

ДОКУМЕНТАЦИЯ


Инициализация


Объект энкодера может быть создан несколькими способами:
Encoder enc; // не привязан к пину (для виртуального энкодера, см. пример)
Encoder enc(пин CLK, пин DT); // энкодер без кнопки (ускоренный опрос)
Encoder enc(пин CLK, пин DT, пин SW); // энкодер с кнопкой
Encoder enc(пин CLK, пин DT, пин SW, тип); // энкодер с кнопкой и указанием типа
Encoder enc(пин CLK, пин DT, ENC_NO_BUTTON, тип); // энкодер без кнопки и с указанием типа

Опрос


Опрос энкодера происходит в методе .tick(), после чего можно узнать состояние энкодера из методов is*. Сам .tick() должен вызываться как можно чаще:
  • В loop() - у вас должен быть "прозрачный" loop() без задержек
  • В прерывании таймера - достаточно опрашивать энкодер каждые 5 мс (зависит от скорости поворота)
  • В аппаратном прерывании (достаточно завести одну таковую ногу энкодера)
Для "расшифровки" состояния энкодера используются следующие методы:
  • isTurn(); // возвращает true при любом повороте, сама сбрасывается в false
  • isRight(); // возвращает true при повороте направо, сама сбрасывается в false
  • isLeft(); // возвращает true при повороте налево, сама сбрасывается в false
  • isRightH(); // возвращает true при удержании кнопки и повороте направо, сама сбрасывается в false
  • isLeftH(); // возвращает true при удержании кнопки и повороте налево, сама сбрасывается в false
  • isFastR(); // возвращает true при быстром повороте
  • isFastL(); // возвращает true при быстром повороте
Для кнопки энкодера:
  • isPress(); // возвращает true при нажатии кнопки, сама сбрасывается в false
  • isRelease(); // возвращает true при отпускании кнопки, сама сбрасывается в false
  • isClick(); // возвращает true при нажатии и отпускании кнопки, сама сбрасывается в false
  • isHolded(); // возвращает true при удержании кнопки, сама сбрасывается в false
  • isHold(); // возвращает true при удержании кнопки, НЕ СБРАСЫВАЕТСЯ
  • isSingle(); // возвращает true при одиночном клике (после таймаута), сама сбрасывается в false
  • isDouble(); // возвращает true при двойном клике, сама сбрасывается в false
Примечание: isClick() возвращает true сразу же после отпускания кнопки, в то время как isSingle() возвращает true после таймаута, во время которого можно сделать второй клик и поймать уже двойной клик при помощи isDouble(). В версии 4.4 появился метод resetStates(), который принудительно сбрасывает все флаги is-методов

Настройки в скетче


Некоторые параметры работы энкодера можно настроить из программы:
  • setType(type); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
  • setTickMode(tickMode); // MANUAL / AUTO - ручной или автоматический опрос энкодера функцией tick() (по умолчанию ручной)
  • setDirection(direction); // NORM / REVERSE - направление вращения энкодера
  • setFastTimeout(timeout); // установка таймаута быстрого поворота
  • setPinMode(mode); // тип подключения пинов энкодера, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
  • setBtnPinMode(mode); // тип подключения кнопки, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)

Настройки в библиотеке


В заголовочном файле библиотеки (GyverEncoder.h) есть несколько дополнительных настроек: Время:
  • ENC_DEBOUNCE_TURN 1 // время антидребезга для энкодера, миллисекунд
  • ENC_DEBOUNCE_BUTTON 80 // время антидребезга для кнопки, миллисекунд
  • ENC_HOLD_TIMEOUT 700 // таймаут удержания кнопки, миллисекунд
  • ENC_DOUBLE_TIMEOUT 300 // таймаут двойного клика
Использование кнопки:
  • #define ENC_WITH_BUTTON  // если закомментировать данную строку, опрос кнопки будет полностью "убран" из кода, что сделает его легче и чуть быстрее
Логика подключения:
  • #define DEFAULT_ENC_PULL LOW_PULL // тип подключения энкодера по умолчанию (LOW_PULL или HIGH_PULL)
  • #define DEFAULT_BTN_PULL HIGH_PULL // тип подключения кнопки энкодера по умолчанию (LOW_PULL или HIGH_PULL)

Алгоритмы опроса энкодера


Алгоритм работы библиотеки можно выбрать в заголовочном файле библиотеки (GyverEncoder.h), для этого нужно раскомментировать одну из строк с дефайнами алгоритмов:
  • #define FAST_ALGORITHM // быстрый, не справляется с люфтами
  • #define BINARY_ALGORITHM // медленнее, лучше справляется с люфтами
  • #define PRECISE_ALGORITHM // медленнее, но работает даже с убитым энкодером (по мотивам https://github.com/mathertel/RotaryEncoder)

Работа с "виртуальным" энкодером


Версия библиотеки 4+ поддерживает работу с виртуальным энкодером, т.е. алгоритм опрашивает не напрямую цифровой пин микроконтроллера, а логическую величину, которую ему передадут. Таким образом можно попробовать опрашивать несколько энкодеров, подключенных через расширитель пинов. Для работы с таким энкодером нужно инициализировать энкодер без указания пина:
Encoder enc; // не привязан к пину
Работа с таким энкодером ничем не отличается от обычного, кроме метода tick() - в него нужно передать состояния тактовых пинов энкодера (CLK и DT), а также пина кнопки (опционально):
enc1.tick(stateCLK, stateDT, stateSW);  // с кнопкой
enc1.tick(stateCLK, stateDT);  // без кнопки
Смотрите пример external_enc в папке с примерами
Encoder(); // для непривязанного к пинам энкодера
Encoder(uint8_t clk, uint8_t dt, int8_t sw = -1, bool type = false);  // CLK, DT, SW, тип (TYPE1 / TYPE2) TYPE1 одношаговый, 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 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-флаги

ПРИМЕРЫ


Остальные примеры смотри в папке examples библиотеки, также примеры можно открыть из Arduino IDE/Файл/Примеры

#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.isClick()) Serial.println("Click");         // отпускание кнопки (+ дебаунс)
  //if (enc1.isRelease()) Serial.println("Release");     // то же самое, что isClick
  
  if (enc1.isHolded()) Serial.println("Holded");       // если была удержана и энк не поворачивался
  //if (enc1.isHold()) Serial.println("Hold");         // возвращает состояние кнопки
}
#define CLK 7
#define DT 8
#define SW 9

#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW);

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);   // выводим значение при повороте
  }  
}
#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);            // выводим значение при повороте
  }
}
// два энкодера

#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");
}
// два энкодера

#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");
}
/*
	В последнее время китайцы стали делать одинаковые модули (ку 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");
}
#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");         // возвращает состояние кнопки
}
/*
   Пример работы с энкодером с прерыванием. Максимальная чёткость работы
   в любом быдлокоде!
*/

#define CLK 2
#define DT 3
#define SW 4

#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW);

void setup() {
  Serial.begin(9600);
  attachInterrupt(0, isr, CHANGE);    // прерывание на 2 пине! CLK у энка
}

void isr() {
  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");
}
/*
 * Отработка по прерыванию таймера
 */

#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");  
}

ВИДЕО


ПОДДЕРЖАТЬ


Вы можете поддержать меня за создание доступных проектов с открытым исходным кодом, полный список реквизитов есть вот здесь.

5 1 голос
Рейтинг статьи
Подписаться
Уведомить о
guest

60 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Прокрутить вверх