Устранение неполадок при программировании AVR для интерпретации ввода от модуля энкодера Arduino - PullRequest
2 голосов
/ 27 июня 2019

Я пытался запрограммировать свой ATtiny817-XPRO для интерпретации входных данных с поворотного энкодера (модуля Arduino), однако у меня возникли некоторые проблемы, и я не могу понять, в чем проблема. По сути, я пытаюсь запрограммировать цифровой кодовый замок, который мигает красным светодиодом каждый раз, когда вращающийся энкодер поворачивается на одну «галочку» (в любом направлении), и мигает зеленым светодиодом, когда обнаружена правильная «комбинация». , Это немного сложнее, поэтому, когда я столкнулся с проблемами при тестировании своего кода, я решил написать простой метод, который помог бы мне устранить или устранить проблему. Я включил это ниже:

void testRotaryInput(){
    if(!(PORTC.IN & 0b00000001)){   // if rotary encoder is turned clockwise
        PORTB.OUT = 0b00000010;     // turn on green LED
    }
    else if(!(PORTC.IN & 0b00000010)){  // if rotary encoder is turned CCW
        PORTB.OUT = 0b00000001;         // turn on blue LED
    }
    else{                           // if rotary encoder remains stationary
        PORTB.OUT = 0b00000100;     // turn on red LED
    }
    RTC.CNT = 0;
    while(RTC.CNT<16384){}          // wait 500ms
    PORTB.OUT = 0x00;               // turn LED off
    while(RTC.CNT<32768){}          // wait another 500ms
}

int main(void)
{
    PORTB.DIR = 0xFF;               // PORT B = output
    PORTC.DIR = 0x00;               // PORT C = input
    RTC.CTRLA = RTC_RTCEN_bm;       // Enable RTC
    PORTB.OUT = 0x00;               // Ensure all LEDs start turned off
                                    // ^(not necessary but I do it just in case)^

    //testLED(); <-- previous test I used to make sure each LED works upon start-up

    while(1)
    {
        testRotaryInput();
    }
}

Идея заключается в том, что какая бы выходная линия не поступала в AVR первой, она должна указывать, в каком направлении вращался энкодер, поскольку это диктует сдвиг фазы между двумя сигналами. В зависимости от направления вращения (или его отсутствия) красный / зеленый / синий светодиод будет мигать один раз в течение 500 мс, а затем программа будет ждать еще 500 мс, прежде чем снова прослушивать выходной сигнал поворотного энкодера. Однако, когда я запускаю этот код, светодиод будет постоянно мигать красным некоторое время или зеленым некоторое время, в конечном итоге переключаясь с одного цвета на другой с периодическим (одиночным) синим миганием. Это кажется абсолютно случайным каждый раз, и, кажется, полностью игнорирует любое вращение, которое я применяю к поворотному энкодеру.

Что я сделал для устранения неполадок:

  • Подключил оба выхода поворотного энкодера к осциллографу, чтобы увидеть, есть ли какой-либо выход (все выглядело так, как должно)

  • Использовал внешний источник питания для питания поворотного энкодера, поскольку я считывал только 1,6 В с вывода VCC 5,0 В на моем ATtiny817-XPRO, когда он был подключен к этому (я подозреваю, что это произошло потому, что светодиоды и поворотный энкодер, вероятно, потребляет слишком много тока)

  • Измерено напряжение от указанного источника питания, чтобы убедиться, что вращающийся датчик получает 5,0 В (я измерял прибл. 4,97 В)

  • Проверяется, чтобы убедиться, что схема исправна и работает как надо

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

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

Спасибо!

Ответы [ 3 ]

3 голосов
/ 27 июня 2019

Кодеры могут вести себя различными странными способами. Вы будете иметь сигналы отказов, как с любым переключателем. У вас будут случаи, когда несколько входов могут быть активны одновременно во время хода. И т.д. Поэтому вам необходимо периодически их пробовать.

Создайте таймер, который опрашивает кодировщик каждые 5 мс или около того. Всегда сохраняйте предыдущее прочтение. Не принимайте какие-либо изменения в качестве допустимых, пока они не будут стабильными в течение двух последовательных чтений. Это самая простая форма цифрового фильтра.

