реклама на сайте
подробности

 
 
6 страниц V  « < 4 5 6  
Reply to this topicStart new topic
> MEGA+энкодер
tremor
сообщение Jun 25 2008, 01:54
Сообщение #76


Участник
*

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



Цитата
Только вряд ли он выдержит вращения на высокой скорости.


В ДШ пишут что 100 RPM (Operating), наверно связанно с тем что контакты будут подвисать при большей частоте вращения. Можно посоветовать порыться на сайте Chip&Dip там может чего и есть.
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 25 2008, 04:27
Сообщение #77


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



Цитата(tremor @ Jun 25 2008, 10:54) *
В ДШ пишут что 100 RPM (Operating), наверно связанно с тем что контакты будут подвисать при большей частоте вращения. Можно посоветовать порыться на сайте Chip&Dip там может чего и есть.

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


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Maik-vs
сообщение Jun 26 2008, 12:46
Сообщение #78


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
wired
сообщение Jun 26 2008, 14:48
Сообщение #79


Участник
*

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
sansnotfor
сообщение Nov 12 2008, 09:51
Сообщение #80


Участник
*

Группа: Участник
Сообщений: 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;
}
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Nov 13 2008, 16:41
Сообщение #81


Профессионал
*****

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
Andrew O. Shadou...
сообщение Nov 15 2008, 12:41
Сообщение #82


Участник
*

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
pavel-pervomaysk
сообщение Nov 15 2008, 14:14
Сообщение #83


Местный
***

Группа: Свой
Сообщений: 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 //
Go to the top of the page
 
+Quote Post
sansnotfor
сообщение Nov 21 2008, 06:43
Сообщение #84


Участник
*

Группа: Участник
Сообщений: 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);}
Go to the top of the page
 
+Quote Post

6 страниц V  « < 4 5 6
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 28th August 2025 - 09:39
Рейтинг@Mail.ru


Страница сгенерированна за 0.01479 секунд с 7
ELECTRONIX ©2004-2016