Сопрягаем энкодер и микроконтроллер

14/09/2009 - 21:00
  Из этой статьи вы узнаете, что такое энкодер, зачем он нужен, и как его подружить с микроконтроллером. Если вы пользовались современной стиральной машиной, микроволновой печью или аудио системой то, скорее всего вы уже имели дело с энкодером, сами того не подозревая. Например, в большинстве современных домашних и автомобильных стерео систем энкодеры используются для регулировки громкости звука.
   Энкодер или датчик угла поворота – это электромеханическое устройство, предназначенное для преобразования углового положения вала или оси в электрические сигналы. Существует два основных типа энкодеров  - инкрементные и абсолютные.
   Инкрементный энкодер при вращении формирует импульсы, число которых пропорционально углу поворота. Подсчет числа этих  импульсов даст нам величину угла поворота вала энкодера относительно его начального положения. Этот тип энкодеров не формирует выходные импульсы, когда его вал находится в покое. Инкрементные энкодеры находят широкое применение в индустриальных средствах управления, бытовой и  музыкальной технике.
Абсолютный энкодер для каждой позиции своего вала выдает уникальный код.  Ему, в отличии от инкрементного энкодера, счетчик не нужен, угол вращения всегда известен. Абсолютный энкодер формирует сигнал и когда вал вращается, и когда он находится в покое. Абсолютный энкодер не теряет информацию о своем положении при потере питания и не требует возврата в начальную позицию. Этот тип энкодеров применяется в промышленно оборудовании - робототехнике, станках, конвейерных линиях.
  Я хотел бы рассказать о сопряжении инкрементного механического энкодера с микроконтроллером.  Для этого я приобрел инкрементный энкодер фирмы Bourns - PEC12-4220F-S0024. Вот расшифровка его названия согласно datasheet: PEC12 – модель, 4 – вертикальное положение выводов, 2 – 24 стопора, 20 – длина вала в мм, S – наличие кнопки, 0024 – 24 импульса за оборот.
внешний вид энкодера
внешний вид энкодера
   У него 5 выводов. 2 вывода на фотографии слева – выводы кнопки, 3 вывода на фотографии справа – выводы энкодера. Из них - 2 сигнальных и 1 общий. Он посередине. Схема подключения энкодера ничем не отличается от подключения обычных кнопок. Сигнальные выводы энкодера подключаем к любому порту ввода вывода микроконтроллера. Общий вывод энкодера сажаем на землю. Для защиты от дребезга контактов не лишним будет добавить еще пару керамических конденсаторов номиналом в несколько нанофарад. Выводы микроконтроллера в программе конфигурируем как входы и включаем подтягивающие резисторы. Можно использовать внешние.

схема подключения энкодера к микроконтроллеру

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

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

Сигналы сняты со старого энкодера, включенного без фильтрующих конденсаторов.

   Алгоритм обработки сигналов энкодера выглядит следующим образом. В обработчике прерывания таймера запускается функция опроса энкодера. Она считывает логические уровни, присутствующие на выводах микроконтроллера к которым подключен энкодер и записывает их во временную переменную. Внутри функции есть статическая переменная (переменная, которая сохраняет свое значение при выходе из функции) хранящая последовательность предыдущих состояний. С помощью битовой маски микроконтроллер выделяет из этой переменной последнее состояние и сравнивает его с текущим, чтобы определить произошли ли изменения. Если состояния равны – функция завершает работу, если отличны – значение статической переменной сдвигается влево на 2 разряда и на «освободившееся» место записывается текущее состояние. Таким образом, если вал энкодера вращается, функция будет постоянно сохранять некую повторяющуюся кодовую последовательность. При вращении вправо – это будет 11100001. При вращении влево – 11010010. По этим последовательностям микроконтроллер и будет понимать, в какую сторону происходит вращение.
   Исходник для работы с энкодером можно скачать здесь. Архив содержит два файла: encoder.h и encoder.c. В хедере задаются порт и номера выводов, к которым подключен энкодер, константы LEFT_SPIN и RIGHT_SPIN. Также там описаны прототипы функций. Сишный файл содержит реализацию функций.

void InitEncoder(void) – инициализирует выводы порта.

void PollEncoder(void)
– однократно опрашивает энкодер. Если зафиксировано вращение, записывает в буфер одну из констант, если нет, просто завершает работу.

