tremor 0 25 июня, 2008 Опубликовано 25 июня, 2008 · Жалоба Только вряд ли он выдержит вращения на высокой скорости. В ДШ пишут что 100 RPM (Operating), наверно связанно с тем что контакты будут подвисать при большей частоте вращения. Можно посоветовать порыться на сайте Chip&Dip там может чего и есть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 25 июня, 2008 Опубликовано 25 июня, 2008 · Жалоба В ДШ пишут что 100 RPM (Operating), наверно связанно с тем что контакты будут подвисать при большей частоте вращения. Можно посоветовать порыться на сайте Chip&Dip там может чего и есть. Есть-то есть, но как минмум 700 р за штуку. Хотелось бы дешевле. Но изделие если не разовое, то не высокотиражное - датчики из мышек пойдут. Лишь бы высокой вибрации не было в самодельных крепежных элементах, иначе могут быть помехи в измерениях мгновенной скорости и потеря пройденного пути. А в остальном полностью устраивают: мышек дохлых полно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maik-vs 0 26 июня, 2008 Опубликовано 26 июня, 2008 (изменено) · Жалоба я правильно понял: по каждому изменению заполняем некую переменную, состояниями входов, 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 канала, как на мыше) стоит на тросе. Трос стоит, счётчик бежит вперёд. Оказывается, трос мелко дрожит, и один сигнал (иногда!) быстренько меняется тоже. Какие к нему претензии? Построил граф состояний - понял. Изменено 26 июня, 2008 пользователем Maik-vs Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
wired 0 26 июня, 2008 Опубликовано 26 июня, 2008 (изменено) · Жалоба нет. Периодически принимаем состояние енкодера, сдвигаем в регистр. Если входы сидят, допустим, на битах 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; } Изменено 26 июня, 2008 пользователем wired Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sansnotfor 0 12 ноября, 2008 Опубликовано 12 ноября, 2008 · Жалоба мой вариант. энкодер опрашиваю в прерывании таймера. #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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 13 ноября, 2008 Опубликовано 13 ноября, 2008 (изменено) · Жалоба Ух ты... А тема ещй жива... Попробую предложиьть изящный (с моей точки зрения) способ реализации этого алгоритма. Используется с оптическими валкодерами, проблемы с подавлением дребезга механических датчиков в данном месте решал бы только с помощью 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 и в аттаче. Изменено 13 ноября, 2008 пользователем Genadi Zawidowski Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bugzilla 0 15 ноября, 2008 Опубликовано 15 ноября, 2008 · Жалоба Добавлю немного в копилку. Знаю, не самый лучший вариант, писалось на скорую руку, но работает. 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
pavel-pervomaysk 0 15 ноября, 2008 Опубликовано 15 ноября, 2008 · Жалоба Приложу свою первую подпрограмку для работы с Энкодером типа 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 // Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sansnotfor 0 21 ноября, 2008 Опубликовано 21 ноября, 2008 · Жалоба оооо... заметил, что мой код можно сократить в этом месте 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);} Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться