elchupanibrei (elchupanibrei) wrote,
elchupanibrei
elchupanibrei

Categories:

Маленькая и быстрая библиотека для энкодера

Давно хотел разобраться с "крутилкой". Наконец появилось время и желание это сделать. В паутине нашел три метода обработки кода грея для энкодера.



Первый самый примитивный. Использует тонны if-else и програмный debounce на millis(). Работает медленно. Вот скриншот такой копипасты.


счетчик энкодера у курильщика с ардуино головного мозга

С переходными процессами в этом примере разбираются без таймера. Тупо ждут микросекунду. Шах и мат перфекционисты. Вторая особенность - вешают функцию onA() на первое прерывание, а onB() на второе. Зачем? Никто не запрещает читать encoder_A_Pin вместе с encoder_B_Pin при срабатывании внешнего прерывания на onA(). Освободившийся interrupt можно использовать для кнопки или второго энкодера.

Второй метод на основе массива всех возможных состояний энкодера. А их не много не мало 16 штук. Достоинства. Простота кода. Чуть-чуть быстрее if-else. Автоматический debounce - все ложные состояния отбрасываются. Правда при сильном дребезге отбрасываются и истиные значения - энкодер кликает, а счетчик не срабатывает. Лечится добавлением 100nF/0.1μF конденсаторов между ногами энкодера и землей.


таблица состояний энкодера

Самый продвинутый - это доработанный второй. Из 16 состояний удаляются бесполезные. Какая нам польза от знания где крутилка до/после клика? На основе оставшихся 4-х комбинаций с помощью булевой алгебры и switch-case делается простейший счетчик. Все! Правда есть нюанс. Функция digitalRead() оказалась настолько медленной, что ATmega328 не успевал читать значения pinA и pinB при срабатывании внешнего прерывания с условием CHANGE на pin A. Поэтому для AVR пришлось использовать прерывание по Timer1. Каждые 0.01 секунд срабатывает таймер и AVR не спеша читает состояние пинов и обновляет счетчик энкодера. Для быстрых STM32 и ESP8266 все работает на внешнем прерывании - как только энкодер начинает крутиться, срабатывает внешнее прерывание на pinA, считываются значения pinA и pinB и обновляется позиция энкодера. UDP: Версия библиотеки подросла до 1.4.1 - заменен тормозной digitalRead() для ATmega328 . Тепрь AVR работает без костыля Timer1.


счетчик энкодера здорового человека

Библиотека подсчитывает только физические клики, оставляя все лишнее за бортом. Внутренняя подтяжка включена и доплнительные резисторы не нужны. У популярного шилда KY-040 10КОм уже есть на плате и подключать их НЕ НАДО.

Чтобы подавить дребезг и избежать пропуск кликов нужно добавить конденсаторы:
- 100nF/0.1μF между A и землей
- 100nF/0.1μF между B и землей
- 100nF/0.1μF между кнопкой и землей

БЕЗ КОНДЕНСАТОРОВ БИБЛИОТЕКА РАБОТАТЬ НЕ БУДЕТ!!!



железный debounce

С теорией по методам устранения дребезга можно ознакомится здесь. Калькулятор для подбора гасящего конденсатора тут. Чем больше емкость конденсаторов, тем выше износ контактов энкодера.


расшифровка контактов KY-040

UDP: Переписал код. Теперь еще быстрее, меньше в размере и винарнее. Для кого-то недостаток, для кого-то достоинство, но теперь без аппаратных прерываний не работает. Спасибо товарищу kotyamba за консультацию и знания.

UDP2: Пришлось опять переписать код. Как правильно заметил ksergey9 в комментариях, наше с kotyamba творение более менее нормально работало на медленном AVR. Как только его запускали на быстрых Cortex все превращалось в тыкву. Тепрь все ОК. Лично проверил на Arduino Nano 16Mhz, STM32 Blue Pill и ESP8266.

UDP3: Воспользовался ООП и путем наследования сделал тяжелый класс с float - "RotaryEncoderAdvanced". В нем можно прописывать количество шагов на клик, минимальное и максимальное значение. Получился законченный велосипед. Естественно легкий класс "RotaryEncoder" никуда не делся и работает без изменений.

UDP4: Переделал "RotaryEncoderAdvanced" на template, прощай float. Библиотека может занимать меньше памяти - все зависит от типа используемых переменных. Добавил возможность на лету менять - step per click, minimum value и maximum value. Управляем множеством различных значений с помощью одного энкодера!!!

UDP5: Тормозной digitalRead() для ATmega328 заменен на быстрый, теперь все работает без костыля Timer1.

Забирать как всегда тут.
Tags: #arduino, arduino
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 36 comments