unsigned char GetStateEncoder(void)
– возвращает содержимое буфера и очищает его.

   Опрос энкодера я обычно произвожу с частотой ~ 4 кГц. Если опрашивать медленней, микроконтроллер будет пропускать импульсы при быстрых поворотах ручки энкодера. Если энкодер используется для установки линейно меняющейся величины, например для установки времени в часах, то в качестве констант LEFT_SPIN и RIGHT_SPIN удобно использовать числа 255 и 1 соответственно. В обработчике сигналов энкодера эти числа просто складываются с устанавливаемой величиной. При сложении с 1 величина увеличивается на 1, при сложении с 255 уменьшается на 1. Конечно это актуально если эта величина однобайтная. Ну а в принципе константы LEFT_SPIN и RIGHT_SPIN можно выбирать произвольно, главное правильно написать обработчик. На этом все.

Исходник для работы с энкодером здесь.

Comments   

# akl 2009-11-07 12:09
akl
"Когда ручка энкодера стоит неподвижно – на входах микроконтроллер а присутствуют логические единицы."
Вы заблуждаетесь. На самом деле уровни сигналов на выходах не меняются при неподвижной ручке в одном из возможных состояний.
# Pashgan 2009-11-07 22:25
Согласен.
Но у этого энкодера самое устойчивое состояние - когда оба сигнальный вывода не соединены с общим. При остановке он всегда попадает именно в него. Проверено практикой.
Спасибо за замечание.
# Guest 2009-11-13 13:43
А пример можете показать ?
# Pashgan 2009-11-13 15:00
Пример готового проекта где используется энкодер?... Скоро выложу что-нибудь.
# Guest 2009-11-13 15:15
Да, пример добавления и убавления значения например, простой пример работы с энкодером, если можно.
# Guest 2009-12-23 12:00
Хорошо написано!
Статья принесла пользу.
# DVF 2010-01-03 08:13
Не всегда удобно "дергать" МК с частотой 4кГц (каждые 250мкс) :-|
# gringo 2010-01-08 00:16
никто не мешает завести сигналы с энкодера на внешнее прерывание..чер ез диоды или напрямую
# DVF 2010-01-11 20:03
Можно и на внешнее прерывание, но если такое прерывание не стоит на первом месте по важности, то не стоит тратить время на его обработку. Считывать информацию с энкодера и анализировать, в этом случае, лучше в main() программы, а результат анализа использовать, когда посчитает нужным программист, конечно с приемлемой частотой.
# Guest 2010-01-22 09:12
Насколько хорошо конденсаторы справляются с дребезгом контактов?
# Guest 2010-01-22 19:20
В некоторых случаях удобнее использовать экнодер мышки без выпайки его. Или заместь него впаять выводы от другого энкодера, а данные считывать по протоколу ps/2 непостредственн о из мыши.
Получается что для обработки энкодера есть уже готовый контроллер. К тому же можно считать сразу три энкодера и три кнопки всего по двум проводам :)
# Pashgan 2010-01-24 22:23
Quote:
Насколько хорошо конденсаторы справляются с дребезгом контактов?
Дребезг совсем исчезает
# Guest 2010-01-25 08:24
Использую внешнее прерывание. Одна ножка кодера на INT вторая на любой свободный. В прерывании проверяю пин если сброшен то вращение влево, если установлен то вправо. С дребезгом поначалу боролся, сейчас перестал, так как заметного влияния на управление не заметил. Важен факт манипуляции.
# Guest 2010-02-07 16:06
автору спасибо
в моем случае PollEncoder и GetStateEncoder стоит в main, эти функции там одни и с предельно возможной скоростью полят изменения с энкодера, поскольку скорость полинга в таком случае предельно высокая, то все работает без пропусков

