Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Опрос валкодера
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Anjey_N
Все привет!
Вопрос такой:
В системе стоит механический валкодер. Опрашиваю его я вот так

signed char ReadEncoder(void)
{
register signed char temp = 0;
encoder = (~PIN_Coder & 0x03);//i?iaa?yai PD0,PD1
if(status != encoder)
{
switch(encoder)
{
case 0:
if(status == 1) temp = 1;
else if(status == 2) temp = -1;
break;
case 1:
if(status == 3) temp = 1;
else if(status == 0) temp = -1;
break;
case 2:
if(status == 0) temp = 1;
else if(status == 3) temp = -1;
break;
case 3:
if(status == 2)temp = 1;
else if(status == 1) temp = -1;
break;
}
status = encoder;
}
return temp;
}
Єту программку скачал с нета. При медленном вращении валкодера показания на индикаторе меняются стабильно, а при быстром вращении - не изменяются.
Похоже на дребезг контактов. Как можно от этого избавиться?
psw
похоже, что я писал этот кусок smile.gif как часто опрашиваешь валкодер?
Anjey_N
Цитата(psw @ Nov 14 2007, 17:24) *
похоже, что я писал этот кусок smile.gif как часто опрашиваешь валкодер?


1 раз в 1 мсек
Anjey_N
Валкодеры, их два, подключены по такой схеме

Длительность строба 2 мс

Вместе с валкодерами подключены и кнопки. Валкодеры опрашиваются, когда на их средний вывод приходит "0".
Опрос валкодера, если незадействованы кнопки 1раз в 12 мс
Нажмите для просмотра прикрепленного файла
Alex B._
Обязательно нужно через фильтр пропускать отсчеты. Ниже старый, но рабочий код. Сканируется раз в 200 мкс

Код
typedef struct __ENC_CB
{
    U08 phs_sample_period;

    U16 A_window;
    U16 B_window;

    U16 A_sum;
    U16 B_sum;

    U08 A_mask;
    U08 B_mask;

    U08 Current;
    U08 Previous;

    U08 State;

} ENC_CB;

ENC_CB ENC;

/* =================== */

void adsf (void)
{
    port = ENC_PORT;

    if (++ENC.phs_sample_period > (ENC_PHS_SAMPLE_PERIOD_VAL - 1))
    {
        ENC.phs_sample_period = 0;

        if (port & ENC_A_PIN)
        {
            ENC.A_sum++;
            ENC.A_window |= ENC.A_mask;
        }
        else
        {
            if (ENC.A_sum > 0)
                ENC.A_sum--;
            ENC.A_window &= ~ENC.A_mask;
        }

        ENC.A_mask <<= 1;
        if (ENC.A_mask == 0)
            ENC.A_mask = 1;

        if ((ENC.A_window & ENC.A_mask) &&
            (ENC.A_sum > 0)
           )
            ENC.A_sum--;

        if (port & ENC_B_PIN)
        {
            ENC.B_sum++;
            ENC.B_window |= ENC.B_mask;
        }
        else
        {
            if (ENC.B_sum > 0)
                ENC.B_sum--;
            ENC.B_window &= ~ENC.B_mask;
        }

        ENC.B_mask <<= 1;
        if (ENC.B_mask == 0)
            ENC.B_mask = 1;

        if ((ENC.B_window & ENC.B_mask) &&
            (ENC.B_sum > 0)
           )
            ENC.B_sum--;

        ENC.Current = ENC.Previous;

        if      (ENC.A_sum > 5)  ENC.Current |=  0x01;
        else if (ENC.A_sum < 2)  ENC.Current &= ~0x01;

        if      (ENC.B_sum > 5)  ENC.Current |=  0x02;
        else if (ENC.B_sum < 2)  ENC.Current &= ~0x02;

        if (!ENC.Current)
        {
            if (ENC.Previous == 0x01)
                ENC.State |= ENC_EVENT_UP;
            if (ENC.Previous == 0x02)
                ENC.State |= ENC_EVENT_DW;
        }

        ENC.Previous = ENC.Current;
    }
}
alexander55
Цитата(Anjey_N @ Nov 15 2007, 11:27) *
Опрос валкодера, если незадействованы кнопки 1раз в 12 мс
Нажмите для просмотра прикрепленного файла

Опрашивать надо чаще. Чем выше максимальная скорость, тем чаще.
Частота опроса д.б. более, чем в 2 раза больше скорости изменения показаний.
Теорема Котельникова- Шенона, однако. 07.gif
Anjey_N
Цитата(alexander55 @ Nov 15 2007, 12:44) *
Опрашивать надо чаще. Чем выше максимальная скорость, тем чаще.
Частота опроса д.б. более, чем в 2 раза больше скорости изменения показаний.
Теорема Котельникова- Шенона, однако. 07.gif



