|
|
  |
MEGA+энкодер |
|
|
|
Sep 19 2006, 07:47
|
Частый гость
 
Группа: Свой
Сообщений: 75
Регистрация: 7-04-05
Из: Украина
Пользователь №: 3 948

|
Один из сигналов (А или В ) я заводил на внешнее прерывание, второй на любую ногу порта, сконфигурированую как вход. Прерывание - по любому логическому изменению сигнала. В обработчике, исходя из предыдущего и текущего значения сигналов А и В (предыдущее значение - значение А и В, при предыдущем вызове обработчика внешнего прерывания ) принимал решение в какую сторону происходит вращение и соотв. увеличивал или уменьшал значение требуемой переменной. Вот краткий алгоритм работы.. если нужно более подробное описание - обращайтесь...
Сообщение отредактировал XsanyaX - Sep 19 2006, 07:48
--------------------
Метрология - наука о достаточной точности.
|
|
|
|
|
Sep 19 2006, 08:25
|

Местный
  
Группа: Участник
Сообщений: 318
Регистрация: 21-07-06
Из: Минск
Пользователь №: 18 986

|
Обработка энкодера по прерываниям неудобна, так как требуется давить дребезг. Более того, чтобы корректно реализовать квадратурный декодер 1х (или 2х, 4х), прерывания должны происходить не по фронту или спаду одного из сигналов, а по любому изменению состояния энкодера. Отсюда следует порочность декодера типа "программный D-триггер, один сигнал энкодера на вход D, второй - на C". При такой реализации INC/DEC всегда происходит по фронту одного из сигналов энкодера, что есть неправильно. Если вал энкдера просто пошевелить на месте, может насчитаться куча импульсов. INC/DEC нужно делать по изменению состояния двух сигналов, чтобы и INC, и DEC происходили в одной и той же точке, но при её проходе с разными направлениями вращения. Информацию о построении правильных квадратурных декодеров можно почерпнуть из описания спец. микросхем, например, HCTL-2000. Я обрабатываю энкодер и его кнопку в основном цикле программы. Если программа чем-то занята, то она всё равно не сможет отреагировать на вращение энкодера, а буферизовать проделанный поворот и откладывать его обрботку - это уже слишком. Практика показала, что для комфорного использования энкодера задержки на подавление дребезга не должны превышать 500 мкс, иначе становится заметным пропуск шагов при резком повороте ручки. Я использую 300 мкс. Столь малые времена, к сожалению, не могут быть сформированы системным таймером как большинство других временных интервалов в программе. Поэтому приходится применять "тупую" задержку в виде цикла. Для таких малых интервалов это вполне допустимо, потери производительности процессора будут минимальными. Тем более, что обработка энкодера - это общение с пользователем, который всегда является самым медленным звеном системы  Более того, если какая-то задача в основном цикле захочет временно забрать все ресурсы процессора (за вычетом потерь на прерывания), она сможет это сделать. В это время энкодер обслуживаться не будет. Для кнопки время подавления дребезга должно быть существенно большим, я использую 50 мс. Уж очень разные механические характеристики контактных групп кнопки и энкодера. Сюда выложил пример обработки энкодера на асме для AVR: http://upload.caxapa.ru/Enc.txt
--------------------
|
|
|
|
|
Sep 19 2006, 08:52
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 8-06-06
Пользователь №: 17 866

|
Цитата(vetbaston @ Sep 19 2006, 10:17)  Есть MEGA64 и инкрементальный энкодер PEC12-4220F , кто работал с энкодером посоветуйте , как правильно обстучать его?  здесь кусок обслуживающий кодер, кнопку сам допишешь. Полностью согласен с Леонидом Ивановичем, поэтому функцию вызываю из основной программы примерно раз в 20мСек, избавляюсь от дребезга и слишком быстрого вращения define PIN_Coder PIND//PD0,PD1 char status,encoder = 0; //----------------------------------------------------------------------------------- signed char ReadEncoder(void) { register signed char temp = 0; encoder = (~PIN_Coder & 0x03);//ïðîâåðÿåì 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; } //-----------------------------------------------------------------------------------
|
|
|
|
|
Sep 19 2006, 11:16
|
Местный
  
Группа: Свой
Сообщений: 256
Регистрация: 4-11-04
Из: Болгария
Пользователь №: 1 050

|
Не невозможно сделат на 2 перервания. Вот я делал. Прилагаю изходник. Ето работает стабилно.
|
|
|
|
|
Sep 21 2006, 07:18
|

Мастер-фломастер
   
Группа: Свой
Сообщений: 611
Регистрация: 29-12-05
Пользователь №: 12 700

|
Цитата(Леонид Иванович @ Sep 19 2006, 12:25)  Обработка энкодера по прерываниям неудобна, так как требуется давить дребезг. Я обрабатываю энкодер и его кнопку в основном цикле программы. А я наоборот отказался от полинга работы с энкодером когда имеем достаточный загруз контроллера - иногда очень не аккуратно получалось ;-) сейчас работаю по прерыванию как уже говорилось выше... но несколько застраховавшись от дребезга, введя переменную "чувствительности" энкодера - она, кстати, очень полезна.. хотя дребезг есть также последствие мех воздействия и его отметать тоже не стоит - а нужно проанализировать... проблем уже как 3 года не наблюдаю причем даже с нонейм энкодерами, и энкодерами имеющие достаточный мех износ.... плюс ко всему под прерывание все прекрасно ложиться - и ресурсов кушает очень мало... так что вот ещё автору, тема для обмозгования..
--------------------
Вон ПОПОВ, клоун клоуном, а радио изобрел!!
|
|
|
|
|
Sep 21 2006, 09:17
|
Местный
  
Группа: Новичок
Сообщений: 232
Регистрация: 24-06-06
Пользователь №: 18 332

|
Цитата(Kovrov @ Sep 21 2006, 11:18)  проблем уже как 3 года не наблюдаю причем даже с нонейм энкодерами, и энкодерами имеющие достаточный мех износ.... плюс ко всему под прерывание все прекрасно ложиться - и ресурсов кушает очень мало... Если не жалко - можно пример кода на Си ?
|
|
|
|
|
Sep 21 2006, 09:42
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Для устранения дребезга по нескольким входам с одинаковой динамикой удобно использовать алгоритм "вертикальных счетчиков". Выходы енкодера обрабатывались по 100 мкс прерываниям фильтром на вертикальных счетчиках. Результат: PIn - отфильтрованные входы, PInChg - изменения по входам. Извините, прога на ассемблере под PIC'и. C-шный код достаточно раскомментировать.[attachment=7297:attachment] PIn и PInChg можно дальше обработать в основном цикле, или, если напряг по времени, не отходя от кассы. PInChg должен быть обработан до следующего прерывания. Применительно к энкодеру в предположении, что обрабатываются только два входа: Код uchar EncPos = 0; // IA и IB , естесно, равны номерам битов входов, на которые бегут выходы енкодера // bit-fields располагаются соответственно #define IA 0 #define IB 1 union { uchar i; struct { uchar A: 1; uchar B: 1; } b; } PIn, PInChg; ... if(PInChg.i == ((1<<IA)|(1<<IB))) { switch (PIn.i) { не вдаваясь в подробности case 0: ... case (1<<IA): ... case (1<<IB): ... case ((1<<IA)|(1<<IB)): ... } EncPos = PIn.i; } Ограничения: битовые позиции входов по портам (если обрабатываются входы с нескольких портов) не должны пересекаться.
|
|
|
|
|
Sep 21 2006, 15:46
|

Мастер-фломастер
   
Группа: Свой
Сообщений: 611
Регистрация: 29-12-05
Пользователь №: 12 700

|
Цитата(Леонид Иванович @ Sep 21 2006, 13:07)  А какой физический смысл несет переменная "чувствительность энкодера"? фактически это счетчик инкрементов или декриментов очень хорошо когда энкодеры на различное число импульсов на оборот Цитата(Shurmas @ Sep 21 2006, 13:17)  Если не жалко - можно пример кода на Си ? увы на си для 8 бит не пишу... а алгоритм описан выше - ничего секретного...
--------------------
Вон ПОПОВ, клоун клоуном, а радио изобрел!!
|
|
|
|
|
Sep 22 2006, 04:48
|
Знающий
   
Группа: Свой
Сообщений: 517
Регистрация: 7-02-06
Пользователь №: 14 073

|
Цитата(Леонид Иванович @ Sep 21 2006, 15:09)  Если частота опроса 20 Гц, то получится страшно тормозной энкодер. При быстром вращении он будет пропускать шаги - это некомфортно. Нужна частота опроса в 100 раз выше. Эта частота лишь для примера, ее можно и поднять в десятки раз, суть в использовании кольцевого буфера и занесения в него состояния энкодера. Частота опроса влияет на комфортность работы с энкодером: когда требуется менять параметры регулирования энкодером, например в диапозоне 0-1000 нужна частота выше, чем для диапазона 0-100. При большой частоте опроса бывают затруднения при подходе к требуемой точке , приходится балансировать. Вот и получается, что частота опроса должна быть адаптивной и зависеть от скорости вращения. Все требования к конпоновке органов управления, средствам отображения и удобству работы с органами управления, как и с прибором в целом, определяются эргономикой, как и та не очень высокая частота для "страшно тормозного энкодера", но с которым очень комфортно работать.
Сообщение отредактировал Vladimir_T - Sep 22 2006, 04:57
|
|
|
|
|
Sep 22 2006, 07:10
|