а весь сервис по программе реализован в прерывании по одному таймеру
# Pashgan 2010-02-07 20:02
ого.. а зачем такие скорости?
# Guest 2010-04-01 19:51
спасибо!
минут 15 сидел,прозванив ал контакты,ломал бошку как работает
пока не глянул на вашу статью)
# Олег 2010-12-06 08:39
Энкодер hohner AWI90S-121AXX0- 50 кто нибудь знает расшифровку сколько импульсов на оборот и на какой его можно заменить
# Pashgan 2010-12-06 18:10
50 импульсов. Вот описание http://www.snabexpress.ru/Downloud/hohner/katalog-hohner2008.pdf 12 и 13 страницы
# Гость 2010-12-27 23:35
У меня есть энкодер, но не знаю маркировки :-| ,
как элементарно проверить число импульсов на оборот? :-)
# Pashgan 2011-01-01 16:51
Покрутить ручку энкодера и посчитать щелчки. Если на 90 градусов укладывается 6 щелчков, то логично предположить, что за полный оборот он делает 24. Это и есть количество импульсов на оборот.
# Гость 2011-01-11 20:56
Здравствуйте, очень нужна помощь. Хочу в автомобиле заменить кнопки климат-контроля на крутилки. Крутилки будут взяты с другого авто, соответственно там уже установлены энкодеры. Реально штатный энкодер применить в этом случае или может быть через микроконтроллер подружить энкодеры и климат контроль с кнопками.
# Pashgan 2011-01-17 21:15
Надо понять, что из себя представляет штатный энкодер другого авто. Если это обычный инкрементный энкодер, то подружить его с кнопками можно только с помощью микроконтроллер а.
# Роман 2011-01-21 16:30
А попадробнее можно? Получается что лучше средний контакт вообще не подключать на землю?
# Pashgan 2011-01-22 23:07
Если его не подключить, то ничего работать не будет.
# Роман 2011-01-21 16:31
А чем отличаются PEC12 от PEC16? Они взаимозаменяемы е?
# Pashgan 2011-01-22 23:13
По моему только конструкцией. Да взаимозаменяемы . Если не важно наличие/отсутст вие кнопки, количество импульсов на оборот (12 или 24), тип конструкции (для горизонтальной установки или вертикальной, длина вала),то можно вместо любого PEC12 взять любой PEC16 и наоборот. Если что-то важно, то подбирать.
# Роман ------ 2011-02-14 15:05
Я на магнитоле убрал кондеры и все работет отлично
# Brigadir 2011-02-17 15:57
Ставить кондеры для защиты от дребезга нет необходимости, т.к. сам дребезг будет фильтроваться программным образом, путем периодического опроса остояния энкодера. А если цеплять энкодер на вывод внешнего прерывания, то здесь, в прерывании можно подождать (потупить), пока дребезг не прекратится, а потом спокойно считывать состояние. Вообщем, кондеры тут ни к чему.
# Pashgan 2011-02-18 15:25
Это все хорошо звучит только в теории. Я ведь не случайно их туда поставил.
# Brigadir 2011-02-18 19:29
Quoting Pashgan:
Это все хорошо звучит только в теории. Я ведь не случайно их туда поставил.

Ну почему же только в теории, я и на практике проверял, на AT89S52. Думаю разницы особой нет, что МК не АВР. Никаких ложных срабатываний, все четко, без кондеров. Алгоритм по сути такой же, что и у вас, только реализация несколько отличается.
К тому же в промышленных агрегатах тоже, редко где их ставят, в подавляющем большинстве обходятся без них. Особенно китайцы любят экономить на такой мелочевке, и ничего, работает.
# Pashgan 2011-02-19 21:34
У меня был на макете старый инкрементальный экодер, он давал очень грязный сигнал - с хорошим таким дребезгом на фронтах. Не смотря на фильтующие свойства алгоритма, возникали ложные срабатывания. Проблема решилась добавлением конденсаторов.
А на промышленных агрегатах энкодеры посерьезнее PEC12.
# Lion_A 2011-07-31 19:00
Quoting akl:
akl
"Когда ручка энкодера стоит неподвижно – на входах микроконтроллера присутствуют логические единицы."
Вы заблуждаетесь. На самом деле уровни сигналов на выходах не меняются при неподвижной ручке в одном из возможных состояний.

Порывшись в хламе и достав все энкодеры из бытовой аппаратуры обнаружил что они работают так: щелчек=00,01,ще лчек=11,10,щелч ек=00. Тоесть при этом алгоритме нужно сделать два щелчка чтобы зделать одно переключение. Я сделал так:
Code:
void ENC_PollEncoder(void)
{

static unsigned char stateEnc; //хранит последовательность состояний энкодера
unsigned char tmp;
unsigned char currentState = 0;

currentState |= ENC_PIN_A<<1;
currentState |= ENC_PIN_B<<0;

//если равно предыдущему, то выходим
tmp=stateEnc;
if (currentState == (tmp & 0b00000011)) return;

//если не равно, то сдвигаем и сохраняем в озу
tmp = (tmp<<2)|currentState;
stateEnc = tmp;
tmp=tmp & 0b00001111;

if((tmp == 0b00000111) || (tmp == 0b00001000))bufEnc = LEFT_SPIN;
if((tmp == 0b00001011) || (tmp == 0b00000100))bufEnc = RIGHT_SPIN;

}


Пологаю что это более распространенны й тип энкодера, так как из пяти найденных пять именно такие.
# ibiza11 2011-08-30 11:43
а у меня почему то при вращении совпадают либо rising либо falling фронты сигналов... если в одну сторону - совпадают нарастающие фронты, если в другую - низходящие... почему так?
# Vit 2011-09-26 18:36
Quoting ibiza11:
а у меня почему то при вращении совпадают либо rising либо falling фронты сигналов... если в одну сторону - совпадают нарастающие фронты, если в другую - низходящие... почему так?