Боюсь, в моём случае это не сработает! Валкодер привязан к сканированию индикатора.
Схему нужно изменить, средний вывод посадить на "землю", тогда можно и скорость увеличить!

Цитата(Alex B._ @ Nov 15 2007, 12:40) *
Обязательно нужно через фильтр пропускать отсчеты. Ниже старый, но рабочий код. Сканируется раз в 200 мкс

Код
typedef struct __ENC_CB
{
    U08 phs_sample_period;

    U16 A_window;
    U16 B_window;

    U16 A_sum;
    U16 B_sum;

    U08 A_mask;
    U08 B_mask;

    U08 Current;
    U08 Previous;

    U08 State;

} ENC_CB;

ENC_CB ENC;

/* =================== */

void adsf (void)
{
    port = ENC_PORT;

    if (++ENC.phs_sample_period > (ENC_PHS_SAMPLE_PERIOD_VAL - 1))
    {
        ENC.phs_sample_period = 0;

        if (port & ENC_A_PIN)
        {
            ENC.A_sum++;
            ENC.A_window |= ENC.A_mask;
        }
        else
        {
            if (ENC.A_sum > 0)
                ENC.A_sum--;
            ENC.A_window &= ~ENC.A_mask;
        }

        ENC.A_mask <<= 1;
        if (ENC.A_mask == 0)
            ENC.A_mask = 1;

        if ((ENC.A_window & ENC.A_mask) &&
            (ENC.A_sum > 0)
           )
            ENC.A_sum--;

        if (port & ENC_B_PIN)
        {
            ENC.B_sum++;
            ENC.B_window |= ENC.B_mask;
        }
        else
        {
            if (ENC.B_sum > 0)
                ENC.B_sum--;
            ENC.B_window &= ~ENC.B_mask;
        }

        ENC.B_mask <<= 1;
        if (ENC.B_mask == 0)
            ENC.B_mask = 1;

        if ((ENC.B_window & ENC.B_mask) &&
            (ENC.B_sum > 0)
           )
            ENC.B_sum--;

        ENC.Current = ENC.Previous;

        if      (ENC.A_sum > 5)  ENC.Current |=  0x01;
        else if (ENC.A_sum < 2)  ENC.Current &= ~0x01;

        if      (ENC.B_sum > 5)  ENC.Current |=  0x02;
        else if (ENC.B_sum < 2)  ENC.Current &= ~0x02;

        if (!ENC.Current)
        {
            if (ENC.Previous == 0x01)
                ENC.State |= ENC_EVENT_UP;
            if (ENC.Previous == 0x02)
                ENC.State |= ENC_EVENT_DW;
        }

        ENC.Previous = ENC.Current;
    }
}



Спасибо за код, изучаю. Вы какой компилятор используете?
Kirill Frolov
Цитата(Anjey_N @ Nov 14 2007, 12:49) *
Вопрос такой:
В системе стоит механический валкодер. Опрашиваю его я вот так


Суть вопроса вот какая. Частота опроса входного сигнала должна быть минимум вдвое больше его частоты с которой он изменяется. Это очевидный факт. Но реализовать это в случае многократного пересечения валкодером края одной метки, когда он колеблется возле этого самого края сложно... И не нужно!. Тем более, если валкодер обрабатывается аппаратным прерыванием (к вопросу о том как прибору сделать "DoS" путём перепиливания тупой ножёвкой жгута проводов...)

Решение, вкратце таково: алгоритм модифицируется таким образом, что при прохождении края какой-либо метки в одном направлении её прохождение в обратном направлении попросту не фиксируется (запрещается прерывание, например). А фиксируется только прохождение следующего края метки в том же направлении (+1 к позиции) или прохождение не только что пройденного, а предшествующего ему края метки в обратном направлении (-2 к позиции). Может смутно объяснил. Советую просто расписать код Грея в круге и тогда легко будет понять как это работает, и что для реализации алгоритма достаточно запретить (допустим, валкодер имеет два выхода) прерывание от того выхода, который вызвал вот прямо сейчас прерывание -- т.е. поочерёдно разрешается прерывание от первого или второго выхода.

