ELECTRONICS

Энкодер и Arduino: схема подключения KY-040, скетч и борьба с дребезгом

ЭнкодерыСкетч проверен компиляцией

Энкодер выглядит как обычная ручка громкости, но работает иначе. Потенциометр говорит «я повёрнут на треть», а энкодер — «меня только что крутнули на один щелчок вправо». У него нет ни начала, ни конца: крутите сколько угодно в любую сторону. Именно поэтому его ставят в меню приборов, в 3D-принтеры и в самодельные пульты.

Внутри два контакта, замкнутых через прорези диска. Они срабатывают со сдвигом, и по тому, какой сработал первым, программа понимает направление вращения. Эти два сигнала называются CLK и DT, а третий вывод SW — обычная кнопка: на ручку можно нажать.

Схема подключения

Наведите курсор на провод — расскажу, зачем он нужен.

Распиновка

ПроводКуда и зачем
CLKПервый фазовый выход. Лучше на пин с прерыванием — 2 или 3.
DTВторой фазовый выход, по нему определяется направление.
SWКнопка нажатия на ручку. Замыкается на землю.
+ (VCC)Питание 5 В.
GNDЗемля.

Характеристики

Тип
инкрементальный, механический
Шагов на оборот
20 щелчков
Питание
3,3 или 5 В
Кнопка
есть, нажатие на ось
Подтягивающие резисторы
на плате модуля уже стоят

Дребезг — главная проблема энкодера

Контакты внутри механические, и в момент переключения они не замыкаются один раз, а несколько раз подряд стучат за пару миллисекунд. Микроконтроллер успевает посчитать этот стук как десяток поворотов. Внешне это выглядит так: крутите вправо на один щелчок, а счётчик прыгает на пять или дёргается туда-сюда.

Лечится двумя способами. Программно — игнорировать новые срабатывания в течение двух-трёх миллисекунд после предыдущего, как в скетче ниже. Аппаратно — повесить конденсаторы на сто нанофарад между каждым фазовым выводом и землёй; тогда стук сглаживается ещё до того, как доходит до платы. Надёжнее всего сделать и то, и другое.

Библиотека

не нужнаЭнкодер читается обычными digitalRead и прерыванием. Библиотеки вроде Encoder или NewEncoder пригодятся, когда энкодеров несколько или нужен счёт на высокой скорости.

Готовый скетч

const int PIN_CLK = 2;
const int PIN_DT  = 3;
const int PIN_SW  = 4;

volatile int counter = 0;
volatile unsigned long lastTurn = 0;

void onTurn() {
  // отсекаем дребезг: щелчки чаще 3 мс — это стук контактов, а не рука
  unsigned long now = millis();
  if (now - lastTurn < 3) return;
  lastTurn = now;

  // если второй сигнал отличается от первого — крутят вправо
  if (digitalRead(PIN_DT) != digitalRead(PIN_CLK)) {
    counter++;
  } else {
    counter--;
  }
}

void setup() {
  Serial.begin(9600);
  pinMode(PIN_CLK, INPUT);
  pinMode(PIN_DT, INPUT);
  pinMode(PIN_SW, INPUT_PULLUP);   // кнопка замыкает на землю

  attachInterrupt(digitalPinToInterrupt(PIN_CLK), onTurn, FALLING);
}

void loop() {
  static int shown = 0;
  if (counter != shown) {
    shown = counter;
    Serial.println(shown);
  }

  if (digitalRead(PIN_SW) == LOW) {
    Serial.println("Нажата ручка");
    counter = 0;
    delay(300);                    // чтобы одно нажатие не считалось десятью
  }
}

Скетч собирается arduino-cli под Arduino UNO

Слово volatile перед переменными обязательно: их меняет прерывание, и без этой пометки компилятор решит, что значение не меняется, и подставит старое из регистра.

Частые ошибки

Счётчик прыгает на несколько шагов за щелчок

Дребезг контактов. Добавьте отсечку по времени, как в скетче, и конденсаторы на 100 нФ между CLK и землёй, DT и землёй.

Направление определяется случайно

Перепутаны местами CLK и DT либо энкодер подключён к пинам без прерываний и часть импульсов теряется. Проверьте, что фазовый вывод сидит на пине 2 или 3.

Кнопка срабатывает сама по себе

Забыт режим INPUT_PULLUP. Без внутренней подтяжки вывод болтается в воздухе и ловит наводки.

Значение не меняется, хотя прерывание работает

Переменная объявлена без volatile. Компилятор оптимизировал доступ к ней и не видит изменений, сделанных внутри прерывания.

Энкодер путают с потенциометром

У энкодера нет крайних положений и нет «текущего значения» — он сообщает только приращение. Если нужен именно уровень от нуля до максимума, берите потенциометр.

Что понадобится