Механический энкодер и Arduino: три способа опроса

Механический энкодер и Arduino: три способа опроса

Как устроен простой инкрементальный энкодер-«крутилка», как подключить его к Arduino и чем различаются опрос в цикле, по таймеру и по прерыванию.

Что это за устройство

В любительской электронике энкодером обычно называют ручку управления, которую можно вращать, а иногда и нажимать, как кнопку. На 3D-принтерах прошлого поколения такая ручка часто была единственным органом управления.

Механический энкодер с ручкой

В широком смысле энкодеры — большое семейство датчиков, преобразующих угол поворота в сигналы для контроллера. Промышленные модели с оптическими, магнитными и индуктивными датчиками достигают точности в сотые и тысячные доли градуса. По способу выдачи данных их делят на абсолютные и инкрементальные. Абсолютный в любой момент сообщает точное положение независимо от предыстории, что необходимо станкам с ЧПУ, роботам и промышленным автоматам. Инкрементальный фиксирует только изменения, причём лишь тогда, когда за ним вовремя следят. Рассматриваемый энкодер относится ко второму типу.

Энкодер в разобранном виде

Устройство и характеристики

Конструкции у разных производителей различаются, но принцип один: внутри находятся две пары механических контактов, расположенные слегка несимметрично. Из-за этого при вращении они переключаются не одновременно, а с небольшим сдвигом по времени, и по тому, какой сигнал изменился первым, определяют направление.

Схема расположения контактов энкодера
Диапазон вращения360 градусов
Импульсов на оборотот 20, зависит от модели
Кнопкаесть, нажатие на вал
Напряжениедо 12 В
Скорость вращениядо 2 об/с

Подключение

С электрической точки зрения это две обычные кнопки, поэтому и схема «кнопочная»: средний контакт общий и соединяется с землёй, а каждый из двух сигнальных подтягивается к плюсу питания резистором 1 кОм. В примерах сигнальные выводы подключены к пинам 2 и 8 Arduino.

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

На осциллограмме видно, что каждый «щелчок» инвертирует сигнал на обоих выводах с небольшой задержкой, а опережающий вывод зависит от направления вращения. Алгоритм отсюда простой: дождаться изменения на первом выводе и сравнить его со вторым. Если уровни совпали — счётчик увеличивается, если нет — уменьшается.

Способ 1: опрос в основном цикле

Функция опроса вызывается из loop() и раз в 5 мс читает первый вывод, сравнивая значение с предыдущим. Пауза нужна для защиты от дребезга контактов; тот же эффект можно получить аппаратно, RC-цепочкой. Значение 5 мс подобрано так, чтобы дребезг гарантированно отсеивался, а полезный сигнал при умеренной скорости вращения не терялся.

Способ рабочий, но ненадёжный: функция должна вызываться без пропусков длиннее 5 мс. Любой другой код, даже вывод в последовательный порт, а тем более delay(), приводит к потере шагов.

Способ 2: прерывание по таймеру

Та же проверка переносится в обработчик прерывания таймера 1, настроенного на период 5 мс. Теперь опрос идёт строго по расписанию независимо от остальной программы, а актуальное положение всегда лежит в переменной-счётчике. Недостаток в том, что код выполняется постоянно, занимая один из таймеров и часть ресурсов контроллера, хотя ручку крутят редко.

У обоих способов есть общая слабость. При очень быстром вращении задержка между переключениями выводов оказывается короче интервала опроса — в измерениях из источника 1,6 мс против 5 мс, — и счёт начинает ошибаться. Варианты: не вращать ручку слишком быстро, сократить интервал (ценой большей нагрузки и риска пропустить дребезг) или отказаться от периодического опроса.

Способ 3: прерывание по изменению сигнала

Пин 2 выбран не случайно: к нему средствами Arduino привязывается внешнее прерывание. Строка attachInterrupt(INT0, pushPD, CHANGE) вызывает обработчик при каждом изменении уровня. Внутри сравниваются состояния двух выводов и меняется счётчик, а слишком частые повторные вызовы отбрасываются как дребезг.

Контроллер не делает лишней работы, сигналы не пропускаются, и показания остаются корректными практически при любой скорости вращения. Ограничение — таким образом в Arduino доступны только пины 2 и 3, то есть не более двух энкодеров.

Второму и третьему способу могут мешать библиотеки, временно отключающие прерывания, — например, для адресных светодиодов. Если контроллер постоянно занят анимацией ленты или выводом графики, корректно следить за энкодером он не сможет, и задачу приходится распределять между несколькими контроллерами.

Дополнительные вопросы

  • Несколько энкодеров: в первых двух способах достаточно добавить опрос новых пар пинов; при нехватке выводов применяют сдвиговые регистры типа 74HC165.
  • Ускорение: меньший интервал опроса допускает более быстрое вращение, но снижает точность; к тому же энкодер не рассчитан на высокие скорости и может быстро выйти из строя. Чтение портов напрямую вместо digitalRead() экономит несколько микросекунд.
  • Смена направления: поменять местами выводы или знаки в строке подсчёта.
  • Кнопка на валу обрабатывается как любая механическая кнопка.
  • Измерение угла оси возможно с точностью около 15 градусов и с калибровкой нуля при каждом запуске; обычно для этого берут абсолютные промышленные энкодеры.

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

← Все статьи