скорее всего, неверно определен общий вывод. попробуйте поискать его на двух оставшихся.
# Makswell 2011-10-16 09:05
Quoting Brigadir:
если цеплять энкодер на вывод внешнего прерывания, то здесь, в прерывании можно подождать (потупить), пока дребезг не прекратится, а потом спокойно считывать состояние.

в энкодерах восновном изменение уровня одного сигнала приходиться на средину второго сигнала, а к этому времени дребезг в контактах второго сигнала успевает устаканиться и "тупить" совсем не обязательно.
# mmv 2011-10-18 12:51
А как программно опрежелить обрыв одной из ножек энкодера?
# Nixie 2011-12-13 18:57
Quoting Lion_A:
Quoting akl:
akl
"Когда ручка энкодера стоит неподвижно – на входах микроконтроллера присутствуют логические единицы."
Вы заблуждаетесь. На самом деле уровни сигналов на выходах не меняются при неподвижной ручке в одном из возможных состояний.

Порывшись в хламе и достав все энкодеры из бытовой аппаратуры обнаружил что они работают так: щелчек=00,01,щелчек=11,10,щелчек=00. Тоесть при этом алгоритме нужно сделать два щелчка чтобы зделать одно переключение

И у меня тоже так : 2 щелчка--одно переключение. Пробовал 2 энкодера : из мышки и какой-то безымянный китаец.
# Uri 2012-03-02 14:49
Использовал ваш код для обработки энкодера только функцию включил в обработчик прерывания по таймеру 2. на энкодер не реагирует, посему?
Код:
Code:

ISR(TIMER2_COMP_vect) //ïðåðûâàíèå äëÿ îïðîñà ýíêîäåðà ïî ñîâïàäåíèþ
{
PORTD|=(1<<7);

unsigned char t; //New=PINB&0x07; //ïðèñâàåâàåì òåêóùåå çíà÷åíèå
static unsigned char se;
unsigned char cs=0;

//åñëè íå óñòàíîâëåíû áèòû íà ïîðòó ýíêîäåðà òî âûïîëíÿåì
if ((PINB&(1<<0))!=0)
{cs|=(1<<0);} //óñòàíàâëèâàåì íóëåâîé áèò ïåðåìåííîé cs
if ((PINB&(1<<1))!=0)
{cs|=(1<<1);} //óñòàíàâëèâàåì ïåðâûé áèò ïåðåìåííîé cs

//åñëè ñîñòîÿíèå ðàâíî ïðåäûäóùåìó òî âûõîäèì
t=se;
if (cs==(t&0b00000011)) return;

//åñëè íå ðàâíî òî ñäâèãàåì
t=(t<<2)|cs;
cs=t;

if (t==0b11100001) bufEnc=1;
if (t==0b11010010) bufEnc=2;
# UraGun 2012-03-30 15:11
Как то не рациональненько , ребята.
Я одну из ног направления (назовём "А") завожу на прерывание, в этом прерывании, если буфер направления поворота пуст- проверяю уровень на входе "А", дальше ветвление, если на входе "В" в это время ноль - то в буфер признак поворота вправо, если на "В" единица - то в буфер признако поворота влево. В этом же прерывании, если на входе "А" противоположный уровень, то при сравнении входа "В" - присваивать обратные признаки буферу направления. И всё... Естественно прерывание вызывается по любому изменению на "А", ну а уже в основном тексте проверяю буфер признака поворота, если он не пуст - произвожу действия в зависимости от направления и очищаю буфер... Занят таки образом один байт. Каждое прерывание производится всего три сравнения и одно присвоение. Быстро и безошибочно...
# UraGun 2012-03-30 15:16
Естественно, за каждый щелчок энкодера, прерывание вызывается два раза, так что, это позволяет также правильно обрабатывать ситуацию, когда пользователь повернул энкодер на пол щелчка и вернул назад. В такой ситуации, после первого прерывания появится признак поворота в одну сторону, а после второго - во вторую.
# UraGun 2012-03-30 15:23
НУ и для самых ленивых, привожу пример :) !
Code:
#pragma vector=INT5_vect// Прерывание по входу PINE_Bit5 при любом изменении
__interrupt void INT5_rout(void)
{
if (ENCODER1==0)
{
if (!PINE_Bit5)
{if (PINE_Bit6) ENCODER1=1; else ENCODER1=2;}
if (PINE_Bit5)
{if (PINE_Bit6) ENCODER1=2; else ENCODER1=1;}
}
return;
}

void main()
{

while (1)
{
...
if (ENCODER1==0) outtext(16,30,"0", 1); else
if (ENCODER1==1) outtext(16,30,"1", 2); else
if (ENCODER1==2) outtext(16,30,"2", 2);
if (ENCODER1!=0) ENCODER1=0;
...
}

Успехов, друзья ! :)
# Andy 2013-05-01 23:12
Товарищи, кто поможет согласовать энкодер с клавиатурой от PC? Задача - установить енкодер на срабатывание 2-х клавиш клавиатуры. Например, чтобы при повороте влево, срабатывало нажатие клавиши "Q", а при повороте вправо нажатие клавиши "E". Для простоты задачи, наверное, можно подпяться к кнопкам обычной клавиатуры. Как я понимаю, для этого нужен энкодер и некий блок логики, который будет замыкать 2 контакта в зависимости от напраления поворота энкодера? Цель - упростить управление программой, заменив многократное нажатие кнопки на вращение энкодера. За идеи и помощь в практической реализации возможно вознаграждение! :) можете писать напрямую на мейл: mowx@mail.ru
# Ersafap 2013-11-05 01:15
Товарищи, у меня непонятный глюк, использую енкодер без щелчков, все работает, но когда начинаю крутить назад, то первый шаг определяется как в ту же сторону в которую крутил перед этим, то есть совершается 1 шаг вперед, не смотря на то что я начал крутить назад. В чем дело?
# JoJo 2013-11-05 17:05
Как энкодер называется?
# Ersafap 2013-11-06 04:54
Продавцы не знают, все его покупают вот и все. Такой как на картинке в статье, без щелчков с непрерывным вращением, но 3 вывода, доп кнопок нет, на корпусе выдавлено ALPS. Кажется 48 импульсов на оборот.
# pshonia74 2014-05-10 12:27
Я подключаю энкодер без прерываний на Atmega к примеру PC0 PC1 - вход с Re
листинг простой
if(bit_is_clear(PINC,PC0)
{ delay_ms(5);
if(bit_is_clear (PINC,PC1) a++:
else a--;
delay_ms(70);
}
в розрыв провода с энкодера PC0 (только на PC0)ставим 2,2мкф 16v некоторые энкодеры(китайс кие) или грязные контакты или останавливается на замкнутом контакте - элекртолит решает проблему
остальная схема как на рис. выше
# Иван 2014-06-12 04:12
Здравствуйте кто нибуть измерял енкодером скорость.
# Pashgan 2014-06-14 09:46
Я не измерял. Ну а в чем там сложность? Измеряешь период импульсов, переводишь в скорость.
# Иван 2014-06-14 10:03
может есть какой то сирой пример?
# Pashgan 2014-06-14 19:31
Вот здесь описан принцип измерения частоты и есть примеры. http://chipenable.ru/index.php/programming-avr/item/88-chastotomer-na-mikrokontrollere.html
http://chipenable.ru/index.php/programming-avr/item/51-uchebnyy-kurs-16-razryadnyy-taymer-schetchik-t1-preryvanie-po-sobytiyu-zahvat-prostoy-chastotomer-na-avr.html
# QXin 2015-01-10 18:23
Спасибо! Очень устойчиво работает, наконец разобрался с энкодером.
# DenisSop 2016-09-28 05:55
Здравствуйте! Насал заниматься робототехникой и возникла задача определять направление движения двухколесного робота, отслеживать его повороты. Для этого достал мышь с шариком. Отрезал ту часть платы, где сами энкодеры с роликами, контактирующими с шариком. Фототранзистор и светодиод образуют оптопару, перегародка с дырками между ними образует сам энкодер. Фототранзистор сдвоенный с общим коллектором. Подключаю как: на коллектор 5V, эмитеры подтягиваю на ноль с помощью резистора нв 27 кОм. Также с эмитера фигачу проводок на МК. Так вот: на маленьких оборотах (1000 импульсов в сек) более менее точно, на высоких - счетчик не инкрементируетс я. Подсоединял осциллограф к эммитеру - чем выше частота вращения, тем ниже амплитуда сигнала, и в конце концов амплитуда опускается ниже критической точки, воспринмаемая МК, как логическая 1.
Если увеличить сопротивление - не будет логического нуля.
Если уменьшить - тоже фигня.
Что сделать, подскажите пожалуйста!!!
# DenisSop 2016-09-28 05:58
Quoting DenisSop:
Насал

Начал*
# Alex_M 2016-10-19 05:07
ну все правильно - используй высокочастотный коаксиальный кабель для соединения.

У вас недостаточно прав для комментирования.