Подключение инкрементального энкодера к микроконтроллеру.
Инкрементальный энкодер внешне похож на потенциометр, но в отличие от потенциометра у него нет крайних положений, он может вращаться в обоих направлениях неограниченное количество оборотов. Также надо отметить, что инкрементальный энкодер вращается не так плавно как потенциометр, а шагами. Его можно увидеть на автомобильной магнитоле, осциллографе, музыкальном центре, стиральной машине и прочей технике, где регулировка какого-то параметра осуществляется в больших пределах. Конечно, параметры можно изменять и с помощью кнопок, например, для того чтобы сделать музыку на 20 значений громче, при управлении кнопкой, надо нажать её 20 раз, а при управлении энкодером, провернуть его на определённый угол, в зависимости от алгоритма обработки.
Инкрементальный энкодер представляет собой два контакта, порядок замыкания которых зависит от направления вращения.
По сути инкрементальный энкодер преобразует вращение вала в электрические импульсы, содержащие информацию о направлении вращения.
Давайте соберём тестовую схему изображенную на картинке выше и подключимся к выводу A и B осциллографом, резисторы подтяжки - 4.7К.
Покрутим энкодер по часовой стрелке.
Теперь против часовой.
На осциллограммах видно, что в зависимости от направления вращения, изменяется порядок замыкания контактов. Но фронта не всегда получаются такие красивые.
Так как контакты механические, они подвержены дребезгу, то есть при замыкании за счёт упругости материалов, возникают многократные неконтролируемые замыкания и размыкания, которые можно увидеть на осциллограмме выше.
Бороться с дребезгом можно двумя способами, первый состоит в добавлении конденсаторов и резисторов, как показано на картинке ниже.
Так как дребезг явление кратковременное, он легко гасится конденсатором.
На осциллограмме видно, что после установки конденсаторов, фронты стали менее крутыми, а дребезг исчез.
Второй способ — программный и тут всё зависит от реализации опроса выводов энкодера. Если состояние энкодера отслеживается с помощью внешних прерываний, то после срабатывания прерывания необходимо сделать задержку 20 - 30 миллисекунд, во время которой МК не будет реагировать на изменение состояния вывода, то есть не будет чувствовать дребезг. Если опрос выводов энкодера реализован на таймере, то интервал между опросами должно быть больше длительности дребезга, те же 20 -30 миллисекунд.
Давайте рассмотрим методы обработки данных, приходящих с энкодера.
Первый метод, заключается в том, что одну из ножек энкодера мы подключаем к выходу внешних прерываний и настраиваем её на прерывание по спадающему фронту. В прерывании мы проверяем состояние другой ножки и если на ней ноль, то вращение происходит в одну сторону, иначе в другую. Ниже приведён код, реализующий этот метод для AVR.
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(INT2_vect)
{
if (PINB & 0X02)
{
PORTB |= (1<<0);
}
else
{
PORTB &= ~(1<<0);
}
//антидребезг
_delay_ms(20);
//сбрасываем флаг прерывания вызванный дребезгом
GIFR = (1<<INTF2);
}
int main(void)
{
//настраиваем вывод внешнего прерывания на вход
DDRB &= ~(1<<2);
//включаем подтяжку
PORTB |= (1<<2);
//настраиваем вход для подключения второго вывода энкодера
DDRB &= ~(1<<1);
//настраиваем на выход подключения светодиода
DDRB |= (1<<0);
//определяем фронт прерывания - спадающий
MCUCR &= ~(1<<ISC2);
//разрешаем внешнее прерывание int2
GICR |= (1<<INT2);
sei();
while(1)
{
}
}
При повороте энкодера в одну сторону светодиод загорается, при повороте в другую - гаснет.
Второй метод, заключается в сравнении текущего состояния и предыдущего. Давайте выразим логические уровни последовательности импульсов в виде нулей и единичек.
Тогда мы получим конечное число состояний энкодера. Первая цифра — логический уровень первого вывода энкодера, вторая — логический уровень второго вывода.
00 = 0
10 = 2
11 = 3
01 = 1
Предположим последнее состояние в котором находился энкодер равно трем, если следующее состояние будет равно единице, то он вращается в одну сторону, если двум, то в другую. Получается, что можно фиксировать переход из одного состояние в другое и определять направление вращения, но наиболее простой является реализация при переходе от 11 к 01 и 10. Ниже приведён код реализующий описанный алгоритм для AVR,
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
uint8_t last_state = 0;
ISR(TIMER0_COMP_vect)
{
//оба вывода энкодера подключены к 2 и 3 выводу порта B
//считываем их состояние
uint8_t current_state = (PINB & 0x06)>>1;
//учитываем переход только если пред.состояние 11
//и если оно не равно новому
if ((last_state == 3) && (last_state != current_state))
{
//если новое сост 01 - включаем светодиод
if(current_state == 1)
{
PORTB |= 0x01;
}
//если новое сост 10 - гасим светодиод
if(current_state == 2)
{
PORTB &= ~0x01;
}
}
//при выходе из прерывания текущее состояние становится прошлым
last_state = current_state;
}
int main(void)
{
//два входа для подключения энкодера
DDRB &= ~0x06;
//подтягиваем входы к питанию
PORTB |= 0x06;
//выход для подключения светодиода
DDRB |= 0x01;
//настраиваем таймер по в режим сброс по совпадению
TCCR0=(1<<WGM01);
//разрешаем прерывания счетчика по совпадению
TIMSK |= (1<<OCIE0);
//устанавливаем число для сравнения, чтобы частота опроса была 20ms
OCR0 = 150;
//устанавливаем предделитель 1024
TCCR0|=(1<<CS02 | 1<<CS00);
//разрешаем прерывания глобально
sei();
while(1)
{
}
}
На этом всё.
Энкодер покупал тут.
Похожие статьи