In my frustration with not getting any of the example code to reliably read my rotary encoder, I wrote my own. It works very well for me on my 20 detent 10 ppr encoder. I am using this encoder for a small user interface, so I don't need perfect accuracy at high speeds.
The problem with that code is that you run moving averages on the wrong variables.
You treat the A and B phases independently, which will lead to occasional errors since the
mark/space ratio of each phase is not the same thing as the phase or position state.
A more reliable approach is to read both pins simultaneously using PIND register, maintain the correct
phase/position information from that, then use moving averages (or any other de-bouncing technique) on the
phase/position variable.
One way to maintain the postion variable is this:
void setup ()
{
attachInterrupt (0, handle_enc, CHANGE) ;
attachInterrupt (1, handle_enc, CHANGE) ;
}
volatile long phase = 0 ;
volatile byte portd = (PIND & 0x0C) >> 2 ; // initial state of pins 2 and 3
void handle_enc ()
{
byte pd = (PIND & 0x0C) >> 2 ; // read pins 2 and 3 simultaneously (we know one has probably just changed)
pd ^= (pd >> 1) ; // 00 01 11 10 sequence converted to 00 01 10 11 sequence
byte sig = (pd - portd) & 3 ; // difference from last observation (crop to 2 bits)
if (sig == 1) // sig should be either 0, 1 or 3 (2 is an illegal state for a working encoder)
phase -- ;
else if (sig == 3)
phase ++ ;
portd = pd ; // remember this pins' state for next time
}
Then in your loop() function you can implement de-bouncing on the value of phase using your moving
average if you wish.