Алгоритм полностью решает проблему "дребезга", когда валкодер колеблется на краю метки (быстрая смена +1, -1, +1, -1...) -- не имея возможности его, валкодер, опрашивать с достаточно большой частотой можно потерять в точности, или же, используя прерывания легко заблокировать весь микроконтроллер исключительно в процессе обработки прерываний от валкодера. С описанным алгоритмом подобных проблем нет.
Anjey_N
Спасибо, думаю a14.gif
Anjey_N
Мне тут посоветовали применить компъютерную мышь! Что вы думаете по этому поводу?
676038
Мой опыт смотри здесь:
http://electronix.ru/forum/index.php?s=&am...st&p=218642
Anjey_N
Ходил по ссылке, читал. Так вы закончили этот проект?
Если это возможно, хотелось бы посмотреть на код, желательно на Си!
676038
По ссылке выше во вложении есть весь проект на С (компилируется и работает, как это было описано там) для IAR.
Дальше эта работа не пошла по причинам, описанным там же.

Себе жа нашел совсем другой вариант решения опроса двух энкодеров и нескольких кнопок:
- Взял Atmega48-88-168, там есть pin change interrupt.
- На две линии порта повесил один энкодер, еще на две линии - другой энкодер, и на оставшиеся линии - кнопки. Затем опрос порта в обработчике прерывания.

Если это вариант интересен - могу описать подробнее.
Anjey_N
Цитата(676038 @ Nov 17 2007, 22:29) *
По ссылке выше во вложении есть весь проект на С (компилируется и работает, как это было описано там) для IAR.
Дальше эта работа не пошла по причинам, описанным там же.

Себе жа нашел совсем другой вариант решения опроса двух энкодеров и нескольких кнопок:
- Взял Atmega48-88-168, там есть pin change interrupt.
- На две линии порта повесил один энкодер, еще на две линии - другой энкодер, и на оставшиеся линии - кнопки. Затем опрос порта в обработчике прерывания.

Если это вариант интересен - могу описать подробнее.



Извините, я сразу не заметил. Буду разбираться с программой, если будут вопросы - задам. Спасибо
Anjey_N
Я тут провёл один эксперимент. На макетке собрал схему: ATmega16, валкодер, индикация, кварц на 16 МГц. Валкодер подсоединил так: Выводы А и В на PA2 и PA3, средний вывод на землю.
Код привожу, если кому-то интересно.
Результаты такие: энкодер начал нормально работать , не так , как в предыдущих постах.
Начал эксперементировать с задержкой. До 2мс энкодер работает хорошо, потом начинаются глюки.
Теперь хочу посадить средний вывод на стробирование. Результаты отпишу позже.
Anjey_N
Провёл следующий эксперимент.
Результаты те же, при опросе 1р в 10 мс и выше - глюки, ниже - лучше. Вывод сделал такой: средний вывод валкодера нужно цеплять только на землю!!
676038
Позволю себе маленькие замечания по коду:
- При инициализации глобальных переменных присваивать 0 не надо, это делается автоматически.
- Глобальну переменную encoder лучше объявить static и сделать это внутри функции ReadEncoder(), ведь она больше нигде не используется...

А теперь по существу - опрашивать энкодер в главном цикле программы нехорошо, т.к. частота опроса становится непредсказуемой (на нее влияют обработчики прерываний и действия внутри главного цикла). Если уж сильно хочется опрашивать состояние энкодера поллингом, то лучше вызывать считывание состояния экодера из таймера - в этом случае хоть частота опроса будет стабильной и предсказуемой. Но при этом хорошо бы хоть примерно прикинуть максимально возможную частоту опроса, учитывая что надо опрашивать сразу два энкодера и несколько кнопок...

Может, все-таки, лучше завести одну линию от энкодера на вход прерывания и опрашивать состояние энкодера только при возникновении этого прерывания? Тогда не придется тратить процессорное время на бесполезный опрос... Но я, конечно, не настаиваю.
Anjey_N
Цитата(676038 @ Nov 21 2007, 00:03) *
А теперь по существу - опрашивать энкодер в главном цикле программы нехорошо, т.к. частота опроса становится непредсказуемой (на нее влияют обработчики прерываний и действия внутри главного цикла). Если уж сильно хочется опрашивать состояние энкодера поллингом, то лучше вызывать считывание состояния экодера из таймера - в этом случае хоть частота опроса будет стабильной и предсказуемой. Но при этом хорошо бы хоть примерно прикинуть максимально возможную частоту опроса, учитывая что надо опрашивать сразу два энкодера и несколько кнопок...


В программе, где будут использоватся валкодеры, частота их опроса будет 1 раз в 1мс. А за замечания - спасибо
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.