Мастер-фломастер
   
Группа: Свой
Сообщений: 611
Регистрация: 29-12-05
Пользователь №: 12 700

|
Цитата(Vladimir_T @ Sep 21 2006, 15:31)  Еще есть такое решение: По тику таймерного прерывания заполняется кольцевой буфер. интересно придумано :-) почему только таймерного? как то вот этот подбор времени тика таймера мне не очень нравиться... мне кажется эффективней анализировать в буфере данные от внешнего прерывания?
--------------------
Вон ПОПОВ, клоун клоуном, а радио изобрел!!
|
|
|
|
|
Sep 22 2006, 11:57
|

Мастер-фломастер
   
Группа: Свой
Сообщений: 611
Регистрация: 29-12-05
Пользователь №: 12 700

|
Цитата(Леонид Иванович @ Sep 22 2006, 12:30)  Что касается обработки энкодера по прерываниям: зачем зря тратить ресурсы, вызывая обработчик на каждом периоде дребезга? Запрещать прерывание на время подавления дребезга - это хорошая идея. Период таймера как раз и будет временем подавления дребезга. Могу сказать обратное... зачем тратить впустую циклы контроллера, обеспечивая задержку для подавления дребезга, и тем самым увеличивать время основного цикла... да и обработчик прерывания - всего ничего.... а таймер задействовать для этих целей мне откровенно говоря жалко их и так мало :-) а если взять прерывание типа PCint (вектор у него ниже) -вообще красота... А ещё можно к ногам энкодера прицепить конденсатор - тоже не лишнее будет при борьбе с дребезгом.. Ну и что, что прерывание сработает лишний (ненужный) раз - в любом случае это же какое то действие над энкодером. не лучше ли это действие проанализировать?... все таки работа по внеш прерыванию - мне кажется более экономной...
--------------------
Вон ПОПОВ, клоун клоуном, а радио изобрел!!
|
|
|
|
|
Sep 22 2006, 21:23
|

Местный
  
Группа: Участник
Сообщений: 318
Регистрация: 21-07-06
Из: Минск
Пользователь №: 18 986

|
Цитата(Kovrov @ Sep 22 2006, 14:57)  Могу сказать обратное... зачем тратить впустую циклы контроллера, обеспечивая задержку для подавления дребезга, и тем самым увеличивать время основного цикла... да и обработчик прерывания - всего ничего.... а таймер задействовать для этих целей мне откровенно говоря жалко их и так мало :-) Спорить здесь не о чем. Каждый из вариантов имеет право на жизнь. Предпочтительный вариант зависит от особенностей конкретного приложения. Бывает, что и таймер остается неприкаянный, бывает что и основному циклу делать нечего, когда программа ждет действий пользователя. Цитата(Kovrov @ Sep 22 2006, 14:57)  А ещё можно к ногам энкодера прицепить конденсатор - тоже не лишнее будет при борьбе с дребезгом.. Вот этого делать не стоит - конденсатор резко укоротит жизнь энкодера, так как увеличатся импульсные токи при коммутации. Вот RC-цепочку - это можно. Хотя изящнее бороться с дребезгом программно.
--------------------
|
|
|
|
|
Sep 23 2006, 04:00
|

Мастер-фломастер
   
Группа: Свой
Сообщений: 611
Регистрация: 29-12-05
Пользователь №: 12 700

|
конечно же спорить не о чем, да мы и не спорим - обычное обсуждение плюсов и минусов :-) Цитата(Леонид Иванович @ Sep 23 2006, 01:23)  Вот этого делать не стоит - конденсатор резко укоротит жизнь энкодера, так как увеличатся импульсные токи при коммутации. Я вас умоляю ..... :-) я же не предлагаю от 220 вольт запитывать и конденсатор 1000мкф :-))) а вот RC цепочка своей постоянной времени может как раз понизить "быстродействие" энкодера... тогда уж элемент с триггером Шмидта.. -вот что действительно спасет.
--------------------
Вон ПОПОВ, клоун клоуном, а радио изобрел!!
|
|
|
|
|
Nov 6 2006, 12:20
|

Частый гость
 
Группа: Свой
Сообщений: 105
Регистрация: 6-01-06
Пользователь №: 12 901

|
Хочу поделиться результатами опытов с энкодером...
Главное в работе с последним - это борьба с дребезгом. Для борьбы с ним общепринято вводить паузу (задержку) после обнаружения первого изменения уровня (фронта)...
Так я и делал (делал это в прерывании). Но что обраружилось: или происходили ложные срабатывания (если задержка мала) или (при значительном увеличении времени задержки) происходил пропуск срабатываний (при быстром вращении). Оптимальной, но не решившей проблему (возможно из-за свойств конкретного экземпляра энкодера), оказалась задержка в 300мкС, как и советовал ув. 'Леонид Иванович'.
Идея с подключением конденсатора, предложенная 'Kovrov', показалась мне весьма правильной, а проведенный опыт доказал полную состоятельность такого решения.
Таким образом, считаю, что для "победы" над дребезгом контактов, возникающим при работе энкодера, достаточно подключить параллельно выходам энкодера конденсаторы емкостью 0,1...0,15 мкФ (я поставил 0,15). При этом дребезг "пропадает" полностью (задержка не нужна совсем). Срабатывания отрабатываются правильно не зависимо от скорости вращения ручки энкодера.
Удачи! З.Ы. Подключение конденсатора безусловно снижает надежность конструкции (как минимум из-за введения новых деталей) и для СЕРЬЕЗНЫХ изделий такое решение не является правильным. Однако в бытовых условиях такое решения полностью оправдано.
|
|
|
|
|
Dec 6 2006, 13:28
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 25-07-06
Пользователь №: 19 070

|
Перечитал эту ветку и хочу предложить свой алгоритм подавления дребезга. Обкатал его на макете с двумя разными энкодерами (оптический из старой мышки) и механический ALPS - работает четко. Исходные даные - один выход энкодера заводим на вход INT0 (PIND_Bit2), второй выход на другую ногу (в данном случае PIND_Bit3). Настраиваем прерывание INT0 по любому фронту. Есть глобальная переменная "Volume", которая изменяет свое значение при вращении энкодера. Обработчик прерывания: Код #pragma vector=INT0_vect __interrupt void handler_int0(void) { static char flag;
if (flag == PIND_Bit2 ) return;
flag=PIND_Bit2;
if ((PIND_Bit3 == PIND_Bit2) && (volume <255)) volume++; if ((PIND_Bit3 != PIND_Bit2) && (volume > 0)) volume--; } И не используется никаких конденсаторов, таймеров или задержек, при этом все работает как должно. Что я упустил?
|
|
|
|
|
Dec 8 2006, 13:39
|
Участник

Группа: Свой
Сообщений: 63
Регистрация: 3-05-05
Пользователь №: 4 696

|
Посмотрите на "хвостатый экодер". Может пригодится. Mechanical mouse
|
|
|
|
|
Dec 13 2006, 05:15
|
Участник

Группа: Новичок
Сообщений: 38
Регистрация: 12-09-05
Пользователь №: 8 464

|
Нарисуйте на бумажке работу энкодера и сгенерируйте вариант работы который вас устроит. Меня вполне устраивает (правда со спец условиями) - энкодер механический, работает сносно. с оптическим не пробовал но думаю будет лучше и надежней - необходимости нет
Прикрепленные файлы
enk.txt ( 565 байт )
Кол-во скачиваний: 712
|
|
|
|
|
Sep 13 2007, 12:08
|
Участник

Группа: Свой
Сообщений: 65
Регистрация: 17-01-06
Пользователь №: 13 277

|
Цитата(Vladimir_T @ Sep 22 2006, 10:48)  Эта частота лишь для примера, ее можно и поднять в десятки раз, суть в использовании кольцевого буфера и занесения в него состояния энкодера. Частота опроса влияет на комфортность работы с энкодером: когда требуется менять параметры регулирования энкодером, например в диапозоне 0-1000 нужна частота выше, чем для диапазона 0-100. При большой частоте опроса бывают затруднения при подходе к требуемой точке , приходится балансировать. Вот и получается, что частота опроса должна быть адаптивной и зависеть от скорости вращения. Все требования к конпоновке органов управления, средствам отображения и удобству работы с органами управления, как и с прибором в целом, определяются эргономикой, как и та не очень высокая частота для "страшно тормозного энкодера", но с которым очень комфортно работать. Единственная светлая мысль на всю тему... И не обязательно частоте опроса быть адаптивной. Я сделал на плисе 80МГц. Отлично работает!
|
|
|
|
|
Sep 14 2007, 11:50
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(psw @ Sep 19 2006, 12:52)  здесь кусок обслуживающий кодер, кнопку сам допишешь. Полностью согласен с Леонидом Ивановичем ..... Вот здесь, в самом начале обсуждения, и был приведён правильный алгоритм, и соображения начёт скорости опроса. Сам я категорически не люблю программных задержек и фильтрации дребезга по времени. Сегодня дребезг один, затра другой. Сегодня енкодер - ручка пользователя о 16 позициях, завтра - мышка какая-нибудь быстробегающая... Поэтому. Если рассмотреть все фазы енкодера (00 01 10 11) то видно, что последовательность фаз в одну сторону 01320132... в другую 10231023.... Другие переходы (0132-3-2-3-20) есть дребезг. Т.е. нужен fifo на 3 двухбитных числа (1 байт/регистр) и анализ его 64 состояний (всего 2 значимые - шаг влево и шаг вправо). А уже как отслеживать - по прерыванию, поллингом - это каждый сам порешает.
|
|
|
|
|
Sep 14 2007, 15:17
|
Участник

