Использование поворотного энкодера с микроконтроллером AVR

StackOverflow https://stackoverflow.com/questions/34735

Вопрос

У меня возникли проблемы с корректной работой поворотного энкодера с микроконтроллерами AVR.Кодировщик представляет собой механический Кодировщик ALPS, и я использую Atmega168.

Разъяснение

Я пробовал использовать внешнее прерывание для прослушивания выводов, но, похоже, это слишком медленно.Когда вывод A становится высоким, запускается процедура прерывания, а затем проверяется, является ли вывод B высоким.Идея заключается в том, что если вывод B высокий в тот момент, когда вывод A стал высоким, то он вращается против часовой стрелки.Если вывод B низкий, то он вращается по часовой стрелке.Но, похоже, проверка вывода B занимает слишком много времени, поэтому AVR всегда считывается как high.

Я также пытался создать программу, которая просто блокирует до тех пор, пока не изменится Pin-код B или Pin-код A.Но может случиться так, что при вращении энкодера возникает слишком много шума, потому что это тоже не работает.Моей последней попыткой было установить таймер, который сохраняет последние 8 значений в буфере и проверяет, переходит ли он от низкого к высокому.Это тоже не сработало.

Я попробовал настроить кодировщик, и, похоже, он использует от 2 до 4 мс с момента изменения первого вывода до изменения другого вывода.

Это было полезно?

Решение

У меня есть веб-страница о поворотные энкодеры и способы их использования, которые вы могли бы счесть полезными.

К сожалению, без дополнительной информации я не могу устранить вашу конкретную проблему.

Какие контакты микроконтроллера подключены к кодеру и какой код вы в данный момент используете для декодирования импульсов?

Итак, вы имеете дело с несколькими различными проблемами, первая проблема заключается в том, что это механический энкодер, поэтому вам приходится иметь дело с шумом переключения (отскоком, дребезжанием).Тот Самый технический паспорт указывает, что может потребоваться до 3 мс, чтобы детали перестали подпрыгивать и создавать ложные выходные сигналы.

Вам нужно создать процедуру дебаунса.Самый простой из них - постоянно проверять, не поднимается ли A высоко.Если это произойдет, запустите таймер и проверьте его еще раз через 3 мс.Если он все еще высокий, то вы можете проверить B - если он не высокий, то вы игнорируете ложный импульс и продолжаете искать высокий.Когда вы проверяете B, вы смотрите на него, запускаете таймер на 3 мс, а затем снова смотрите на B.Если это было одно и то же оба раза, то вы можете использовать это значение - если оно изменится в течение 3 мс, то вам придется сделать это снова (прочитайте B, подождите 3 мс, затем прочитайте его еще раз и посмотрите, совпадает ли оно).

Atmega работает достаточно быстро, так что вам не нужно беспокоиться о том, что эти проверки будут проходить медленно, если только вы не используете низкую тактовую частоту.

Как только вы разберетесь с механическим шумом, вам захочется взглянуть на правильную процедуру кода грея - алгоритм, которому вы следуете, не будет работать, если вы также не уменьшите значение, если A велико, когда B становится низким.Обычно люди сохраняют последнее значение двух входных данных, а затем сравнивают его с новым значением двух входных данных и используют небольшую функцию для увеличения или уменьшения на основе этого.(Ознакомьтесь с таблицей в разделе "чтение в высоком разрешении" на веб-сайте, о котором я упоминал выше).Я объединяю два показания в четырехразрядное число и использую простой массив, чтобы определить, увеличиваю я счетчик или уменьшаю его, но есть решения, которые еще более продвинуты и оптимизированы для размера кода, скорости или простоты обслуживания кода.

Другие советы

Добавление аналогового фильтра нижних частот значительно улучшает качество сигнала.С фильтром нижних частот код AVR был действительно простым.

       _________
        |         |
        | Encoder |
        |_________|
          |  |  |
          |  |  |
     100n |  O  | 100n  
 GND O-||-+ GND +-||-O GND
          |     | 
          \     /
      3K3 /     \ 3K3
          \     /
          |     |    
VCC O-/\/-+     +-\/\-O VCC
     15K  |     |  15K
          |     |
          O     O
          A     B

Ах, чудеса ASCII-графики:p

Вот программа на AVR.Подключите A и B к входному порту B на avr:

#include <avr/io.h>

#define PIN_A (PINB&1)
#define PIN_B ((PINB>>1)&1)

int main(void){
    uint8_t st0 = 0;
    uint8_t st1 = 0;
    uint8_t dir = 0;
    uint8_t temp = 0;
    uint8_t counter = 0;
    DDRD = 0xFF;
    DDRB = 0;
    while(1){   
    if(dir == 0){
        if(PIN_A & (!PIN_B)){
            dir = 2;
        }else if(PIN_B & (!PIN_A)){
            dir = 4;
        }else{
            dir = 0;
        }
    }else if(dir == 2){
        if(PIN_A & (!PIN_B)){
            dir = 2;
        }else if((!PIN_A) & (!PIN_B)){
            counter--;
            dir = 0;
        }else{
            dir = 0;
        }
    }else if(dir == 4){
        if(PIN_B & (!PIN_A)){
            dir = 4;
        }else if((!PIN_A) & (!PIN_B)){
            counter++;
            dir = 0;
        }else{
            dir = 0;
        }
    }else if(PIN_B & PIN_A){
        dir = 0;
    }
        PORTD = ~counter;
    }
    return 0;
}

Этот код работает до тех пор, пока вы не повернете кодировщик очень быстро.Тогда он может пропустить шаг или два, но это не важно, так как человек, использующий кодировщик, не будет знать, на сколько шагов он его повернул.

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

С чем именно у вас возникли проблемы?Я предполагаю, что вы смогли подключить контакты энкодера к своему изображению в соответствии с техническими характеристиками, приведенными на странице Farnell, которую вы предоставили, так что проблема в чтении данных?Вы не получаете никаких данных от кодировщика?Вы не знаете, как интерпретировать данные, которые вы получаете обратно?

/* into 0 service rutine */
if(CHB)
{
  if(flagB)
   Count++;
  FlagB=0;
}
else
{
  if(FlagB)
   count--:
  FlagB=0:
}

/* into 1 service rutine */
FlagB=1;

/* make this give to you a windows time of 1/4 of T of the encoder resolution
   that is in angle term: 360/ (4*resolution)
 */
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top