1 голос
/ 28 июня 2019

Как уже отмечали другие, механические энкодеры подвержены отскоку.Вы должны справиться с этим.

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

Вы ожидаете падающего (или нарастающего) фронта выхода «синхроимпульса», и, когда он обнаружен, сразу считываете состояние другого выхода, чтобы определить направление.

После этого включите некоторое «мертвое время», в течение которого вы игнорируете любые другие границы сигнала «часов», возникающие из-за отскока контактов.

Алгоритм:

0) состояние чтениясигнала «A» и сохранения («предыдущее состояние»)

1) считывают состояние «A» и сравнивают с «предыдущим состоянием»

2) если тактовый сигнал не изменился, например, с высокого на низкий (если вы хотите использовать падающий фронт), переходите к 1).

3) считывание состояния сигнала направления (B), сохраните текущее состояние часов в «предыдущее состояние часов»

4) теперь вы знаете, чтопроизошел «тик» (изменение сигнала часов) и направление, обработайте его

5) отключите чтение сигнала «часы» (A) в течение некоторого времени, например, 10 мс, для дебатирования;после истечения периода ожидания перейдите к 1)

. Этот подход не является критичным по времени.До тех пор, пока вы убедитесь, что опрашиваете «часы» как минимум вдвое быстрее, чем кратчайшее время между изменением сигнала A и соответствующим изменением сигнала B (минус время отскока A), которое вы ожидаете увидеть (зависит от максимального ожидаемогоскорость вращения), он будет работать абсолютно надежно.

Обнаружение фронта сигнала 'clock' также может быть выполнено с помощью прерывания смены штырька, которое вы просто отключаете на время простоя после возникновения прерывания.Однако обработка отскакивающих контактов через прерывание смены штырька, как правило, не рекомендуется, поскольку отскакивание (т. Е. (Очень) быстрое переключение штыря может быть импульсами длительностью наносекунд ) может сбивать аппаратное обеспечение.

1 голос
/ 27 июня 2019

Какой вход закорочен, не показывает, в каком направлении был повернут кодировщик. Но порядок, в котором они были закорочены, делает.

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

enter image description here

Так что, вообще говоря, каждый "НАЖМИТЕ!" движение вы можете рассматривать как 4 этапа:

  • 0. Оба входа разблокированы (высокий уровень) - положение по умолчанию
  • 1. Вход A замкнут на землю (низкий уровень), вход B отключен (высокий уровень)
  • 2. Оба входа закорочены (низкий уровень)
  • 3. Вход A отключен (высокий уровень), B замкнут (низкий уровень).

Вращение в одном направлении - это проход через фазы 0-1-2-3-0. Другое направление 0-3-2-1-0. Таким образом, независимо от направления вращения энкодера, оба входа будут замкнуты на землю в определенный момент.

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

Поскольку эти фазы меняются очень быстро, вам нужно очень быстро объединять входные контакты, может быть 1000 раз в секунду, для обработки быстрых вращений.

Код для управления вращением может быть следующим:

signed int encoder_phase = 0;

void pull_encoder() {
    int phase = ((PORTC.IN & (1 << INPUT_A_PINNO)) ? 0 : 1)
                ^ ((PORTC.IN & (1 << INPUT_B_PINNO)) ? 0 : 0b11);
    // the value of phase variable is 0 1 2 or 3, as described above
    int phase_shifted = (phase - encoder_phase) & 3;
    if (phase_shifted == 2) { // jumped instantly over two phases - error
        encoder_phase = 0;
    } else if (phase_shifted == 1) { // rotating forward
        encoder_phase++;
        if (encoder_phase >= 4) { // Full cycle
            encoder_phase = 0;
            handle_clockwise_rotation();
        }
    } else if (phase_shifted == 3) { // rotating backward; 
        encoder_phase--;
        if (encoder_phase <= -4) { // Full cycle backward
            encoder_phase = 0;
            handle_counterclockwise_rotation();
        }
    }
    if (phase == 0) {
        encoder_phase = 0; // reset 
    }
}
...