Ух ты... А тема ещй жива... Попробую предложиьть изящный (с моей точки зрения) способ реализации этого алгоритма. Используется с оптическими валкодерами, проблемы с подавлением дребезга механических датчиков в данном месте решал бы только с помощью 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 и в аттаче.