0 / 0 / 0
Регистрация: 05.10.2007
Сообщений: 498
|
|
1 | |
Обработка сигналов энкодера25.09.2014, 11:34. Показов 7257. Ответов 0
Метки нет (Все метки)
Занимаюсь новым интерфейсом для своих систем. Разработал простую и интересную программу для работы с энкодером. Мне она понравилась, и захотелось поделиться удачной программой.
Просматривая аналогичные решения по обработке сигналов от инкрементального энкодера, я увидел три способа решения задачи: 1) с помощью условных переходов и статических переменных, хранящих предыдущие состояния энкодера; 2) с помощью машины состояний, которая переключается по сигналам энкодера, исключая запрещённые состояния. 3) вариация номера два с использованием switch - case с метками возможных состояний. Однако, все варианты имеют недостатки. Вариант номер один использует несколько переменных и переключается один раз за четыре возможных состояния энкодера. Вариант номер два использует одну переменную, в которой хранятся в битовом представлении текущее и предыдущее состояние энкодера. Анализ состояний производится с помощью массива данных. Это вариант мне понравился больше всего. Но в том состоянии алгоритм не защищён от ложных срабатываний и пропуска данных. Вариант номер три использует такое же представление данных, как и вариант номер два, но вместо массива данных использует переход по множеству case меток. Самый неудобный и трудный для восприятия. Взяв второй метод за основу, я доработал его до приемлемого вида. Вначале основы. При повороте энкодера по часовой стрелке состояние выводов изменяются как 00, 01, 11, 10, 00... А при повороте против часовой стрелки состояние выводов изменяется в другой последовательности: 00, 10, 11, 01, 00... Считывать состояния энкодера можно один, два или четыре раза за период, но необходимо учитывать предыдущее состояние. Например, если текущее состояние энкодера 11 и предыдущее значение 01, то энкодер повернули по часовой стрелке. А если предыдущее значение 10, то энкодер повернули против часовой стрелки. Соответственно, предыдущие состояния 00 и 11 будут ошибочными, и их нужно игнорировать. Итак, мы имеем 4 варианта текущего состояния и 4 варианта предыдущего состояния энкодера. Вместе они дают 16 комбинаций. Если взять переменную из четырёх бит, и в младшие два бита записать текущее состояние, а в старшие два - предыдущее состояние, и использовать получившееся число как индекс в массиве, то с помощью значений чисел в массиве возможно точно определить состояние энкодера. Например, 1 - поворот вправо, -1 - поворот влево, 0 - запрещённая комбинация. Что самое интересное, это то, что такой алгоритм можно применять как для одного изменения энкодера за период, так и для двух и четырёх изменений. А это важно, потому что встречаются энкодеры с разным количеством периодов за оборот. Например, энкодеру с 12 периодами однозначно понадобится 2 или 4 изменения за период, а энкодеру с 48 периодами не больше 1. Возможность подстройки под тип энкодера это первое преимущество. Второе - я добавил защиту от повторных срабатываний при одинаковом положении энкодера. Например, встретилось два подряд значения 01. Без фильтрации это вызовет запрещённое состояние 01-01 и ошибку в определении следующего состояния. Почему - ответ в третьем преимуществе. Программа анализирует три последовательные состояния энкодера, и при переходе, например, 00-01-00 (то есть шаг туда, шаг сюда) не будет двух ложных срабатываний энкодера. Без фильтрации мы можем получить последовательность состояний 00-01-01-00 и сравнение текущего и третьего состояний не решит проблему дрожания энкодера. Такая проверка нужна для 1-го и 2-х срабатываний за период энкодера. Программу я писал для микропроцессора STM8S в среде IAR. Текст приведён ниже: Код
// определение количества событий за период энкодера (1, 2, 4) #define ENC_COUNT 2 // массив правильных значений переходов // между предыдущим и настоящим значением энкодера #if (ENC_COUNT == 1) // для 1-го переключения за период int8_t enc_array [16] = { 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }; #elif (ENC_COUNT == 2) // для 2-х переключений за период int8_t enc_array [16] = { 0, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 0 }; #else // для 4-х переключений за период int8_t enc_array [16] = { 0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, 1, 0 }; #endif uint8_t state = 0; // сохранённые состояния энкодера int8_t count_encoder = 0; // переменная приращения энкодера /***************************************************************************** * Настройка энкодера. * Ножки на вход с подтяжкой к питанию * Прерывания на этот порт с активацией по фронту и спаду * Приоритет высокий *****************************************************************************/ void encoder_init (void) { // настройка контроллера прерываний __disable_interrupt(); EXTI->CR1 &= ~EXTI_CR1_PAIS_MASK; EXTI->CR1 |= 0x03; //EXTI_CR1_PAIS_FR; // Прерывания А по фронту и спаду // настройка приоритетов прерываний ITC->ISPR2 &= ~ITC_SPR2_PORTA_MSK; ITC->ISPR2 |= ITC_SPR2_PORTA_LVL3; // высокий уровень прерываний порта A // настройка ножек GPIO_ConfigInput (ENC_A_PORT1, ENC_A_PIN1, PinPullup, PinIrqOn); GPIO_ConfigInput (ENC_B_PORT1, ENC_B_PIN1, PinPullup, PinIrqOn); // установка текущего состояния энкодера if (ENC_A_PIN) state |= 0x01; if (ENC_B_PIN) state |= 0x02; __enable_interrupt(); } /***************************************************************************** * Прерывание по порту A * здесь опрашивается состояние энкодера * результат прерывания сохраняется в переменной count_encoder *****************************************************************************/ INTERRUPT_HANDLER (Port_A_EXTISR, 3) { int8_t stt; state <<= 2; // освободили место для новых значений if (ENC_A_PIN) state |= 0x01; if (ENC_B_PIN) state |= 0x02; // считали данные энкодера if ((state & 0x03) != ((state >> 2) & 0x03)) // если разные значения с предыдущим { stt = enc_array [state & 0x0F]; // получили условие из таблицы if (stt) // при изменении энкодера { #if (ENC_COUNT == 1 || ENC_COUNT == 2) if ((state & 0x03) != ((state >> 4) & 0x03)) // и если энкодер не вернулся обратно #endif { count_encoder += stt; // изменим счётчик энкодера } } } else { state >>= 2; // если одинаковые значения - вернуть state } } /***************************************************************************** * функция int_8t encoder() возвращает изменение положения * энкодера после последнего чтения, если энкодер не двигался, то 0 ******************************************************************************/ int8_t encoder (void) { int8_t status = count_encoder; count_encoder = 0; return status; }
0
|
25.09.2014, 11:34 | |
Ответы с готовыми решениями:
0
Обработка энкодера обработка инкрементального энкодера на прерываниях (asm) [MSC-51] Цифровая обработка сигналов по формулам Цифровая обработка сигналов. Ортогональность сигналов Обработка ЧМ сигналов(спектры ЧМ сигналов) |
25.09.2014, 11:34 | |
25.09.2014, 11:34 | |
Помогаю со студенческими работами здесь
1
Обработка сигналов Обработка сигналов Обработка сигналов Обработка сигналов обработка сигналов Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |