... Vermutlich geben die Inkrementalgeber ein Quadratursignal ... im Allgemeinen nicht die beste Lösung, dieses per ext. Interrupts ... auzuwerten ...
Die Frage ist ja, ob es Sinn macht das komplette Quadratursignal (wenn es eins ist) auszuwerten.

......Bild hier  

Warum? Weil ich einigermassen sicher bin, dass der Versatz der Signalflanken nicht genau gleich ist (so lange ich den Encoder nicht selbst hergestellt oder ausführlich getestet habe). Dann kommt eine Ungenauigkeit rein, die sich bei hohen Drehzahlen - und den damit verbundenen wenigen Timerticks schon wesentlich auf die Regelung auswirken kann. Hier wäre zu überlegen, ob man nicht (nur) jede gleichsinnige Flanke einer Encoderspur auswertet. Wenns nicht gerade eine hochgenaue Drehzahlregelung für etliche zehntausend Touren sein soll dürfte das reichen und möglicherweise eine genauere Regelungsgrundlage liefern als die Auswertung aller Flanken.

Die Lösung mit dem externen Interrupt ist nicht die schlechteste. Ich fahre bei meinem Dottie, beim MiniD0 und beim Archie, alles aber KEINE Schrittmotoren, mit dem externen Interrupt für steigende Flanke (beim Archie nur für EINE Endoderspur - je Motor *gg*) und werte in der zugehörigen ISR natürlich auch gleich die zweite Spur zur korrekten Wegberechnung (Drehrichtungserkennung) aus. Der Erfolg ist eine überraschend hohe Geschwindigkeitstreue. Ob Schrittmotoren in dieser Hinsicht empfindlicher sind, kann ich aber nicht sagen.

... Inkrementalgeber gerne über Interrupts auslesen würde, um möglichst keine Schritte zu verpassen ...
Wenns nicht um genaue Drehzahlregelung geht, sondern nur um exakte Wegerfassung (Drehwinkel), dann sehe ich das CPU-Laufzeitproblem nicht so gravierend, weil es nur wenige Codezeilen sind:

Die vollständige ISR für (m)einen Encoder bei Archie (der zugehörige *lls-Auszug ist gaaaanz unten) :
Code:
// ============================================================================= =
// ===  Nicht unterbrechbare ISR für EXT_INT0 auf Pin 4/PD2/mega328
// Der Timer tmrE0 für Laufzeit des EXT_INT0 wird ausgelesen
//      Der zugehörige Motor auf PD7/PB0 = re,li und PB1 Geschwind./PWM
 ISR(INT0_vect)                 // INT0 triggert auf RISING edge => 
 {                              //   => Wenn Aufruf, dann PORTD2 = high
// - - - - - - - - - - - - - - - -
//      Encoderticks Iencdrx nur hochzählen, IencBx rauf- od runterzählen
  Iz_diff0  = tmrE0;    // Abspeichern Zeit seit dem letzten ISR-Aufruf
  tmrE0     =    0;     // Resetten ##>> IN der ISR ohne CLI/SEI möglich
  Iencdr0 ++;           // Incrementiere Encodercounter, zählt NUR aufwärts
  if (IsBitSet (PIND, 4)) IencB0++;     // Rad treibt vorwärts,  math. negativ
  else                    IencB0--;     // Rad treibt rückwärts, math. positiv
 }      // Ende ISR(INT0_vect)
// ============================================================================= =
In der Timer-ISR - 20 kHz <=> 50 µs - wird der Zeitwert tmrE0 getickert:
Code:
// ===  Nicht unterbrechbare ISR für timer2 =================================== */
// Routine zählt hoch im Takt 20 kHz = 50 µs.  Der Zählerwert wird von den ISR für
//      EXT_INT0 und -INT1 ausgelesen
 ISR(TIMER2_COMPA_vect)         // 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 {                              //
  Izeit_1 --;           //  ###>>> Izeit_1 ist aktuell int16_t ==>>
                        //  Izeit_1 bleibt bis 32000 in der int16-Grenze
  tupUM0 ++;            // Tupsicounter für Umdrehungsmessung(en)
  tmrE0   ++;           // Encodertimer hochtickern
  tmrE1   ++;           // Encodertimer hochtickern
//RCzeit1 ++;           // Tupsicounter uint16_t für RC-5-Decoding

  if ( Izeit_1 )        // Interrupt-Timer = 1 ... 20 000 ... (1 sec blink)
    {  }                // WENN Izeit_1 =|= Null => wahr => Anweisung ausgeführen
  else                  // Izeit_1 = Null = unwahr, daher "else" ausführen
  {                     // Eine Sekunde ist voll =>
    Izeit_1 = Izthrznt; // ansonsten: Rückstellen auf Zeithorizont
    ToggleBit (PgLED, L1g);     // gnLED toggeln    HEARTBEAT <<####, aktuell PC1
    Isecundn ++;                // Sekundenzähler hochtackern, max 9 Std
  }             // Ende if (Izeit_1 )

  if (tmrE0 > 2000)     // Grenzwert für Stillstand
// ... usf
Der *lls-teil zur Encoder-ISR:
Code:
// ============================================================================= =
// ===  Nicht unterbrechbare ISR für EXT_INT0 auf Pin 4/PD2/mega328
// Der Timer tmrE0 für Laufzeit des EXT_INT0 wird ausgelesen
//      Der zugehörige Motor auf PD7/PB0 = re,li und PB1 Geschwind./PWM
 ISR(INT0_vect)                 // INT0 triggert auf RISING edge => 
 {                              //   => Wenn Aufruf, dann PORTD2 = high
     8d4:    1f 92           push    r1
     8d6:    0f 92           push    r0
     8d8:    0f b6           in    r0, 0x3f    ; 63
     8da:    0f 92           push    r0
     8dc:    11 24           eor    r1, r1
     8de:    8f 93           push    r24
     8e0:    9f 93           push    r25
// - - - - - - - - - - - - - - - -
//      Encoderticks Iencdrx nur hochzählen, IencBx rauf- od runterzählen
  Iz_diff0  = tmrE0;    // Abspeichern Zeit seit dem letzten ISR-Aufruf
     8e2:    80 91 2f 07     lds    r24, 0x072F
     8e6:    90 91 30 07     lds    r25, 0x0730
     8ea:    90 93 0f 07     sts    0x070F, r25
     8ee:    80 93 0e 07     sts    0x070E, r24
  tmrE0     =    0;     // Resetten ##>> IN der ISR ohne CLI/SEI möglich
     8f2:    10 92 30 07     sts    0x0730, r1
     8f6:    10 92 2f 07     sts    0x072F, r1
  Iencdr0 ++;           // Incrementiere Encodercounter, zählt NUR aufwärts
     8fa:    80 91 0a 06     lds    r24, 0x060A
     8fe:    90 91 0b 06     lds    r25, 0x060B
     902:    01 96           adiw    r24, 0x01    ; 1
     904:    90 93 0b 06     sts    0x060B, r25
     908:    80 93 0a 06     sts    0x060A, r24
  if (IsBitSet (PIND, 4)) IencB0++;     // Rad treibt vorwärts,  math. negativ
     90c:    4c 9b           sbis    0x09, 4    ; 9
     90e:    06 c0           rjmp    .+12         ; 0x91c <__stack+0x1d>
     910:    80 91 48 06     lds    r24, 0x0648
     914:    90 91 49 06     lds    r25, 0x0649
     918:    01 96           adiw    r24, 0x01    ; 1
     91a:    05 c0           rjmp    .+10         ; 0x926 <__stack+0x27>
  else                    IencB0--;     // Rad treibt rückwärts, math. positiv
     91c:    80 91 48 06     lds    r24, 0x0648
     920:    90 91 49 06     lds    r25, 0x0649
     924:    01 97           sbiw    r24, 0x01    ; 1
     926:    90 93 49 06     sts    0x0649, r25
     92a:    80 93 48 06     sts    0x0648, r24
 }      // Ende ISR(INT0_vect)
     92e:    9f 91           pop    r25
     930:    8f 91           pop    r24
     932:    0f 90           pop    r0
     934:    0f be           out    0x3f, r0    ; 63
     936:    0f 90           pop    r0
     938:    1f 90           pop    r1
     93a:    18 95           reti
... das sind schlappe vierzig Maschinenzyklen für einen Encoder.