KY-040 |
Энкодеры KY-040 часто применяют в различных проектах Arduino. KY-040 как правило выполнен в виде модуля, который состоит из небольшой платы в которую установлен энкодер и 3 подтягивающих (к +5 В) резистора номиналом 10 кОм. При вращении ручки модуля мы получаем два сигнала (A и B), которые противоположны по фазе. Каждый раз, когда сигнал А переходит от положительного уровня к нулю, мы считываем значение выхода В. Если В в этот момент находится в положительном состоянии, значит энкодер вращается по часовой стрелке, если В нуль, то энкодер вращается против часовой стрелки. Считывая оба выхода, можно определить направление вращения, и при помощи подсчета импульсов с А выхода — угол поворота.
Что бы безошибочно определять угол поворота и направление вращения необходимо постоянного опрашивать (считывать) состояние выходов A и B (CLK и DT) энкодера, при этом содержимое скетча не должно влиять на период опроса. Этого можно добиться двумя путями, использовать внешние прерывания или при помощи таймера.
Ниже показан скетч который использует Timer2 для постоянного опроса выходов CLK и DT энкодера.
#define CLK 8 #define DT 9 bool enc_a,enc_b,enc_old_a; int enc_data, enc_data_old; void setup(){ Serial.begin(9600); TCCR1B |= (1 << WGM22)|(1 << CS20)|(1 << CS21); TIMSK2 |= (1 << OCIE2A); OCR2A = 250; // 1 ms pinMode(CLK,INPUT); pinMode(DT,INPUT); } void loop(){ if(enc(1) != enc_data_old){enc_data_old = enc(1); Serial.println(enc(1)); } } int enc(bool byte_s){ enc_a = digitalRead(CLK); _delay_us(500); enc_b = digitalRead(DT); if((!enc_a) && (enc_old_a)){ if(enc_b) {enc_data++;} else {enc_data--;}} enc_old_a = enc_a; if(byte_s == 0){enc_data = 0;} return enc_data; } ISR (TIMER2_COMPA_vect){enc(1);}
Период опроса выходов CLK и DT 1 мс. При при вращении ручки энкодера в монитор порта выводится значение функции enc(1). Для обнуления значения функции используйте выражение enc(0).
Для удобства использования можно использовать библиотеку ENC (созданную на основе скетча показанного выше).
Пример использования:
#include <ENC.h> // http://rcl-radio.ru/wp-content/uploads/2020/08/ENC-1.zip int data_old; ENC enc(8,9); // D8, D9 / DT, CLK void setup(){ Serial.begin(9600); } void loop(){ if(enc.data(1) != data_old){ data_old = enc.data(1); Serial.println(enc.data(1)); // enc.data(0); // обнуление функции } } ISR (TIMER2_COMPA_vect){enc.data(1);}
При использовании библиотеки можно использовать цифровые входы D2 … D13 (Arduino Nano)
Александр, библиотека ENC.h вступает в конфликт с IRremote.h версии 2.2.3 (взял с вашего сайта, но есть более новая). Проблема в том, что при нажатии на одну и ту же кнопку в мониторе порта получаю совершенно разные хаотичные коды. Отключаю (комментирую) ENC.h пульт начинает нормально работать, отдельно ENC.h работает замечательно. Что делать?
Библиотека энкодеоа и IR (скаченная с моего сайта) используют один и тот же таймер. Скачайте библиотеку IR не с моего сайта, она должна работать на таймере1, библиотека энкодера использует таймер2.
Скачал IRremote.h с гитхаба, всё то же самое… А есть возможность сделать два варианта ENC.h на Timer1 и Timer2 ?
В библиотеке IRemote найдите файл boarddefs.h. Далее найдите строчки:
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
// ATmega48, ATmega88, ATmega168, ATmega328
#define IR_USE_TIMER1 // tx = pin 9
//#define IR_USE_TIMER2 // tx = pin 3
#endif
таймер 2 должен быть закомментирован.
Так же в скетче нужно подключать этот файл:
#include «boarddefs.h»
Александр, всё заработало! Спасибо за компактную, неглючную, понятную в работе и быстродействующую библиотеку для обработки команд с энкодера!
Пошёл учить регистры портов (Arduino)… :-))