Написал давно, никак руки не дойдут проверить.
//////////
// Энкодер
#define ENCODER_PORT PORTA
#define ENCODER_DDR DDRA
#define ENCODER_PIN PINA
//////
#define MAXIMUM ( 10000 )
#define MINIMUM ( 0 )
//////
// Переменная Move - перемещение. Знаковая. Допускаются
// отрицательные величины.Иначе - "unsigned int Move"
signed int Move;
// Enc - буфер FIFO для последних 4-х двухбитовых состояний фаз
unsigned char Enc;
// Переменная old_state для подавления дребезга
unsigned char old_state;
// Функция Encoder здесь выполнена как вызываемая
// программно функция. Возвращает unsigned char флаг об
// обнаружении перемещения.
unsigned char Encoder( void )
{
// Phase 1 (pin A.1) ____/^^^^^^^^\________/^^^^^^^^\______
// Phase 0 (pin A.0) ________/^^^^^^^^\________/^^^^^^^^\__
//
// При ИНкременте история состояний: 10 11 01 00 - пришло 10!
// При ДЕкременте история состояний: 00 01 11 10 - пришло 00!
// Т.о., инкремент стробируется положительным фронтом Phase 1,
// а декремент - отрицательным. Получается гистерезис.
register unsigned char state;
// Каждый раз инициализовать порт энкодера (для параноиков).
// ENCODER_DDR &= 0xfc;
//////// ENCODER_PORT |= 0x02; // pull up
//////// _NOP();
//////// _NOP();
state = ENCODER_PIN;
state &= 0x03; // Убрать лишние биты слева
if( state != old_state ) // Подтверждение состояния.
{
// Изменение или дребезг? Разобраться при следующем проходе.
// А пока запомним это новое состояние - и на выход.
old_state = state;
}/*if*/
else
{
// Фазы стоят устойчиво.
if( state != (Enc & 0x03) )
{
// Это новое устойчивое состояние фаз!
Enc <<= 2; // Вталкивание справа нового состояния в Enc
Enc |= state; //Enc-буфер FIFO для 4 последних состояний
// Какую "историю" из четырех последних фаз имеем?
if( Enc == 0x78 ) // binary( 01 11 10 00 )
{
// Есть перемещение "-"
////// Enc &= 0x03; // "Историю" фаз можно начать заново (?)
if( Move > MINIMUM )
Move--;
else
Move = MINIMUM; // Ограничение количества перемещений.
return (1); // Было перемещение!
}/*if*/
if( Enc == 0xd2 ) // binary( 11 01 00 10 )
{
// Есть перемещение "+"
////// Enc &= 0x03; // "Историю" фаз можно начать заново (?)
if( Move < MAXIMUM )
Move++;
else
Move = MAXIMUM; // Ограничение количества перемещений.
return (1); // Было перемещение!
}/*if*/
}/*if*/
}/*else*/
return (0); // Безрезультатный выход. Не выявлено перемещения.
}/*Encoder*/
/////
void main( void )
{
// Перемещение ставлю на середину диапазона.
Move = (unsigned int)((MAXIMUM + MINIMUM) / 2 );
Enc = 0;
old_state = 0;
ENCODER_DDR &= 0xfc;
ENCODER_PORT |= 0x02; // pull up
_NOP();
for(;;)
{
if( Encoder() ) printf(" %02x \n", Move );
}/*for*/
}