Encoder auslesen

Hallo,
ich bin gerade dabei mir ein LCD Menue mit Drehgeber zu basteln. Dazu habe ich mir angeschaut, was mir der Drehgeber für Impulse ausgibt. Bei meinem Teil sind die Anschlüsse A und B wenn der Drehgeber in der Raststellung steht immer High.
Von einer Rastung zur nächsten gibt es immer 4 Impulse auf A und B.
Die Impusle sehen folgendermaßen aus:

Links drehen: A B
1 0
0 0
0 1
1 1

Rechts drehen: A B
0 1
0 0
1 0
1 1
d.h. wenn ich links drehe habe ich am Anschluß A immer eine 9, wenn ich rechts drehe habe ich immer eine 12.
Daraus habe ich einen kleinen Sketch gebastelt, der relativ klein und übersichtlich ist.

/* Encoder auslesen
 * gemeinsamer Anschluß auf GND
 * Ardubu
 * 25.03.2014
*/
#define debug
#define ENCODER_A 2
#define ENCODER_B 3

boolean a=1;
boolean a_alt=1;
boolean b=1;
boolean b_alt=1;
byte n=0;
byte A=0;
int imp;
int imp_alt=1;

void setup() {
  #ifdef debug
  Serial.begin(9600);
  Serial.println(F("Setup"));
  #endif
  
  pinMode(ENCODER_A, INPUT_PULLUP);
  pinMode(ENCODER_B, INPUT_PULLUP);
 
}
void loop()
{
  a=digitalRead(ENCODER_A);
  delay(2);
  b=digitalRead(ENCODER_B);
  delay(2);
  
  if (a!=a_alt || b!=b_alt)
  {
    if(a)bitSet(A,n);
    n++;
    if (a&&b) n=0;
    if (A==12) imp++;
    if (A==9) imp--;
    a_alt=a; b_alt=b;
    if(a&&b)A=0;
    #ifdef debug
    if (imp_alt!=imp){
    Serial.println(imp);
    imp_alt=imp;}
    #endif
  }
}

Vielleicht kann einer von euch so was gebrauchen.
Gruß
Ardubu

Wie verhält sich der Encoder beim schnellen Rechts/Links drehen? Hatte eine ähnliche Lösung getestet, war aber nicht damit zufrieden, da er immer wieder mal nicht genau gezählt hat.
Das delay gefällt mir in der Lösung nicht.

#define XTAL		16E6				// 16 MHz
#define PHASE_A		(PIND & 1<<2)		// PD2 (+) --- SW -- PD2 --- 10k --- (-) 
#define PHASE_B		(PIND & 1<<3)		// PD3 (+) --- SW -- PD3 --- 10k --- (-)

volatile int8_t deltaEnc;				// Drehgeberbewegung zwischen zwei Auslesungen im Hauptprogramm

const int8_t table[16] PROGMEM = {		// Dekodertabelle
	0, 0, -1, 0, 0, 0, 0, 1,			// halbe Aufloesung
	1, 0, 0, 0, 0, -1, 0, 0
};

ISR(TIMER1_COMPA_vect)
{
	static int8_t last = 0;
	last = (last << 2) & 0x0F;
	if (PHASE_A) last |= 2;
	if (PHASE_B) last |= 1;
	deltaEnc += pgm_read_byte(&table[last]);
}

void encoderInit(void)
{
	TCCR1A = 1 << WGM10;
	TCCR1B = (1 << CS11) | (1 << CS10);
	OCR1A = XTAL / 128.0 * 1e-3 - 0.5;
	TIMSK1 |= 1 << OCIE1A;
}

int8_t encoderRead(void)
{
	int8_t val;
	cli();
	val = deltaEnc;
	deltaEnc = 0;
	sei();
	return val;
}

int main(void)
{
encoderInit();
sei();

	while (1)
	{
	int8_t value;	
	value += encoderRead();
	}
}

bei schnellem Drehen verschluckt er sich schon mal, aber da ich ihn für eine Menüsteuerung brauche, und je Menü max. 10 Menüpunkte habe, brauche ich nicht so schnell drehen. Die delays stören mich hier auch nicht, da das Encoder auslesen innerhalb der Menüfunktion läuft und der Dino in dem Moment bei mir keine zeitkritischen Aufgaben zu erledigen hat.

ardubu:
bei schnellem Drehen verschluckt er sich schon mal, aber da ich ihn für eine Menüsteuerung brauche, und je Menü max. 10 Menüpunkte habe, brauche ich nicht so schnell drehen. Die delays stören mich hier auch nicht, da das Encoder auslesen innerhalb der Menüfunktion läuft und der Dino in dem Moment bei mir keine zeitkritischen Aufgaben zu erledigen hat.

Das delay zwischen den beiden digitalRead-Anweisungen in der loop ist ein absolutes No-Go!
Die beiden Encoder-Pins müssen möglichst beide GLEICHZEITIG ausgelesen werden.
Also mit Arduino-Boardmitteln digitalRead direkt nach digitalRead.

Und das delay nach den beiden digitalRead-Anweisungen ist einfach nur überflüssig und macht die loop-Funktion langsamer als sie sein könnte (delay(2) schadet aber ansonsten auch nicht weiter).

@sschultewolter: Vernünftige Auswerteraten für stark prellende mechanische Drehgeber mit Timer-Interrupts liegen bei 500 bis 1000 Hz. Dein Timer-Interrupt scheint etwa hundertmal zu oft zu laufen (wenn ich den Code zur Timer-Initialisierung richtig interpretiere), um eine vernünftige Auswertung zu ermöglichen.

Hallo Jurs,
du hast recht, ohne delay verschluckt er sich nicht spürbar.
Gruß Ardubu