Енкодер KY-040 і індикатор TM1637: лічильник на перериваннях
Поворотний енкодер — «нескінченна» ручка для меню й налаштувань. Розбираємо квадратурний сигнал, ловимо кроки перериванням, щоб не пропустити жодного, і виводимо значення на чотирицифровий індикатор TM1637.
Про проєкт
Потенціометр має упори й аналоговий вихід, а енкодер крутиться нескінченно і видає цифрові імпульси: кожне клацання — один крок. Ще в ньому є кнопка під ручкою. Ідеально для меню, гучності чи уставок термостата. Лічимо кроки на перериванні й показуємо число на індикаторі TM1637.
Що знадобиться
- ESP32 DevKit
- Енкодер-модуль KY-040
- 4-розрядний 7-сегментний індикатор TM1637
- Бібліотека TM1637Display (avishorp)
Схема
| Модуль | Вивід | ESP32 |
|---|---|---|
| KY-040 | CLK | GPIO25 |
| DT | GPIO26 | |
| SW | GPIO27 | |
| + / GND | 3V3 / GND | |
| TM1637 | CLK | GPIO22 |
| DIO | GPIO23 | |
| VCC / GND | 3V3 / GND |
Модуль KY-040 уже має підтягувальні резистори 10 кОм на CLK і DT, тож досить INPUT. На кнопці SW підтяжки на модулі немає, тому для неї INPUT_PULLUP.
Квадратурний сигнал
Усередині енкодера два контакти, зсунуті на чверть кроку, — канали A (CLK) і B (DT):
за годинниковою: CLK ‾‾|__|‾‾ DT ‾|__|‾‾‾
проти годинникової: CLK ‾|__|‾‾‾ DT ‾‾|__|‾‾
У момент фронту CLK дивимося на DT: якщо рівні різні, крок в один бік, якщо однакові, в інший. Звідси порівняння digitalRead(DT) != digitalRead(CLK) у коді.
Навіщо переривання
Якщо опитувати енкодер у loop(), а там є delay() або повільний вивід на дисплей, швидкі повороти загубляться. Переривання викликає функцію onClk() у момент фронту, що б не робила програма.
Правила для обробника:
- позначка
IRAM_ATTR, щоб код лежав у швидкій пам'яті; - спільна змінна —
volatile, інакше компілятор може «закешувати» її вloop(); - ніяких
Serial.print()іdelay()усередині: лише мінімальна робота.
Код
// Енкодер KY-040 (переривання) + індикатор TM1637
#include <TM1637Display.h>
TM1637Display display(22, 23); // CLK, DIO
const int ENC_CLK = 25, ENC_DT = 26, ENC_SW = 27;
volatile int value = 0;
void IRAM_ATTR onClk() {
// на кожному фронті CLK рівень DT показує напрямок
if (digitalRead(ENC_DT) != digitalRead(ENC_CLK)) value--;
else value++;
}
void setup() {
pinMode(ENC_CLK, INPUT);
pinMode(ENC_DT, INPUT);
pinMode(ENC_SW, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENC_CLK), onClk, RISING);
display.setBrightness(5);
}
void loop() {
if (digitalRead(ENC_SW) == LOW) value = 0; // натискання ручки — скидання
display.showNumberDec(value);
delay(20);
}
Корисно знати
- Брязкіт. Дешеві енкодери деренчать, і лічильник може «стрибнути» на 2 замість 1. Допоможе конденсатор 10–100 нФ із CLK і DT на землю або бібліотека зі скінченним автоматом (ESP32Encoder використовує апаратний лічильник PCNT).
- Кроки й клацання. У більшості KY-040 на одне клацання припадає один повний цикл квадратури. Деякі дають два імпульси на клацання: тоді ділимо на 2.
- TM1637 — не I2C, хоч теж має два дроти. Його протокол схожий, але без адрес, тож кожен індикатор потребує своєї пари виводів.