Группа: Свой
Сообщений: 65
Регистрация: 17-01-06
Пользователь №: 13 277

|
Цитата(Maik-vs @ Sep 14 2007, 17:50)  Вот здесь, в самом начале обсуждения, и был приведён правильный алгоритм, и соображения начёт скорости опроса. Сам я категорически не люблю программных задержек и фильтрации дребезга по времени. Сегодня дребезг один, затра другой. Сегодня енкодер - ручка пользователя о 16 позициях, завтра - мышка какая-нибудь быстробегающая... Поэтому. Если рассмотреть все фазы енкодера (00 01 10 11) то видно, что последовательность фаз в одну сторону 01320132... в другую 10231023.... Другие переходы (0132-3-2-3-20) есть дребезг. Т.е. нужен fifo на 3 двухбитных числа (1 байт/регистр) и анализ его 64 состояний (всего 2 значимые - шаг влево и шаг вправо). А уже как отслеживать - по прерыванию, поллингом - это каждый сам порешает. Да. Без сомнений, кусок тот самый. Ни в каких модификациях не нуждается. Помнить больше 4 бит смысла нет. Из них только 2 бита во время пребывания снаружи этого кода. Переходы 3-2-3-2-3-2 отлавливаются по 4м битам. Со счётчиком будет происходить +1,-1,+1,-1,+1,-1 - что на конечный результат отрицательно не скажется. Прошу прощения, если кого-то ввёл в заблуждение... Тема исчерпана...
|
|
|
|
|
May 16 2008, 17:29
|
Гуру
     
Группа: Свой
Сообщений: 2 318
Регистрация: 13-02-05
Из: Липецкая область
Пользователь №: 2 613

|
Цитата(qqqqqq @ Sep 14 2007, 19:17)  Да. Без сомнений, кусок тот самый. Ни в каких модификациях не нуждается. Помнить больше 4 бит смысла нет. Из них только 2 бита во время пребывания снаружи этого кода. Переходы 3-2-3-2-3-2 отлавливаются по 4м битам. Со счётчиком будет происходить +1,-1,+1,-1,+1,-1 - что на конечный результат отрицательно не скажется. Прошу прощения, если кого-то ввёл в заблуждение... Тема исчерпана... Пробую использовать энкодер PEC16 BOURNS. Предварительно заготовленный код не пошел. Решил попробовать упоминаемый код, сбоит. Снял несколько осциллограм. Это с установленными RC цепочками. Без них иголки полноразмерные. Попробую использовать прерывания, с многократным считыванием в течении 5 мсек для принятия решения о состоянии уровня. Благо, на 4 энкодера и кнопки целая Мега88.
Эскизы прикрепленных изображений
|
|
|
|
|
May 17 2008, 07:51
|
Гуру
     
Группа: Свой
Сообщений: 2 318
Регистрация: 13-02-05
Из: Липецкая область
Пользователь №: 2 613

|
Смотрел на одном. Но исходя из вида плоскости контактных пластин и конструкции фиксатора, такую ситуацию нельзя исключать. Правда, энкодеры имеют 24 положения на оборот, что, на мой взгляд, много. Оптимально, я думаю, 10-12. Потом сменю, а пока то, что есть. 5 мс - предварительно, исходя из ширины импульса при более, менее разумном вращении. Далее буду уменьшать. И RC цепочки уберу, вероятно.
|
|
|
|
|
May 18 2008, 10:52
|
Гуру
     
Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047

|
Цитата(777777 @ May 17 2008, 18:19)  Ну вы даете! Я успешно обрабатываю с помощью ATtiny13 программой из 100 байт. Правда, не покупной энкодер (долгий поиск выявил, что все они - полное говно), Вот так прямо и все ? Что-то не замечал... Видел разок истирание пары позиций в валкодере трансивера от Yaesu, а так - работают годами, без проблем. В некоторых готовых изделиях - бывает пропуск или забывчивость, но совершенно однозначно чисто программная проблема. Тоже, видимо, кто-то посчитал, что раз энкодеры г..., то и утруждать себя правильной обработкой не стоит. А вот если головой подумать (или хоть начало топика прочитать, где как раз все разжевано) - то все получится просто, надежно, и будет работать много лет. Цитата а оптрон TCUT1300. А нахрена ? Еще и оптическую часть городить, юстировать... Оптическая мышь стоит от сотни рублей, вытаскивается сенсор с подсветкой - и вот все готово. Бонусом еще и отдельный оптический кодер на колесико. С трещеткой. Цитата Так он еще и не оптический?! Выкинуть на помойку немедленно! Разрешите выполнять ?! Вот сейчас прямо бегом все помчались... А кто будет делать трещетку, кнопку на шток ? Кто обеспечит микропотребление ? Предложите что-то оптическое в ту же цену, что изделия от Boirns или ALPS ? Нет ? Тогда, может быть, стоит поумерить категоричность ? Цитата А я еще удивляюсь, какой у энкодера может быть дребезг... А еще дребезг бывает у кнопок, переключателей и реле. Если драйвер руки.sys настроен правильно - не мешает.
|
|
|
|
|
May 18 2008, 11:23
|
Участник

Группа: Участник
Сообщений: 25
Регистрация: 8-08-05
Пользователь №: 7 466

|
Цитата(Леонид Иванович @ Sep 21 2006, 15:09)  Если частота опроса 20 Гц, то получится страшно тормозной энкодер. При быстром вращении он будет пропускать шаги - это некомфортно. Нужна частота опроса в 100 раз выше. Пробовал тут рулёз от Parallax. Там готовая прога шла к нему на 16 квадратурных энкодеров. При внешнем кварце 8МГц и умножителе на 16 (внутренняя 128МГц) без прерываний обрабатывалось на ура. Может то же попробуете. Микроконтроллер P8X32A (на имраде 82 грн.).
|
|
|
|
|
May 18 2008, 17:04
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(rx3apf @ May 18 2008, 14:52)  Видел разок истирание пары позиций в валкодере трансивера от Yaesu, а так - работают годами, без проблем. И что, это нормально, с неработающей позицией можно продолжать работать? Цитата(rx3apf @ May 18 2008, 14:52)  В некоторых готовых изделиях - бывает пропуск или забывчивость, но совершенно однозначно чисто программная проблема. Пропуск - это чисто аппаратная проблема. Цитата(rx3apf @ May 18 2008, 14:52)  А нахрена ? Еще и оптическую часть городить, юстировать... Что там юстировать? Поставил колесо с прорезями и пусть крутится. Цитата(rx3apf @ May 18 2008, 14:52)  А кто будет делать трещетку, кнопку на шток? Не понял, что за трещетка с кнопкой?
|
|
|
|
|
May 18 2008, 18:03
|
Гуру
     
Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047

|
Цитата(777777 @ May 18 2008, 21:04)  И что, это нормально, с неработающей позицией можно продолжать работать? Нет. Вот этот как раз случай, когда требуется замена. Вот только я встречался с этим один раз. А так - работают годами, даже там, где используется активно. Более того, механические кодеры использовались даже в компьютерных мышах, а уж там износоустойчивость нужна солидная. Цитата Пропуск - это чисто аппаратная проблема. Нет. Не всегда, точнее. Зависит от обработки. И есть у меня такое подозрение, что заявления типа "готовые кодеры - г.." происходит как раз из-за непонимания, как надо обрабатывать сигналы таких датчиков. Гордое заявление про программу из 100 байт - тоже. Куда там столько ? Автомат состояний для кодера с дребезгом - этак слов 20-30 программы (AVR). И не пропускает, и лишнего не считает. Цитата Что там юстировать? Поставил колесо с прорезями и пусть крутится. И каналы должны располагаться с определенным сдвигом, и диск с соотствующим шагом и шириной прорезей. Который еще надо сделать, хоть бы даже напечатав на прозрачной пленке. Но - делать. И это - не самая сложная часть. И уж если нужен дешевый оптический кодер - то оптомышь за сотню рублей гораздо удобнее и надежнее. Цитата Не понял, что за трещетка с кнопкой? Основная масса механических энкодеров имеет достаточно крупный шаг, причем эти шаги ощущаются тактильно (как, например, колесико мыши), причем у разных изделий - по-разному (скажем, PEC12, PEC16 - довольно мягкие, попадавшиеся мне ALPS - жесткие и четкие, в зависимости от назначения выбирается тот или иной тип). Замена на плавно вращающийся кодер просто недопустима по эргономическим соображениям, это столь же неудобно, как компьютерная клавиатура без клика. Там же, где нужна плавность - и без того обычно применяют оптику. Дело и не только в ресурсе - трудно сделать механический кодер с сотнями импульсов на оборот. А еще у мелких механических кодеров часто есть кнопка на штоке, во многих случаях удобная вещь. И заниматься самодельщиной, изобретая механическую часть самостоятельно - удел радиолюбителей. Для единичного изделия - годится. Для серийного - нет.
Сообщение отредактировал rx3apf - May 18 2008, 18:14
|
|
|
|
|
May 19 2008, 09:09
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(rx3apf @ May 18 2008, 22:03)  Основная масса механических энкодеров имеет достаточно крупный шаг, причем эти шаги ощущаются тактильно (как, например, колесико мыши) Так вам он нужен в качестве элемента управления? Я-то думал - как промышленый датчик... Тогда зачем энкодер? Поставьте многопозиционный переключатель и будет вам щасття Цитата(rx3apf @ May 18 2008, 22:03)  И заниматься самодельщиной, изобретая механическую часть самостоятельно - удел радиолюбителей. Для единичного изделия - годится. Для серийного - нет.  К счастью, у нас есть конструкорский отдел и механический цех, который умеет точить любые детали, а уж диск с зубьями 1.6 мм - плевое дело. А что такое самодельщина? Ведь ты тоже что-то делаешь, разрабатываешь какие-то схемы - зачем заниматься самодельщиной, ведь наверняка это уже кто-то делал до тебя, не проще ли это купить? Я знаю одно предприятие, на котором никогда не разрабатываются собственные платы - это такая принципиальная установка руководства. Хотя они занимаются промышленной автоматизацией. Для любого изделия закупается готовая микропроцессортая плата, вставляется в покупной корпус - и все, изделие готово, остается только запрораммировать. В качестве пульта или монитор, или - в последнее время - берется микропроцессорная плата с установленным на ней ЖК дисплеем. То есть, кроме проводов и разъемов -ничего своего. Так что, самодельщина - понятие растяжимое, все зависит от профиля предприятия.
|
|
|
|
|
May 19 2008, 18:51
|
Гуру
     
Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047

