Сопрягаем энкодер и микроконтроллер
14/09/2009 - 21:00
Pavel Bobkov
Из этой статьи вы узнаете, что такое энкодер, зачем он нужен, и как его подружить с микроконтроллером. Если вы пользовались современной стиральной машиной, микроволновой печью или аудио системой то, скорее всего вы уже имели дело с энкодером, сами того не подозревая. Например, в большинстве современных домашних и автомобильных стерео систем энкодеры используются для регулировки громкости звука.
Энкодер или датчик угла поворота – это электромеханическое устройство, предназначенное для преобразования углового положения вала или оси в электрические сигналы. Существует два основных типа энкодеров - инкрементные и абсолютные.
Инкрементный энкодер при вращении формирует импульсы, число которых пропорционально углу поворота. Подсчет числа этих импульсов даст нам величину угла поворота вала энкодера относительно его начального положения. Этот тип энкодеров не формирует выходные импульсы, когда его вал находится в покое. Инкрементные энкодеры находят широкое применение в индустриальных средствах управления, бытовой и музыкальной технике.
Абсолютный энкодер для каждой позиции своего вала выдает уникальный код. Ему, в отличии от инкрементного энкодера, счетчик не нужен, угол вращения всегда известен. Абсолютный энкодер формирует сигнал и когда вал вращается, и когда он находится в покое. Абсолютный энкодер не теряет информацию о своем положении при потере питания и не требует возврата в начальную позицию. Этот тип энкодеров применяется в промышленно оборудовании - робототехнике, станках, конвейерных линиях.
Я хотел бы рассказать о сопряжении инкрементного механического энкодера с микроконтроллером. Для этого я приобрел инкрементный энкодер фирмы Bourns - PEC12-4220F-S0024. Вот расшифровка его названия согласно datasheet: PEC12 – модель, 4 – вертикальное положение выводов, 2 – 24 стопора, 20 – длина вала в мм, S – наличие кнопки, 0024 – 24 импульса за оборот.
Энкодер или датчик угла поворота – это электромеханическое устройство, предназначенное для преобразования углового положения вала или оси в электрические сигналы. Существует два основных типа энкодеров - инкрементные и абсолютные.
Инкрементный энкодер при вращении формирует импульсы, число которых пропорционально углу поворота. Подсчет числа этих импульсов даст нам величину угла поворота вала энкодера относительно его начального положения. Этот тип энкодеров не формирует выходные импульсы, когда его вал находится в покое. Инкрементные энкодеры находят широкое применение в индустриальных средствах управления, бытовой и музыкальной технике.
Абсолютный энкодер для каждой позиции своего вала выдает уникальный код. Ему, в отличии от инкрементного энкодера, счетчик не нужен, угол вращения всегда известен. Абсолютный энкодер формирует сигнал и когда вал вращается, и когда он находится в покое. Абсолютный энкодер не теряет информацию о своем положении при потере питания и не требует возврата в начальную позицию. Этот тип энкодеров применяется в промышленно оборудовании - робототехнике, станках, конвейерных линиях.
Я хотел бы рассказать о сопряжении инкрементного механического энкодера с микроконтроллером. Для этого я приобрел инкрементный энкодер фирмы 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
"Когда ручка энкодера стоит неподвижно – на входах микроконтроллер а присутствуют логические единицы."
Вы заблуждаетесь. На самом деле уровни сигналов на выходах не меняются при неподвижной ручке в одном из возможных состояний.
Но у этого энкодера самое устойчивое состояние - когда оба сигнальный вывода не соединены с общим. При остановке он всегда попадает именно в него. Проверено практикой.
Спасибо за замечание.
Статья принесла пользу.
Получается что для обработки энкодера есть уже готовый контроллер. К тому же можно считать сразу три энкодера и три кнопки всего по двум проводам :)
в моем случае PollEncoder и GetStateEncoder стоит в main, эти функции там одни и с предельно возможной скоростью полят изменения с энкодера, поскольку скорость полинга в таком случае предельно высокая, то все работает без пропусков
а весь сервис по программе реализован в прерывании по одному таймеру
минут 15 сидел,прозванив ал контакты,ломал бошку как работает
пока не глянул на вашу статью)
как элементарно проверить число импульсов на оборот? :-)
Ну почему же только в теории, я и на практике проверял, на AT89S52. Думаю разницы особой нет, что МК не АВР. Никаких ложных срабатываний, все четко, без кондеров. Алгоритм по сути такой же, что и у вас, только реализация несколько отличается.
К тому же в промышленных агрегатах тоже, редко где их ставят, в подавляющем большинстве обходятся без них. Особенно китайцы любят экономить на такой мелочевке, и ничего, работает.
А на промышленных агрегатах энкодеры посерьезнее PEC12.
Порывшись в хламе и достав все энкодеры из бытовой аппаратуры обнаружил что они работают так: щелчек=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;
}
Пологаю что это более распространенны й тип энкодера, так как из пяти найденных пять именно такие.
скорее всего, неверно определен общий вывод. попробуйте поискать его на двух оставшихся.
в энкодерах восновном изменение уровня одного сигнала приходиться на средину второго сигнала, а к этому времени дребезг в контактах второго сигнала успевает устаканиться и "тупить" совсем не обязательно.
И у меня тоже так : 2 щелчка--одно переключение. Пробовал 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;
Я одну из ног направления (назовём "А") завожу на прерывание, в этом прерывании, если буфер направления поворота пуст- проверяю уровень на входе "А", дальше ветвление, если на входе "В" в это время ноль - то в буфер признак поворота вправо, если на "В" единица - то в буфер признако поворота влево. В этом же прерывании, если на входе "А" противоположный уровень, то при сравнении входа "В" - присваивать обратные признаки буферу направления. И всё... Естественно прерывание вызывается по любому изменению на "А", ну а уже в основном тексте проверяю буфер признака поворота, если он не пуст - произвожу действия в зависимости от направления и очищаю буфер... Занят таки образом один байт. Каждое прерывание производится всего три сравнения и одно присвоение. Быстро и безошибочно...
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;
...
}
Успехов, друзья ! :)
листинг простой
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 некоторые энкодеры(китайс кие) или грязные контакты или останавливается на замкнутом контакте - элекртолит решает проблему
остальная схема как на рис. выше
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
Если увеличить сопротивление - не будет логического нуля.
Если уменьшить - тоже фигня.
Что сделать, подскажите пожалуйста!!!
Начал*
RSS feed for comments to this post