Scenario
I have 4 ACZ16 quadrature rotary encoders connected to GPIO Port D on an ATMega168P. I am only trying to extract rotation direction from them. Position is irrelevant, and it is guaranteed only one encoder will rotate at any given time. Debouncing is handled in hardware using the recommended debounce filter in the datasheet and there is no switch bounce visible on the scope.
Problem
Differentiating between the encoders is not a problem. Where I run into hurdles is extracting the direction. My first thought after some Googling was a pin change interrupt.
Resulting ISR:
ISR(PCINT2_vect)
{
unsigned static char int_count = 0;
unsigned char pins = PIND;
unsigned char send;
if(int_count == 0)
{
switch(pins)
{
case 0x7F: send = MIRROR_X_L; break;
case 0xBF: send = MIRROR_X_R; break;
case 0xDF: send = MIRROR_Y_D; break;
case 0xEF: send = MIRROR_Y_U; break;
case 0xF7: send = LASER_X_L; break;
case 0xFB: send = LASER_X_R; break;
case 0xFD: send = LASER_Y_D; break;
case 0xFE: send = LASER_Y_U; break;
default: send = NOTHING; break;
}
if(send != NOTHING)
{
sendSPI(send);
}
int_count++;
}
else
{
if(int_count == 3)
{
int_count = 0;
}
else
{
int_count++;
}
}
}
This detected rotation in the correct rotary encoder, but only one direction. A clockwise rotation is decoded correctly, a counterclockwise rotation is still decoded as a clockwise rotation.
After further Googling, I tried a polling approach, using similar code.
Resulting main loop:
while(1)
{
switch(PIND)
{
case 0x7F: send = MIRROR_X_L; break;
case 0xBF: send = MIRROR_X_R; break;
case 0xDF: send = MIRROR_Y_D; break;
case 0xEF: send = MIRROR_Y_U; break;
case 0xF7: send = LASER_X_L; break;
case 0xFB: send = LASER_X_R; break;
case 0xFD: send = LASER_Y_D; break;
case 0xFE: send = LASER_Y_U; break;
default: send = NOTHING; break;
}
if(send != NOTHING)
{
sendSPI(send);
_delay_ms(40);
}
}
I played with multiple delay values following my SPI transmission, thinking that would fix the issue (actual cycle time is about 20ms), but this approach exhibits identical behavior to the pin change interrupt example. A clockwise rotation is decoded correctly, a counterclockwise rotation is still decoded as a clockwise rotation.
Most methods I've found, such as look up tables do not scale well past one, maybe two rotary encoders. What is a better way to do with with multiple rotary encoders?