|
Цитата(777777 @ May 19 2008, 13:09)  Так вам он нужен в качестве элемента управления? Я-то думал - как промышленый датчик... Тогда зачем энкодер? Поставьте многопозиционный переключатель и будет вам щасття Неудобно и ненадежно. И конструкторы связной аппаратуры (где инкрементальные энкодеры с трещеткой применяются повсеместно) придерживаются того же мнения. Там, где положения фиксируются - ничего лучше не придумано. Там, где плавная перестройка - оптика. Аналогично и в другой аппаратуре - где нужно переключатель - поставлю переключатель или абсолютный кодер. А то и сенсорную кнопку. От задачи зависит. Цитата  К счастью, у нас есть конструкорский отдел и механический цех, который умеет точить любые детали, а уж диск с зубьями 1.6 мм - плевое дело. Без особой нужды заниматься изготовлением, пусть даже в заводских условиях, серийного коммутирующего элемента - занятие неблагодарное и попросту глупое. Цитата А что такое самодельщина? Ведь ты тоже что-то делаешь, разрабатываешь какие-то схемы - зачем заниматься самодельщиной, ведь наверняка это уже кто-то делал до тебя, не проще ли это купить? Конечно. Для себя, "для души". Но если что-то такое, что уже "есть в природе" - то стимулом может быть разве что неподходящая цена или качество. Чаще - отсутствие каких-то требуемых функций. Однако времена, когда радиолюбители с энтузиазмом химичили с самодельными детектирующими кристаллами, высунув язык, искали активные точки, делали конденсаторы из стекла и фольги, а резисторы из угольных стержней и стеклянных трубок - давно прошли. Серийный компонент "на коленке" не сделать лучше, чем Bourns, ALPS или кто еще. Так что неубедительно даже применительно к любительской конструкции. В серийное же продаваемое изделие мне такое решение поставить - даже в кошмарном сне не привидится. Это кошмарные ужасы совка, надеюсь, что в далеком прошлом, и возврата к ним не будет...
Сообщение отредактировал rx3apf - May 19 2008, 18:52
|
|
|
|
|
May 20 2008, 07:27
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(rx3apf @ May 19 2008, 22:51)  Но если что-то такое, что уже "есть в природе" - то стимулом может быть разве что неподходящая цена или качество. Ты наверное не понял. Ты предлагаешь не делать "комплектующие", а покупать. Но ведь то изделие, которое ты разрабатываешь - оно тоже является "комплектующим" для более крупного изделия. И если рассуждать как ты - то делать вообще ничего не надо, ведь наверняка кто-то уже это делает. Но тогда ты не получишь зарплату, а твой шеф - прибыль. Так что, стимулом для изготовления чего угодно является не цена или качество имеющегося, и уж тем более не его отсутствие, а банальное желание получить прибыль и подвинуть конкурентов.
|
|
|
|
|
May 20 2008, 09:03
|

Местный
  
Группа: Участник
Сообщений: 318
Регистрация: 21-07-06
Из: Минск
Пользователь №: 18 986

