Il metodo di base per la lettura di un encoder è leggere il livello di uno dei due segnali nell'istante in cui l'altro cambia stato. Hardware si fa con un flip flop di tipo D.
Io solitamente faccio così:
void encoder()
{
uint8_t S; // Lettura dei due valori dell'encoder.
uint8_t So;// Lettura precedente dell'encoder.
uint8_t X; // Usato per evitare letture multiple.
E=0;
// PD 76543210
// S=3-(PIND>>3)&B00000011; Serviva per l'encoder su PD3 e PD4.
// S=3-PIND&B00000011; Gli I/O 0 e 1 sono PD0 e PD1, perciò non devo scorrere a destra.
S=3-((PIND>>4) & B00000011); // Gli I/O 4 e 5 sono PD4 e PD5, perciò devo scorrere a destra di 4 bit.
// Il valore binario di S rappresenta A e B. Il centrale dell'encoder è a massa, quindi faccio complemento a 3 (11).
S^=S>>1; // Faccio XOR (^) fra S (gray) e il suo bit 1, facendolo scorrere a Dx: AB XOR A,
// ottenendo un binario che per ogni scatto fa 0-1-2-3-0 oppure 0-3-2-1-0.
if(S!=So && S==0) X=0;
if(X==0)
{
if(So==1 && S==2)
{E=1; X=1;}
if(So==3 && S==2)
{E=-1; X=1;}
if(S==0)
{E=0; X=0;}
So=S;
}
} // FINE Encoder().
Si può fare così, senza usare gli interrupt, se la funzione viene chiamata in continuazione. Solitamente la uso in un ciclo molto stretto solo di impostazioni e visualizzazione, dal quale poi torno al funzionamento normale del dispositivo. Ogni volta che viene chiamata, la funzione aggiorna il valore di E, che sarà 0 se l'encoder non è stato mosso, -1 se è stato ruotato in seno antiorario e 1 se è stato ruotato in senso orario. Se il risultato è opposto, bisogna scambiare i collegamenti all'encoder.
Studialo bene e impara, non usarlo come se fosse una libreria a scatola chiusa!