|
Цитата(sitafern @ May 18 2008, 14:23)  Пробовал тут рулёз от Parallax...Может то же попробуете. А смысл? С обработкой энкодера нормально справляется AVR. Сейчас использую такой код: Код char Enc_Scan(void) { char n = 0; if(Pin_ENC_F1) n |= EF1; //проверка линии F1 if(Pin_ENC_F2) n |= EF2; //проверка линии F2 return(n); }
//вызывается в основном цикле: void Encoder_Exe(void) { char EncTmp = Enc_Scan(); //сканируем энкодер и запоминаем результат char EncChg = EncTmp ^ EncPre; //разница текущего и предыдущего значений if(!EncChg) return; //ели нет изменений, выход
Delay_us(ENCDEB); //антидребезговая задержка для энкодера
char EncNew = Enc_Scan(); //сканируем энкодер еще раз if(EncNew != EncTmp) return; //дребезг не закончился, выход EncTmp = EncPre; //запоминаем предыдущее значение EncPre = EncNew; //обновляем предыдущее значение
if(!(EncTmp & EF1) && (EncNew & EF1) && !(EncNew & EF2)) { Msg = ENC_DN; return; } //вращение против часовой стрелки if((EncTmp & EF1) && !(EncNew & EF1) && !(EncNew & EF2)) { Msg = ENC_UP; return; } //вращение по часовой стрелке } //Msg - сообщение энкодера, которое сбрасывается при обработке. Иногда делаю еще измерение скорости вращения энкодера и при быстром вращении формирую другие сообщения (например, для изменения редактируемого параметра в 10 раз быстрее).
--------------------
|
|
|
|
|
Jun 17 2008, 11:06
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 13-06-08
Из: KYIV
Пользователь №: 38 269

|
Цитата(676038 @ Dec 6 2006, 16:28)  Перечитал эту ветку и хочу предложить свой алгоритм подавления дребезга. Обкатал его на макете с двумя разными энкодерами (оптический из старой мышки) и механический ALPS - работает четко.
Исходные даные - один выход энкодера заводим на вход INT0 (PIND_Bit2), второй выход на другую ногу (в данном случае PIND_Bit3). Настраиваем прерывание INT0 по любому фронту. Есть глобальная переменная "Volume", которая изменяет свое значение при вращении энкодера.
... взял за основу, прерьівание по спаду volume - вьівожу на дисплейчик сделал так: Код interrupt [EXT_INT0] void ext_int0_isr(void) { GICR = 0x00; delay_ms(3); if (!PIND.2) { if ((PIND.1==0) && (volume <255)) volume++; if ((PIND.1==1) && (volume > 0)) volume--; } GICR = 0x40; } получил интересную картину, на один щелчок енкодера проходит 2 значения т.е. на дисплейчике видньі только четньіе или нечетньіе числа что я не так делаю? или советуете обрабатьівать в основном цикле как у Леонид Иванович
|
|
|
|
|
Jun 17 2008, 13:45
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 25-07-06
Пользователь №: 19 070

|
Цитата(wired @ Jun 17 2008, 17:06)  взял за основу, прерьівание по спаду volume - вьівожу на дисплейчик сделал так: Код interrupt [EXT_INT0] void ext_int0_isr(void) { GICR = 0x00; delay_ms(3); if (!PIND.2) { if ((PIND.1==0) && (volume <255)) volume++; if ((PIND.1==1) && (volume > 0)) volume--; } GICR = 0x40; } получил интересную картину, на один щелчок енкодера проходит 2 значения т.е. на дисплейчике видньі только четньіе или нечетньіе числа что я не так делаю? или советуете обрабатьівать в основном цикле как у Леонид ИвановичЯ считаю, что обрабатывать энкодер в основном цикле - пустая трата ресурсов процессора, ведь обычно энкодер - это устройство ввода команд пользователя, и прибор обычно находится в ожидании таких команд. (Услилитель играет музыку 2 часа в день, а громкость мы выставляем за 5 секунд...) Обычно есть проблема с недостаточной чувствительностью (пропуски щелчков), а здесь же наоборот - и это хорошо. Значит надо просто посмотреть, как настроено прерывание - по переднему фронту, по заднему или изменению состояния. Если стоит измение состояния - то задать по фронту. Ну а если же настроено по фронту, то "real_volume = volume >> 1;" должно помочь.
|
|
|
|
|
Jun 17 2008, 14:11
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 13-06-08
Из: KYIV
Пользователь №: 38 269

|
Цитата(676038 @ Jun 17 2008, 16:45)  Я считаю, что обрабатывать энкодер в основном цикле - пустая трата ресурсов процессора, ведь обычно энкодер - это устройство ввода команд пользователя, и прибор обычно находится в ожидании таких команд. (Услилитель играет музыку 2 часа в день, а громкость мы выставляем за 5 секунд...)
Обычно есть проблема с недостаточной чувствительностью (пропуски щелчков), а здесь же наоборот - и это хорошо. Значит надо просто посмотреть, как настроено прерывание - по переднему фронту, по заднему или изменению состояния. Если стоит измение состояния - то задать по фронту. Ну а если же настроено по фронту, то "real_volume = volume >> 1;" должно помочь. сейчас прерьівание по спаду импульса. думаю разницьі не будет спад или фронт... похоже гдето у меня в логике косяк... обработка результата работьі енкодера у меня в основном цикле если изменился volume то... отключаем прерьівания глобально пишем в индикатор, пишем в регулятор громкости пишем в память EEPROM включаем прерьівания.... едем дельше по основному циклу
Сообщение отредактировал wired - Jun 17 2008, 14:14
|
|
|
|
|
Jun 17 2008, 14:51
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(wired @ Jun 17 2008, 14:06)  взял за основу, прерьівание по спаду volume - вьівожу на дисплейчик ....... получил интересную картину, на один щелчок енкодера проходит 2 значения т.е. на дисплейчике видньі только четньіе или нечетньіе числа что я не так делаю? или советуете обрабатьівать в основном цикле как у Леонид Иванович Достался мне как-то "в наследство" проект, в котором обработывался энкодер... "Дядя" его обработку сделал - как и Вы: прерывание по одному выходу энкодера; направление вращения - анализ состояния другого выхода. Получалось - примерно тоже, что и у Вас: то изменение значения на 1 за щелчок, то на 2... Пришёл к следующему заключению: выход энкодера, заведённый на прерывание - он тоже, конечно, "дребезжит", поэтому после изменения этого выхода -> взводится соответствующий флаг -> происходит прерывание -> флаг сбрасывается, но "дребезг" приводит к повторной установке флага во время обрабоки прерывания -> после выхода из прерывания имеем ещё одно прерывание на тот же щелчок энкодера. Иногда повторного прерывания не происходит, тогда - приращение на 1. В результате - переделал обработку энкодера - получил, что-то аналогичное обработке от Леонида Ивановича. Рекомендую и Вам сделать что-то такое же.
|
|
|
|
|
Jun 17 2008, 15:01
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 13-06-08
Из: KYIV
Пользователь №: 38 269

|
Цитата(Палыч @ Jun 17 2008, 17:51)  Достался мне как-то "в наследство" проект, в котором обработывался энкодер... "Дядя" его обработку сделал - как и Вы: прерывание по одному выходу энкодера; направление вращения - анализ состояния другого выхода. Получалось - примерно тоже, что и у Вас: то изменение значения на 1 за щелчок, то на 2... Пришёл к следующему заключению: выход энкодера, заведённый на прерывание - он тоже, конечно, "дребезжит", поэтому после изменения этого выхода -> взводится соответствующий флаг -> происходит прерывание -> флаг сбрасывается, но "дребезг" приводит к повторной установке флага во время обрабоки прерывания -> после выхода из прерывания имеем ещё одно прерывание на тот же щелчок энкодера. Иногда повторного прерывания не происходит, тогда - приращение на 1. В результате - переделал обработку энкодера - получил, что-то аналогичное обработке от Леонида Ивановича. Рекомендую и Вам сделать что-то такое же. но на время обработки я прерьівание то запрещаю... жду... странно. собсно ничего не мешает устроить обработчик в основном цикле
|
|
|
|
|
Jun 17 2008, 15:09
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 25-07-06
Пользователь №: 19 070

|
Цитата(wired @ Jun 17 2008, 21:01)  но на время обработки я прерьівание то запрещаю... жду... странно. собсно ничего не мешает устроить обработчик в основном цикле Добавь в конце обработчика прерывания строчку типа: Код PCIFR|=(1<<PCIF1); //сбрасываем флаг прерывания, если оно произошло во время обработки. Это такая защита от дребезга. А в обработчике прерывания запрещать прерывания не надо, они и так запрещены, и разрешаются после выхода из прерывания автоматически (компилятором), хотя про Codevision я не уверен.
|
|
|
|
|
Jun 17 2008, 15:12
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 25-07-06
Пользователь №: 19 070

|
Цитата(676038 @ Jun 17 2008, 21:09)  Добавь в конце обработчика прерывания строчку типа: Код PCIFR|=(1<<PCIF1); //сбрасываем флаг прерывания, если оно произошло во время обработки. Это такая защита от дребезга. А в обработчике прерывания запрещать прерывания не надо, они и так запрещены, и разрешаются после выхода из прерывания автоматически (компилятором), хотя про Codevision я не уверен. Может стоит добавить, сейчас обрабатываю энкодер так: Код //PCINT8-14 interrupt implementation #pragma vector=PCINT1_vect __interrupt void handler_pcint1(void) { static unsigned char flag=0xFF; //переменная для хранения предыдущего значения порта
unsigned char tmp; //переменная для хранения текущего значения порта
tmp = PINC & 0x0F; //запоминаем состояние порта
switch (tmp ^ flag) //сравниваем с предыдущим и выполняем действие если изменился соответствующий бит { case 0x01: if (((tmp >> 1) & 0x01) == (tmp & 0x01)) Execute(0x11); //если поворот первого энкодера вправо else Execute(0x10); //иначе это поворот первого энкодера влево break;//выход case 0x02: if (((tmp << 1) & 0x02) == (tmp & 0x02)) Execute(0x10); //если поворот первого энкодера влево else Execute(0x11); //иначе поворот первого энкодера вправо break;//выход case 0x04: if (((tmp >> 1) & 0x04) == (tmp & 0x04)) Execute(0x21); //если поворот второго энкодера вправо else Execute(0x20); //иначе поворот второго энкодера вправо break;//выход // case 0x08: !!! второй энкодер обрбатываем при изменении только одной линии, уменьшая чувствительность вдвое... }
flag = tmp; //сохраняем значение для следующего опроса
PCIFR|=(1<<PCIF1); //сбрасываем флаг прерывания если оно произошло во время обработки. Это такая защита от дребезга.
}
|
|
|
|
|
Jun 17 2008, 15:48
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 25-07-06
Пользователь №: 19 070

|
В своем последнем варианте - по изменению состояния, используется PIN-Change Interrupt на все четыре пина, куда подключены два энкодера.
Просто надо проанализировать логику работы и решить для себя, какое событие считать информационным, а какое дребезгом. Из моего опыта - все что срабатывает в то время, пока идет обработка обработчика - это дребезг. Вот его и сбрасываем заканчивая обработчик. Конечно, в этом варианте есть завязка на время нахождения в обработчике прерывания (время подавления дребезга), но у меня это оказалось не критичным.
|
|
|
|
|
Jun 18 2008, 07:54
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 13-06-08
Из: KYIV
Пользователь №: 38 269

|
Цитата(Палыч @ Jun 17 2008, 18:09)  Чего их (прерывания) запрещать? Они при входе в процедуру прерывания и так - запрещены. Дело в том, что при прерывании сбрасывается флаг, который это прерывание порадил, но поскольку уровень сигнала некоторое время скачет ("дребезг"), то за время выполнения процедуры прерывания флаг взводится повторно! После того как будет произведен выход из прерывания - оно (прерывание) повторится. Как вариант - очистка флага перед выходом из прерывания. УПС...  вот про єто я не знал, что прерьівания во время входа в обработчик запрещеньі. а про флаг спасибо, буду сбрасьівать. Цитата(676038 @ Jun 17 2008, 18:12)  Может стоит добавить, сейчас обрабатываю энкодер так: Код if (((tmp >> 1) & 0x01) == (tmp & 0x01)) Execute(0x11); //если поворот первого энкодера я правильно понял? в Execute(0x11) тьі вьізьіваешь внешний обработчик?
|
|
|
|
|
Jun 18 2008, 09:41
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(676038 @ Jun 17 2008, 19:48)  Просто надо проанализировать логику работы и решить для себя, какое событие считать информационным, а какое дребезгом.
Из моего опыта - все что срабатывает в то время, пока идет обработка обработчика - это дребезг. Вот его и сбрасываем заканчивая обработчик. +100 первому высказыванию. О втором: странный критерий. Сколько времени длится прерывание, устанавливающее флаг? Будем задержки совать в прерывание? Если перейти к пункту 1  то станет понятно, что для энкодера информационное событие - это фронт одного сигнала, регистрирующий новое состояние другого. Всё. Хоть 100 прерываний на один дребезг (если конечно дребезги не пересекаются во времени - но это уже негодный энкодер). Любителям задержек для подавления дребезга. Подключите "резиновую" кнопку к осциллографу, понажимайте, посмотрите. Затянутые фронты, дребезг чуть ли не в секунду длиной - как здрасьте.
|
|
|
|
|
Jun 18 2008, 11:36
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 13-06-08
Из: KYIV
Пользователь №: 38 269

|
Цитата(Maik-vs @ Jun 18 2008, 12:41)  О втором: странный критерий. Сколько времени длится прерывание, устанавливающее флаг? Будем задержки совать в прерывание? Если перейти к пункту 1  то станет понятно, что для энкодера информационное событие - это фронт одного сигнала, регистрирующий новое состояние другого. Всё. Хоть 100 прерываний на один дребезг (если конечно дребезги не пересекаются во времени - но это уже негодный энкодер). какое новое состояние другого если вращение идет в одну сторону? если прерьівание по изменению первого то второй свое значение не меняет, иначе - никакого нового состояния, кроме как вращения в противоположную сторону. или анализировать по двум прерьіваниям...? тогда без ввода задержек может и рполучится... НО внешних прерьіваний всего 2 а мне еще хочется пульт прикошачить, ему тоже кстати надо внешнее прерьівание
Сообщение отредактировал wired - Jun 18 2008, 11:50
|
|
|
|
|
Jun 18 2008, 12:47
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(676038 @ Jun 17 2008, 18:48)  Просто надо проанализировать логику работы и решить для себя, какое событие считать информационным, а какое дребезгом. Итак, как можно построить обработчик энкодера? 1. Можно повесить один из выходов энкодера на прерывание (например, по фронту); второй выход - для определения направления. Каждое прерывание - приращение (или декримент, в зависимости от направления) значения. Недостаток: тяжело бороться с дребезгом (причем, при этом методе нужно бороться с дребезгом того выхода энкодера, который заведен на прерывание). Сброс флага прерывания в конце процедуры обработки прерывания может и не помочь (зависит от длительности дребезга и от времени работы процедуры обработки прерывания). Достоинства: простота обработчика. 2. Можно вспомнить, что за один щелчок энкодера (шаг) состояние его выходов меняется четыре раза (00, 01, 11, 10 и т.д. - "микрошаги"). Второй вариант обработчика энкодера. Некая процедура запускается периодически: в бесконецном цикле main (если не жалко и цикл не загружен иными задачами), или по таймеру и проверяет состояние выходов энкодера. Максимальный период следует выбирать из максимальной скорости вращения энкодера. По состоянию выходов энкодера на предыдущем шаге и текущему состоянию выходов определяется микрошаг поворота энкодера (с учетом направления). "Микрошаги" суммируются и при значении числа "микрошагов" =4 инкрементируется значение регулируемой величины, при числе "микрошагов" =-4 - величина уменьшается на единицу; и сумма "микрошагов" сбрасывается в ноль. Недостатки: 1) некая грамозкоскть обработчика, 2) возможно, жалко отдать под обработчик таймер. Достоинства: нет нужды принимать специальные меры по борьбе с дребезгом, посколько дребезг приводит к колебанию числа "микрошагов" на единицу и повлиять на значение регулируемой величины не может. P.S. Кто-то предложит ещё (может, не один) метод?
|
|
|
|
|
Jun 18 2008, 14:25
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Посмотрел DS. В нём есть рисунок "Quadrature Output Table", в котором фиксированное положение ротора прихотится на серидину "микрошага". Конечно, этот рисунок производителя ни к чему не обязывает, но, ИМХО, при производстве энкодеров стараются выдержать нечто близкое... Фиксация положения - вроде, давольно чёткая. Недавно выпускали серию приборов с энкодерами. ОТК их придирчиво все проверяли, особенно как работает энкодер, потому, что в пилотном экземпляре были выявлены глюки с энкодером (его обработка производилась по фронту одного из выходов и очень часто бывало изменение регулируемой величины на 2 за шаг). Нареканий не было. Может быть, потому, что - энкодеры новые, ещё не обтёрлись...
|
|
|
|
|
Jun 18 2008, 14:33
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(wired @ Jun 18 2008, 15:36)  какое новое состояние другого если вращение идет в одну сторону? если прерьівание по изменению первого то второй свое значение не меняет, иначе - никакого нового состояния, кроме как вращения в противоположную сторону.
или анализировать по двум прерьіваниям...? тогда без ввода задержек может и рполучится... НО внешних прерьіваний всего 2 а мне еще хочется пульт прикошачить, ему тоже кстати надо внешнее прерьівание Да, получается, что нужно 2 прерывания. Лучше периодически опрашивать сигналы, причём можно не через равные интервалы, лишь бы достаточно часто. При вращении в одну сторону получается последовательность 0-2-3-1-0-2-3-1... в другую - 0-1-3-2-0-1-3-2... Принятые сигналы сдвигаем в регистр. Получается, что в регистре хранится 4 последних состояния энкодера. Отбрасывая старые 2 бита и сравнивая его с константой, получаем ответ - был ли шаг и в какую сторону. Это, в общем, реализация способа 2 Палыча. PS А, я уже писал об этом. (#3 и #4) Анализировать надо таки 3 последних состояния, особенно если опрос. Потому что частота дребезга непредсказуема, пропустить переход в последовательности 2-3-2-3-2-3 вполне вероятно, и вот оно - двойное срабатывание на один "зуб".
Сообщение отредактировал Maik-vs - Jun 18 2008, 14:45
|
|
|
|
|
Jun 18 2008, 15:01
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 13-06-08
Из: KYIV
Пользователь №: 38 269

|
Цитата(Maik-vs @ Jun 18 2008, 17:33)  Да, получается, что нужно 2 прерывания. Лучше периодически опрашивать сигналы, причём можно не через равные интервалы, лишь бы достаточно часто. При вращении в одну сторону получается последовательность 0-2-3-1-0-2-3-1... в другую - 0-1-3-2-0-1-3-2... Принятые сигналы сдвигаем в регистр. Получается, что в регистре хранится 4 последних состояния энкодера. Отбрасывая старые 2 бита и сравнивая его с константой, получаем ответ - был ли шаг и в какую сторону. Это, в общем, реализация способа 2 Палыча. PS А, я уже писал об этом. (#3 и #4) Анализировать надо таки 3 последних состояния, особенно если опрос. Потому что частота дребезга непредсказуема, пропустить переход в последовательности 2-3-2-3-2-3 вполне вероятно, и вот оно - двойное срабатывание на один "зуб". ОК.. я пока новичок. и прерьівания обрабатьівать както нагляднее, пройдусь по єтим граблям  потом буду разбираться с регистром... может примерчик ? а....
|
|
|
|
|
Jun 18 2008, 15:14
|
Гуру
     
Группа: Свой
Сообщений: 2 318
Регистрация: 13-02-05
Из: Липецкая область
Пользователь №: 2 613

|
Цитата(Палыч @ Jun 18 2008, 18:25)  Посмотрел DS. В нём есть рисунок "Quadrature Output Table", в котором фиксированное положение ротора прихотится на серидину "микрошага". Конечно, этот рисунок производителя ни к чему не обязывает, но, ИМХО, при производстве энкодеров стараются выдержать нечто близкое... Фиксация положения - вроде, давольно чёткая. Недавно Да, в фиксированном положении оба контакта должны быть разомкнутыми. Фиксация положения обеспечивается пружинным кольцом с выступом. Кольцо хлипкое. В общем, мне больше нравятся на 12 положений.
|
|
|
|
|
Jun 20 2008, 20:37
|

Частый гость
 
Группа: Участник
Сообщений: 88
Регистрация: 14-03-06
Из: Житомир (UA)
Пользователь №: 15 228

|
Цитата(wired @ Jun 18 2008, 14:36)  ...
или анализировать по двум прерьіваниям...? тогда без ввода задержек может и рполучится... НО внешних прерьіваний всего 2 а мне еще хочется пульт прикошачить, ему тоже кстати надо внешнее прерьівание Лично я когда то сделал так (потому как второе прерывание тоже надо было для других целей): Внешнее прерывание по фазе A выставил на срабатывание по любому событию, фазу B на любой вход. И сам обработчик: Код // External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { if ( FASE_A ^ FASE_B)
{ if (FASE_A){ if (FASE_B) current_counter++; else current_counter--; } } else { if (!FASE_A){ if (!FASE_B) current_counter++; else current_counter--; } } } Работает замечательно до сих пор.
|
|
|
|
|
Jun 23 2008, 06:39
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 13-06-08
Из: KYIV
Пользователь №: 38 269

|
Цитата(Maik-vs @ Jun 18 2008, 17:33)  Да, получается, что нужно 2 прерывания. Лучше периодически опрашивать сигналы, причём можно не через равные интервалы, лишь бы достаточно часто. При вращении в одну сторону получается последовательность 0-2-3-1-0-2-3-1... в другую - 0-1-3-2-0-1-3-2... Принятые сигналы сдвигаем в регистр. Получается, что в регистре хранится 4 последних состояния энкодера. Отбрасывая старые 2 бита и сравнивая его с константой, получаем ответ - был ли шаг и в какую сторону. Это, в общем, реализация способа 2 Палыча. PS А, я уже писал об этом. (#3 и #4) Анализировать надо таки 3 последних состояния, особенно если опрос. Потому что частота дребезга непредсказуема, пропустить переход в последовательности 2-3-2-3-2-3 вполне вероятно, и вот оно - двойное срабатывание на один "зуб". я правильно понял: по каждому изменению заполняем некую переменную, состояниями входов, while... { reg = (reg<<1)+A reg = (reg<<1)+B } соответственно заполняется влево 013 00000111 132 00011110 320 00111000 201 00100001 вправо 023 00001011 231 00101101 310 00110100 102 00010010 отбросив старшие 5 бит reg = (reg & 0x07); далее сравниваю влево reg = 1 001 reg = 7 111 reg = 6 110 reg = 0 000 вправо reg = 2 010 reg = 3 011 reg = 5 101 reg = 4 100
|
|
|
|
|
Jun 24 2008, 18:08
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 17-06-08
Из: Томск
Пользователь №: 38 346

|
Читать всю тему влом, поэтому просто приведу свой код обработки энкодера. Работает с энкодером PEC16, частоту сканирования менял в пределах 100uS....1mS, все работает очень четко. Внешний обработчик события поворот в вправо или влево просто проверяет содержимое байта в ОЗУ-Encoder_Status, вообщем из кода вроде должно быть все ясно. Код ;=============================================================================== ============================================== ; Подпрограмма обработки энкодера ;=============================================================================== ============================================== Encoder: lds temp,(Encoder_Status) ; Прочитать из памяти состояние кольцевого буфера энкодера cpi temp,0b00110100 ; Если кольцевой буфер содержит код состояния энкодера "против часовой" breq Encoder_End ; то перейти на выход cpi temp,0b00011100 ; Если кольцевой буфер содержит код состояния энкодера "по часовой" breq Encoder_End ; то перейти на выход clr temp ; Обнулить все разряды РОН out DDRB,temp ; Сделать все выводы порта В входами и записать конфигурацю nop ; подождать пока установиться напряжение на выводах порта В nop ; подождать пока установиться напряжение на выводах порта В nop ; подождать пока установиться напряжение на выводах порта В nop ; подождать пока установиться напряжение на выводах порта В nop ; подождать пока установиться напряжение на выводах порта В lds temp3,(Encoder_rep_state); Прочитать из памяти число повторов состояние контактов энкодера in temp,PINB ; Сканировать состояние энкодера com temp ; Получить обратный код замкнутых контактов andi temp,0b00010100 ; Выделить разряды к которым подключен энкодер через маску контактов энкодера lsr temp lsr temp inc temp ; Сдвинуть первый бит влево если он равен "1" lsr temp ; Сдвинуть байт влево, приведя код состояния энкодера к нормальному виду lds temp2,(Encoder_prev) ; Прочитать из памяти состояние кольцевого буфера энкодера cpse temp,temp2 ; Сравнить состояние контактов энкодера с предыдущим, если они неравны, clr temp3 ; то очистить счетчик повторов sts (Encoder_prev),temp ; Сохранить текущее состояние контактов энкодера в "предыдущем"
cpi temp3,2 ; Сравнить счетчик числа повторов с контстантой (=3 для частоты сканирования 1кГц и 15 для 10кГц)
breq Encoder_1 ; Перейти если равно, в обновлению состояния кольцевого буфера brsh Encoder_End ; Перейти если больше, на выход inc temp3 ; Увеличить счетчие числа повторов sts (Encoder_rep_state),temp3; Сохранить в памяти число повторов состояние контактов энкодера clr temp ; вывести на все выводы порта В нули out PORTB,temp ; запись нули в РВВ порта В com temp ; Установить все разряды РОН в единицу, out DDRB,temp ; Сделать все выводы порта В выходами и записать конфигурацию ret ; Выйти из подпрограммы обработки энкодера Encoder_1: lds temp,(Encoder_Status) ; Прочитать из памяти состояние кольцевого буфера энкодера lsl temp ; Сдвинуть кольцевой буфер состояния энкодера на шаг в лево lsl temp ; Сдвинуть кольцевой буфер состояния энкодера на шаг в лево add temp,temp2 ; Добавить новое состояние контактов энкодера в кольцевой буфер inc temp3 ; Увеличить счетчие числа повторов sts (Encoder_Status),temp ; Сохранить в памяти состояние кольцевого буфера энкодера Encoder_End: sts (Encoder_rep_state),temp3; Сохранить в памяти число повторов состояние контактов энкодера clr temp ; вывести на все выводы порта В нули out PORTB,temp ; запись нули в РВВ порта В com temp ; Установить все разряды РОН в единицу, out DDRB,temp ; Сделать все выводы порта В выходами и записать конфигурацию ret Цитата(haker_fox @ Jun 24 2008, 06:33)  P.S. Есть ли в природе дешевые энкодеры с небольшим количеством импульсов на оборот, но не дорогие? PEC16-4020F-S0012 - имеют 12 отсчетов на 1 оборот
|
|
|
|
|
Jun 25 2008, 01:54
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 17-06-08
Из: Томск
Пользователь №: 38 346

|
Цитата Только вряд ли он выдержит вращения на высокой скорости. В ДШ пишут что 100 RPM (Operating), наверно связанно с тем что контакты будут подвисать при большей частоте вращения. Можно посоветовать порыться на сайте Chip&Dip там может чего и есть.
|
|
|
|
|
Jun 26 2008, 12:46
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(wired @ Jun 23 2008, 10:39)  я правильно понял: по каждому изменению заполняем некую переменную, состояниями входов, while... { reg = (reg<<1)+A reg = (reg<<1)+B }
соответственно заполняется влево 013 00000111 132 00011110 320 00111000 201 00100001 вправо 023 00001011 231 00101101 310 00110100 102 00010010
отбросив старшие 5 бит reg = (reg & 0x07);
далее сравниваю влево reg = 1 001 reg = 7 111 reg = 6 110 reg = 0 000
вправо reg = 2 010 reg = 3 011 reg = 5 101 reg = 4 100 нет. Периодически принимаем состояние енкодера, сдвигаем в регистр. Если входы сидят, допустим, на битах 6 и 7 порта А, то: encoder: in tmp,pina rol tmp lsr reg rol tmp lsl reg ;reg содержит 4 последних состояния: aabbccdd, aa самое старое, dd самое новое andi reg,$3f ; убрали самое старое cpi reg,$2d ; bbccdd = 10 11 01? влево 231 breq toleft cpi reg,$1e ; bbccdd = 01 11 10? вправо 132 breq toright ret Почему 3 состояния. Было так. Колесо с оптическим датчиком (с гистерезисом, 2 канала, как на мыше) стоит на тросе. Трос стоит, счётчик бежит вперёд. Оказывается, трос мелко дрожит, и один сигнал (иногда!) быстренько меняется тоже. Какие к нему претензии? Построил граф состояний - понял.
Сообщение отредактировал Maik-vs - Jun 26 2008, 12:47
|
|
|
|
|
Jun 26 2008, 14:48
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 13-06-08
Из: KYIV
Пользователь №: 38 269

|
Цитата(Maik-vs @ Jun 26 2008, 15:46)  нет. Периодически принимаем состояние енкодера, сдвигаем в регистр. Если входы сидят, допустим, на битах 6 и 7 порта А, то:
encoder: in tmp,pina rol tmp lsr reg rol tmp lsl reg ;reg содержит 4 последних состояния: aabbccdd, aa самое старое, dd самое новое andi reg,$3f ; убрали самое старое cpi reg,$2d ; bbccdd = 10 11 01? влево 231 breq toleft cpi reg,$1e ; bbccdd = 01 11 10? вправо 132 breq toright ret Почему 3 состояния. Было так. Колесо с оптическим датчиком (с гистерезисом, 2 канала, как на мыше) стоит на тросе. Трос стоит, счётчик бежит вперёд. Оказывается, трос мелко дрожит, и один сигнал (иногда!) быстренько меняется тоже. Какие к нему претензии? Построил граф состояний - понял. все, "догнал"... в моем варианте отрабатьіваются 4 фазьі т.е. за 1 щелчок в идеале получаю 4 отчсета, что в принципе с практикой согласовьівается вьізьівается из основного цикла.. Код void rd_encoder(void) {int temp = 0; pinstate = (ENC_PIN & 0x06); // pind.1 pind.2 if (state != pinstate) //состояние изменилось pind.1 pind.2 { state = pinstate; //обновили state /* заполняю буфер */ encoder = encoder<<1; encoder = encoder+ENC_A; encoder = encoder<<1; encoder = encoder+ENC_B;
switch((encoder & 0x07)) //смотрим последние 3 бита { case 1:temp = 1; break; case 7:temp = 1; break; case 6:temp = 1; break; case 0:temp = 1; break; case 2:temp = -1; break; case 3:temp = -1; break; case 5:temp = -1; break; case 4:temp = -1; break; default: temp = 0; } твой вариант будет приблизительно таким буквально: Код void rd_encoder(void) {int temp = 0; pinstate = (ENC_PIN & 0x06); // pind.1 pind.2 if (state != pinstate) //состояние изменилось pind.1 pind.2 { state = pinstate; //обновили state /* заполняю буфер */ encoder = encoder<<1; encoder = encoder+ENC_A; encoder = encoder<<1; encoder = encoder+ENC_B;
switch((encoder & 0x3F)) //смотрим последние 6 бит { case 0x2D:temp = 1; break; case 0x1E:temp = -1; break; default: temp = 0; }
Сообщение отредактировал wired - Jun 26 2008, 14:55
|
|
|
|
|
Nov 12 2008, 09:51
|
Участник

Группа: Участник
Сообщений: 17
Регистрация: 24-10-08
Пользователь №: 41 157

|
мой вариант. энкодер опрашиваю в прерывании таймера. Код #define PORT_Enc PORTA #define PIN_Enc PINA #define DDR_Enc DDRA #define Pin1_Enc 1 #define Pin2_Enc 2
#define _0b00000011 3 #define _0b00111111 63 #define _0b00010010 18 #define _0b00100001 33
#define SBI(port, bit) port|= (1<<bit) #define CBI(port, bit) port&= ~(1<<bit)
//подпрограмма инициализации void Init_Encoder(void) { CBI(DDR_Enc, Pin1_Enc); //вход CBI(DDR_Enc, Pin2_Enc); CBI(PORT_Enc, Pin1_Enc);//вкл подтягивающий резистор CBI(PORT_Enc, Pin2_Enc); }
//подпрограмма опроса энкодера /*считывает значения выводов энкодера, если на обоих выводах единицы, то возвращает 0. если текущее состояние равно предыдущему, то возвращает 0. если состояние изменилось, то сдвигает регистр state_enc влево на 2 разряда и записывает 2 разряда текущего состояния. Проверяет получившуюся последовательность. если последовательность соответствует вращению влево - возвращает (-1), вправо - возвращает (1) */ unsigned char Read_Encoder(void) { unsigned char tmp,tmp2; static unsigned char state_enc; //хранит последовательность состояний энкодера tmp=0; if ((PIN_Enc&(1<<Pin1_Enc))!=0) {SBI(tmp,0);} else {CBI(tmp,0);} if ((PIN_Enc&(1<<Pin2_Enc))!=0) {SBI(tmp,1);} else {CBI(tmp,1);}
if (tmp==_0b00000011) {return 0;}
tmp2=(state_enc & _0b00000011); if (tmp==tmp2) {return 0;}
tmp2=state_enc<<2; state_enc=tmp2 | tmp;
tmp2=tmp2 & _0b00111111; if (tmp2==_0b00100001) {return 0x01;} if (tmp2==_0b00010010) {return 0xff;}
return 0; }
|
|
|
|
|
Nov 13 2008, 16:41
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Ух ты... А тема ещй жива... Попробую предложиьть изящный (с моей точки зрения) способ реализации этого алгоритма. Используется с оптическими валкодерами, проблемы с подавлением дребезга механических датчиков в данном месте решал бы только с помощью RC-цепочки и триггера Шмидта. Начальное значение old_val - считанное значение из функции, дающей состояние битов прерываний. Входы прерываний программируются на срабатывание по любому перепаду. Ничего (кроме максимальной скорости вращения) не изменится, если функцию вызывать и из таймерного прерывания. Код static uint8_t old_val;
void spool_encinterrupt(void) { uint8_t new_val = hardware_get_encoder_bits();
// dimensions are: // old_bits new_bits const static signed char v [4][4] = { { +0, /* 00 -> 00 stopped */ -1, /* 00 -> 01 rotate left */ +1, /* 00 -> 10 rotate right */ +0, /* 00 -> 11 invalid combination */ }, { +1, /* 01 -> 00 rotate right */ +0, /* 01 -> 01 stopped */ +0, /* 01 -> 10 invalid combination */ -1, /* 01 -> 11 rotate left */ }, { -1, /* 10 -> 00 rotate left */ +0, /* 10 -> 01 invalid combination */ +0, /* 10 -> 10 stopped */ +1, /* 10 -> 11 rotate right */ }, { +0, /* 11 -> 00 invalid combination */ +1, /* 11 -> 01 rotate right */ -1, /* 11 -> 10 rotate left */ +0, /* 11 -> 11 stopped */ }, };
rotate += v [old_val][new_val];
old_val = new_val; } Код #if defined (CPUSTYLE_ATMEGA128)
ISR(INT4_vect) { spool_encinterrupt(); }
ISR(INT5_vect) { spool_encinterrupt(); }
#elif defined (CPUSTYLE_ATMEGA32)
ISR(INT0_vect) { spool_encinterrupt(); }
ISR(INT1_vect) { spool_encinterrupt(); } #else
#error Undefined processor
#endif Код /* получение накопленного значения прерываний от валкодера. накопитель сбрасывается */ uint_least16_t getRotateHiRes( uint_least32_t * jumpsize, uint_least16_t granulation) { #if ENCODER_HIRES #define BIGJUMPSIZE (10000UL / 4) static const uint8_t velotable [] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }; #else #define BIGJUMPSIZE (10000UL) static const uint8_t velotable [] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }; #endif
div_t d, h; uint8_t ticks; uint16_t nrotate, hrotate; cli(); if (tickcount != 0) { ticks = tickcount; tickcount = 0; hrotate = rotate; rotate = 0; } else { ticks = 1; hrotate = 0; } sei();
/* Уменьшение разрешения валкодера в зависимости от установок в меню */ h = div(hrotate, hiresdiv);
cli(); rotate += h.rem; sei();
nrotate = h.quot;
d = div(nrotate + stepcount, ticks); stepcount += d.rem; /* остаток пригодится в следующий раз */
if (d.quot < 0) d.quot = - d.quot; if (d.quot < (sizeof velotable / sizeof velotable [0])) * jumpsize = (uint32_t) granulation * velotable [d.quot]; else if (noaccelerate != 0) * jumpsize = (uint32_t) granulation * velotable [(sizeof velotable / sizeof velotable [0]) - 1]; else * jumpsize = BIGJUMPSIZE;
return nrotate; } Код /* получение "редуцированного" количества прерываний от валкодера. * То что осталось после деления на scale, остается в накопителе */
int getRotateLoRes(void) { int nrotate; div_t d; cli(); nrotate = rotate; rotate = 0; sei();
d = div(nrotate, ROTATE_LORES_DIV);
cli(); rotate += d.rem; sei();
return d.quot; }
void encoder_initialize(void) { rotate = 0; stepcount = 0; tickcount = TICKCOUNT_MAX;
hardware_encoder_initialize();
#if ENCODER_MULTICLICK old_val = hardware_get_encoder_bits(); #endif // ENCODER_MULTICLICK } Проект лежит здесь - http://forum.cqham.ru/viewtopic.php?t=15274 и в аттаче.
Сообщение отредактировал Genadi Zawidowski - Nov 13 2008, 16:46
|
|
|
|
|
Nov 15 2008, 12:41
|
Участник

Группа: Свой
Сообщений: 37
Регистрация: 13-05-07
Из: Minsk, Belarus
Пользователь №: 27 694

|
Добавлю немного в копилку. Знаю, не самый лучший вариант, писалось на скорую руку, но работает. Код void check_encoder(void) { static uint8_t state=0; static uint8_t prevstate=0; static uint8_t prevcount=0; static uint8_t laststate=0; register uint8_t temp; temp=(PINA&0x60)<<1;
if (temp==prevstate) { if (prevcount<4) { prevcount++; } if (prevcount!=3) { return; } } else { prevcount = 0; prevstate = temp; return; }
if (laststate==prevstate) return;
laststate=prevstate;
switch (prevstate&0xc0) { case 0xc0: { if (state==4) { if (value>VALUEMIN) { value--; } } if (state==5) { if (value<VALUEMAX) { value++; } } state = 1; } break; case 0x00: { if ((state==1) || (state==3)) state++; } break; case 0x40: { if (state==1) state=3; if (state==2) state=5; } break; } } -- WBR, Andrew
|
|
|
|
|
Nov 15 2008, 14:14
|

Местный
  
Группа: Свой
Сообщений: 253
Регистрация: 28-12-07
Из: Украина г. Первомайск
Пользователь №: 33 716

|
Приложу свою первую подпрограмку для работы с Энкодером типа PEC-16 :
.def tmp = r16 .equ encod = PB2 .equ enc_2 = PB1
.org INT2addr // прерывание по внешнему сигналу INT2 для энкодера громкости rjmp Encoder // обработчик прерывания от энкодера
.CSEG // сегмент кода //Векторы прерываний: .org 0 // по адресу 0 вектор сброса rjmp RESET // перейти на метку ресет
RESET: in temp,MCUCR ori temp,(1 << ISC10) ;по спаду out MCUCR,temp in temp,GIMSK ori temp,(1 << INT2) ;бит INT2 в GIMSK равен 1 out GIMSK,temp ;разрешаем внешнее прерывание INT2 sei
// тут пишем всякую инициализацию //
// Подпрограмма Encoder: sbi PORTD,7 // контроль на PD7 внешнего прерывания push tmp // сохранение темп in tmp,SREG // читаем статус регистр push tmp // сохраняем его sbis pinb,encod // проверяем наличие прерывания rcall encoder_read // читаем энкодер pop tmp // извлекаем статус регистр out SREG,tmp // восст. SREG pop tmp // восст. temp cbi PORTD,7 // гасим светодиод контроля reti // выходим и разрешаем прерывания
Encoder_read: // чтение энкодера sbis pinb,1 // если установлен бит 1 в порте то пропуск след ком rcall plus // вызываем плюс sbic pinb,1 // если очищен бит 1 в порте то пропуск след ком rcall minus // вызываем минус reti // выход из прерывания
minus: // rcall lcd_sub // reti //
plus: // rcall lcd_add // reti //
|
|
|
|
|
Nov 21 2008, 06:43
|
Участник

Группа: Участник
Сообщений: 17
Регистрация: 24-10-08
Пользователь №: 41 157

|
оооо... заметил, что мой код можно сократить в этом месте Код tmp=0; if ((PIN_Enc&(1<<Pin1_Enc))!=0) {SBI(tmp,0);} else {CBI(tmp,0);} if ((PIN_Enc&(1<<Pin2_Enc))!=0) {SBI(tmp,1);} else {CBI(tmp,1);} и будет то же самое Код tmp=0; if ((PIN_Enc&(1<<Pin1_Enc))!=0) {SBI(tmp,0);} if ((PIN_Enc&(1<<Pin2_Enc))!=0) {SBI(tmp,1);}
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|