Was macht mein DUE anders?

Hallo !
Mit dem UNO funktioniert das analoge Abtasten eines Sensors im Takt eines Encoders ausgezeichnet.
(Kompliment an die Arduino-Gemeinde: das habe ich mit rudimentären Kenntnissen und den ausgezeichneten Foreneinträgen geschafft!).
Nur wenn ich zu schnell werde bricht die Messung und die Übermittlung der Daten an den Serial Monitor ab. Also habe ich mir den schnelleren DUE beschafft.
Wenn ich mit dem UNO den Serial Monitor öffne werden im Takt des Encoders endlos Daten aufgezeichnet.
Wenn ich mit dem DUE den Serial Monitor öffne werden zwei Abfragen aufgezeichnet, dann ist Schluss. Es sei denn, ich drücke die SEND-Taste des Monitors, dann folgen nochmals zwei Messungen.
Ich habe Unterschiede gesucht aber kein systematisches Verhalten gefunden, das mich weiter bringen könnte. Kann jemand weiter helfen?

Meine Kristallkugel ist leider momentan defekt, deshalb wird das nichts mit dem Hellsehen. Es würde helfen, wenn Du uns den Code zeigst, der dieses Verhalten zeigt. Und bitte: Code-Tags nicht vergessen!

@pylon - Danke für das Interesse!
Der folgende Code funktioniert mit dem UNO:

/***Encoder***Verhalten Rotary Encoder " von Currymütze"***/ 
int AAread=0;
int BBread=0;
byte A=3;             // weiss/gelb auf dpinNr=3
byte B=2;             // weiss/orange auf dpinNr=2
long d;               
#define FIRST_PIN 5           // Define the Analog Pin, Ue1, schwarz
int firstValue, secondValue; // Define Variables to store the analog Values
int mittel=1;
int mittelWert=1;
int i=1;  int var=1;
/********SETUP**********/
void setup()
{
  Serial.begin (115200);
/*********ENCODER**********/   
  pinMode(A,INPUT);                        
  pinMode(B,INPUT);
  digitalWrite(A,HIGH);                // HIGH = Pullup-Widerstand aktiviert                
  digitalWrite(B,HIGH);                        
  attachInterrupt(0,encoder,RISING); } //  (0,encoder,CHANGE); = doppelte Abtastrate!!
/********HAUPTSCHLEIFE*********************/
void loop()   { 
     delay(1000);     }
/***Encoder Steuerung*** 7 Messungen mitteln ***/
void encoder() {
  for(int x=0; x<7; x++) {
  AAread=digitalRead(A);
  BBread=digitalRead(B);  
/*----Linksdrehen-----------*/
  if (AAread==LOW && BBread==LOW ||AAread==HIGH&& BBread==HIGH){
   d=d-1;
   firstValue = analogRead(FIRST_PIN);  
   mittel = mittel+firstValue;
  }  
/*----Rechtsdrehen------------*/
  if (AAread==HIGH && BBread==LOW||AAread==LOW && BBread==HIGH) {
       d=d+1;
   firstValue = analogRead(FIRST_PIN);   
    mittel=mittel+firstValue;
     }    
   }  
/*****Serial.print**** senden an COM4 ***/   
    mittelWert = mittel/7;
    Serial.print(mittelWert);  Serial.print(','); 
    Serial.print(d/7);       Serial.println(',');
    mittel=0;
}

AuHa:

    Serial.print(mittelWert);  Serial.print(','); 

Serial.print(d/7);      Serial.println(',');

Serial.print innerhalb einer Interruptbehandlung zu verwenden ist ein Programmierfehler!

Der Code funktioniert auch auf einem UNO nicht bzw. nur äußerst eingeschränkt.

Serial.print ist keine Funktion, die man sicher innerhalb einer Interruptbehandlung verwenden dürfte.

Der Code ist auf einem UNO genau so falsch wie auf einem DUE, auch wenn sich der Fehler auf einem UNO nicht so gravierend auswirkt und das Programm dort erst dann crasht, wenn der serielle Sendepuffer zum ersten mal voll wird.

AuHa:
Mit dem UNO funktioniert das analoge Abtasten eines Sensors im Takt eines Encoders ausgezeichnet.
...
Nur wenn ich zu schnell werde bricht die Messung und die Übermittlung der Daten an den Serial Monitor ab.

Das beschreibst Du ja selbst, wie Dein Programm auch auf dem UNO crasht und aufhört zu funktionieren.

Vielen Dank für die rasche Hilfe! Jetzt reicht vielleicht schon der UNO.

AuHa:
Jetzt reicht vielleicht schon der UNO.

Was soll das Programm denn genau machen?

Mit einem lahmen “analogRead” innerhalb der ISR blockierst Du das Programm in jedem Fall ganz schön lange während der Interruptverarbeitung (über 100µs lang), so dass nur viel weniger als 10000 Interrupts pro Sekunde verarbeitet werden können.

Normalerweise kann ein Atmega328 bei 16 MHz mehrere zigtausend Interrupts pro Sekunde verarbeiten, aber dann muss die ISR sehr schnell ablaufen.

In jedem Fall muß das “Serial.print” aus der ISR raus, um das Programm nicht spätestens bei hoher Interruptrate zu crashen. Um das zu machen, deklarierst Du typischerweise globale Variablen, auf die sowohl von der ISR als auch vom normalen Programm aus zugegriffen werden. Diese Variablen müssen mit dem Zusatz “volatile” deklariert werden.

Wenn Du Hilfe benötigst, erkläre was Du genau machen möchtest und wie schnell alles laufen muß, was Du messen und ausgeben möchtest.

pylon:
Meine Kristallkugel ist leider momentan defekt, deshalb wird das nichts mit dem Hellsehen. Es würde helfen, wenn Du uns den Code zeigst, der dieses Verhalten zeigt. Und bitte: Code-Tags nicht vergessen!

Ja, wenn man billig-noname-Kugeln kauft.... :wink: :wink: :wink:

@AuHa

In Deinem Sketch ist viel Optimierungspotential:

if (AAread==LOW && BBread==LOW ||AAread==HIGH&& BBread==HIGH)
ist das gleiche wie
if (AAread==BBread)
Den Sinn der analogen Messung erschließt sich mir nicht. Gleichwenig wie das 7 malige incrementieren/ decrementieren von d
bzw vom kontrollieren der Zustände der beiden Eingänge A und B.

Schreib mal was Du genau machen willst.
Grüße Uwe

@ jurs und uwefed
Das Programm soll einen Sensor im Takt des Encoders abfragen, also wegproportional, vorwärts oder rückwärts (Eingänge A und B) und den Messwert weitergeben (Serial.print) damit ich ihn mittels Grafik auf dem Bildschirm “life” darstellen kann. Damit soll eigentlich ein Linienschreiber emuliert werden.
Geschwindigkeit? 1000 Abfragen pro Sekunde sind vermutlich unanständig schnell? Deshalb mein Versuch durch Komprimierung (z.B. 7 Messwerte/7=1) bzw. Datenmittelung die Datenflut etwas in den Griff zu bekommen.
Wenn ich eure Kommentare lese - ja dann brauche ich Hilfe. Habe ja auch schon welche bekommen!
Danke und Grüsse
AuHa

AuHa:
1000 Abfragen pro Sekunde sind vermutlich unanständig schnell? Deshalb mein Versuch durch Komprimierung (z.B. 7 Messwerte/7=1) bzw. Datenmittelung die Datenflut etwas in den Griff zu bekommen.

Ich kalkuliere mal überschlägig durch:

Die notwendige Rechenzeit für einmal analogRead beträgt standardmäßig = 104µs
Annahme: Der ganze Rest-Plumpatsch verbraucht pro Messung genau so viel Rechenzeit = 104µs
Summe = 208µs

Eine Sekunde hat 1000000 µs / 208 µs = 4807 Messungen
Also die Rechenzeit reicht grob überschlagen für über 4000 Messungen pro Sekunde

Ein anderer Flaschenhals ist die serielle Schnittstelle. Bei nominell 115200 Baud gehen pro Sekunde maximal 11520 Zeichen über die Leitung. Wenn ich mal kalkuliere, dass ein analogRead in ASCII formatiert bis zu 4 Zeichen lang wird plus CRLF als Zeilenende macht 6 Zeichen pro Messung maximal.

11520 / 6 = 1920 Messungen pro Sekunde

Das heißt, erster Flaschenhals ist die serielle Schnittstelle, die bei 115200 Baud nur ca. 1900 Messungen pro Sekunde über die Leitung schieben kann.

Wenn Dir die Ausgabe von 1000 (oder bis max. 1900) Impulse/Messungen pro Sekunde reichen, braucht man weiter nichts berücksichtigen. Ansonsten kann man die Datenübertragung natürlich auch verlangsamen, indem man bei extrem schnell auflaufenden Daten seltener sendet. Z.B. wenn weniger als 0,001s (1ms= 1000µs) zwischen zwei Impulsen liegt, sendet man z.B. nur nach jedem zweiten Impuls den Mittelwert aus zwei Messungen.

Ich kann mal schauen, was mir als Code einfällt, das weit über 1000 Impulse/Messungen pro Sekunde schafft.
Aber das wäre dann nur für UNO oder MEGA (und ggf. andere 8-Bit Controller) kompatibel, aber nicht für DUE kompatibel.
Kann ein paar Tage dauern.

jurs:
Die notwendige Rechenzeit für einmal analogRead beträgt standardmäßig = 104µs

Wobei das für die AVRs gilt. Der ARM Prozessor auf dem Due braucht standardmäßig etwa 40µs

Allerdings ist das wie typisch für den Arduino wohl wieder schlecht implementiert:
http://www.djerickson.com/arduino/
(ganz unten)

AuHa:
Das Programm soll einen Sensor im Takt des Encoders abfragen, also wegproportional, vorwärts oder rückwärts (Eingänge A und B) und den Messwert weitergeben (Serial.print) damit ich ihn mittels Grafik auf dem Bildschirm “life” darstellen kann.

OK, mein Code zu dieser Aufgabenstellung sieht dann zunächst mal wie folgt aus:

// rotary encoder demo by 'jurs' for German Arduino Forum
#define ENCODER_A 3      // encoder pin A
#define ENCODER_B 2      // encoder pin B
#define ANALOG_PIN A5    // analog pin for measure
#define BAUDRATE 115200L // serial baud rate

#define ERRORCODE 9999 // internal error code

void setup() {
  Serial.begin(BAUDRATE);
  Serial.println();
  Serial.println("Good night and good luck!"); // print some Test-Message at beginning
  pinMode(ENCODER_A, INPUT_PULLUP);
  pinMode(ENCODER_B, INPUT_PULLUP);
  encoderImpuls(); // Initialisiert den Anfangszustand des Drehgebers
}

void loop() {
  static int drehRichtung;
  static boolean drehRichtungsWechsel=false;
  int impuls=encoderImpuls(); // read from encoder
  if (impuls==0) return; // no impulse found, exit loop
  if ((impuls==1 && drehRichtung==-1)||(impuls==-1 && drehRichtung==1))
  {
    drehRichtung=impuls;
    drehRichtungsWechsel=true;
  }
  else if (impuls==1 || impuls==-1) 
  {
    drehRichtung=impuls;
    drehRichtungsWechsel=false;
    messung();
  }
  else if (impuls==ERRORCODE) Serial.println("***");
}

int encoderImpuls()
{
  static byte state=0;
  state= state<<2 | (byte)digitalRead(ENCODER_A)<<1 | (byte)digitalRead(ENCODER_B); 
  state= state & 0xF;   // Nur die unteren 4 Bits behalten
  if      (state==0b0000 || state==0b0101 || state==0b1010 || state==0b1111) return 0;
  else if (state==0b0001 || state==0b0111 || state==0b1110 || state==0b1000) return -1;
  else if (state==0b0010 || state==0b1011 || state==0b1101 || state==0b0100) return 1;
  else return ERRORCODE ;
}

void messung()
{
  Serial.println(analogRead(ANALOG_PIN));  
}

Auf Interrupts und sämtliche controllerabhängige Low-Level-Programmierung auf Registerebene habe ich verzichtet, der Code sollte daher zu allen gängigen Arduinos (UNO, MEGA, LEONARDO, DUE etc.) kompatibel sein.

Soweit ich es verstanden habe, ist es auch egal ob der Drehgeber rechtsrum oder linksrum dreht, sobald er Impulse abgibt soll beim Erkennen eines Impulses der Sensorwert gemessen und ausgegeben werden.

Prellen von mechanischen Drehgebern wird unterdrückt.

Fehler durch “Überdrehen” werden (zumindest teilweise) erkannt und beim Erkennen eines Fehlers durch Überdrehen wird “***” anstelle eines Messwertes ausgegeben. Bei einer Baudrate von 9600 kann man mit einfachen mechanischen Drehgebern (18 Raststufen pro Umdrehung) noch ein Überdrehen erzeugen, was mit 115200 Baud dann nicht mehr möglich ist.

Höhere Auswertegeschwindigkeiten sind mit höheren Baudraten möglich. Zwar unterstützt der Serielle Monitor der Arduino-Software nur maximal 115200 Baud, aber wenn das nicht reicht, könntest Du auf der PC-Seite ein anderes Terminalprogramm verwenden, dann sind auch Baudraten von 250000 oder 500000 möglich, da moderne PCs auf ihren virtuellen seriellen Schnittstellen über USB auch solche Baudraten unterstützten.

So ungefähr?
Oder habe ich irgendwas an der Aufgabenstellung nicht verstanden?

@Serenifly
Danke für die Notiz und den Link. Wenn ich aus dem Wochenende zurück bin werde ich mich darin vertiefen.

@jurs
Ausgezeichnete Lösung, ich hab sie gleich ausprobiert. Die Daten fliessen um vieles schneller als mit meiner Lösung. Und Abstürze gibt's auch keine mehr.
Die Drehrichtung des Encoders dient der Ortung des Messpunktes auf einer Wegstrecke. Die Impulse werden zu- und abgezählt je nach Drehrichtung. Jeder Messpunkt ist auf diese Weise lokalisiert. Ich habe deshalb eine Wegmessung eingeführt und den nachstehenden Befehl in void loop():

else if (impuls==1 || impuls==-1) 
  {
    drehRichtung=impuls;
    drehRichtungsWechsel=false;
    messung();
  }

aufgeteilt in:

else if (impuls==1)
{
drehRichtung=impuls;
drehRichtungsWechsel=false;
Weg = Weg - 1;
messung();
}
else if (impuls==-1)
{
drehRichtung=impuls;
drehRichtungsWechsel=false;
Weg = Weg + 1;
messung();
}

Ist diese Ergänzung im Sinne des erfahrenen Programmierers?
An beide: Aufrichtigen Dank für die freundschaftliche Hilfe.
AuHa

Lässt sich vereinfachen zu:

else if (impuls==1 || impuls==-1) 
{
    drehRichtung=impuls;
    drehRichtungsWechsel=false;
    weg = weg - impuls;
    messung();
 }

AuHa:
Ausgezeichnete Lösung, ich hab sie gleich ausprobiert. Die Daten fliessen um vieles schneller als mit meiner Lösung. Und Abstürze gibt's auch keine mehr.

Na bitte, und das komplett OHNE Interrupts!
Und ohne spezielle Optimierungen.

Wenn Du beim Drehen mit hohen Impulsraten trotzdem an die Grenzen stößt und zu oft die drei Sternchen *** anstelle eines Messwerts erscheinen, weil die Auswertung nicht mehr mitkommt, müßte man sich dagegen etwas einfallen lassen.

AuHa:
Ist diese Ergänzung im Sinne des erfahrenen Programmierers?

Wie Serenifly schreibt: Die Fallunterscheidung ist nicht notwendig, Du kannst direkt subtrahieren.
Denn minus eine negative Zahl ist dasselbe wie Plus.

Du könntest aber auch die Pins am Drehgeber für A und B vertauschen, dann zählen die Impulse genau anders herum, also positive Impulse für positiven Weg. Impulse und Weg wären nicht mehr gegenläufig.
Dann würdest Du die Impulse addieren statt subtrahieren:

weg = weg + impuls;

Funkstille: ich musste erst mit dem mechanischen Versuchsaufbau klar kommen!
@jurs
Die vorgeschlagene Lösung funktioniert gut, ist aber noch zu langsam. Vorerst mache ich die Inkremente mindestens 2,5 x länger. Je nach der auftretenden Spannugsfluktuation kann die Datenrate dann noch weiter gesenkt werden.

Wenn Du beim Drehen mit hohen Impulsraten trotzdem an die Grenzen stößt und zu oft die drei Sternchen *** anstelle eines Messwerts erscheinen, weil die Auswertung nicht mehr mitkommt, müßte man sich dagegen etwas einfallen lassen.

Was ist damit gemeint?
Danke
AuHa

AuHa:
Die vorgeschlagene Lösung funktioniert gut, ist aber noch zu langsam. Vorerst mache ich die Inkremente mindestens 2,5 x länger. Je nach der auftretenden Spannugsfluktuation kann die Datenrate dann noch weiter gesenkt werden.

Ich weiß nicht, was das genau bedeuten soll.

Ich weiß ebenfalls nicht, auf was für eine Datenrate und wie viele ADC Messungen pro Sekunde Du kommen möchtest. Der von mir gepostete Sketch sollte auf über 1500 verarbeitete Drehgeber-Impulse und ADC-Messungen pro Sekunde kommen, ohne aus dem Tritt zu geraten.

Und ich weiß nicht einmal, ob es sich überhaupt um einen einfachen passiven mechanischen Drehgeber mit mechanischem Kontraktprellen handelt, den Du auswerten möchtest, oder um einen hochwertigen opto-elektronischen Drehgeber mit eigenem Stromanschluß und eigener Auswerteelektronik, dessen Signal nicht prellt.

AuHa:

Wenn Du beim Drehen mit hohen Impulsraten trotzdem an die Grenzen stößt und zu oft die drei Sternchen *** anstelle eines Messwerts erscheinen, weil die Auswertung nicht mehr mitkommt, müßte man sich dagegen etwas einfallen lassen.

Was ist damit gemeint?

Damit meine ich: Optimierungen, um schneller zu werden, wenn der Sketch nicht mehr mitkommt.
Wenn man genau weiß, um was es geht, kann man genau da ansetzen und optimieren, wo der Flaschenhals ist.

Zwei Flaschenhälse sind bei Deinem Vorhaben möglich:
1.) Bei 115200 Baud bekommst Du maximal 11520 Zeichen pro Sekunde gesendet
2) Mit analogRead() braucht eine ADC-Messung 104µs

Je nachdem kann man an beiden Flaschenhälsen Änderungen vornehmen, wo es erforderlich ist, um eine schnellere Verarbeitung zu ermöglichen.

Übrigens habe ich erst gerade heute hier einen anderen Sketch zur Drehgeberauswertung gepostet:

Der ist allerdings für einen anderen Anwendungsfall (Einstellung von Konfigurationswerten), wertet nicht alle Flankenwechsel aus, sondern nur Flankenwechsel/4, und das mit einem 2000µs/2ms Timeout zur Unterdrückung des Kontaktprellens bei der Ausgabe.

@jurs
Der verwendete Drehgeber ist ein GIO-40 (http://www.twk.de/data/pdf/10862ad0.pdf) Ausführung mit 360 Impulsen/Umdrehung und am Ausgang Schalttransistoren mit offenem Kollektor. Ich messe 1440 Impulse/Umdrehung, also 4*360. Separate Speisung.
Die Frage nach der Datenrate: Bisher wurde eine Induktionsspule in Rechteckform mit 6 mm aktiver Breite ausgewertet. Jetzt soll ein Hallelement an diese Stelle treten. Wie die Signale jetzt aussehen ist noch nicht bekannt - die fokussierte Empfindlichkeit des Sensors dürfte ein neues Bild ergeben. Nach dem, was ich bisher an Signalen (mit Hallsensoren) verarbeiten konnte, ist die Datenrate zu hoch angesetzt. 4 mal weniger Messpunkte/Längeneinheit wären vermutlich genug. Die Elektronik des Drehgebers liefert demnach 4 mal zu viele Inkremente/Umdrehung. Wie komme ich da auf die ursprünglichen 360/Umdrehung?
Eine hohe Abtastgeschwindigkeit wäre erwünscht. z.B. 4 m/s was 2500 Messungen/sec bedeuten würde. Das wäre also das 1,3 fache der Uebertragungsrate von 115200 Baud. Die Daten in binärer Form zu übertragen, könnte das etwas bringen?
Vielen Dank für deine Hilfe

AuHa:
Ich messe 1440 Impulse/Umdrehung, also 4*360.
...
Eine hohe Abtastgeschwindigkeit wäre erwünscht. z.B. 4 m/s was 2500 Messungen/sec bedeuten würde.

So, endlich mal ein paar Angaben dazu, wo Du hinmöchtest!

Also Du möchtest in einer Sekunde 10000 Impulse am Drehgeber zählen und bei jedem vierten Impuls eine Messung mit analogRead machen?

Das wird "standardmäßig" und mit den fertigen "Komfortfunktionen" von Arduino a la "analogRead" schon mal nichts, und das rechne ich Dir gerne mal vor.

Eine Sekunde hat eine Million Mikrosekunden. Wenn Du diese Million durch die 10000 Impulse teilst, dann kommt ein Impuls alle:
1000000µs/10000 = 100µs.

D.h. Du hast zwischen den Impulsen rein rechnerisch ca. 100µs zur Verfügung.

Von diesem Wert abziehen müßtest Du noch laufende Interrupts auf Deinem Controller. Standardmäßig aktiviert der Arduino den Timer0 zur Verwaltung von millis() und micros() und delay. Und Du aktivierst das interruptgesteuerte Senden und Empfangen über Serial. Jeder Interrupt auf dem Atmega hat einen Overhead beim Aufruf von ca. 4µs, und wenn ich nur mal davon ausgehe, dass der Interrupt jeweils 2µs lang läuft, sind das 6µs pro Interrupt. Nun noch den ungünstigen Fall angenommen, dass drei Interrupts aufeinandertreffen und nacheinander abgearbeitet werden, also der Timer-Interrupt von Timer0, der serielle Empfangs-Interrupt und der serielle Sende-Interrupt, dann wird Dein Programm unter Umständen für 3*6 = 18 µs am Stück blockiert. Ziehe ich diese 18µs mal von den zur Verfügung stehenden 100µs ab, dann komme ich auf effektiv:
100µs - 18µs = 82 µs Verarbeitungszeit (worst-case) zwischen zwei Impulsen.
Wahrscheinlich noch etwas weniger, denn wegen mechanischer Fertigungsungenauigkeiten und Ungenauigkeiten in der Auswerteelektronik kommen die Impulse wohl nicht immer im selben Zeitabstand sondern mit zeitlicher Variation.

In diesen 82µs mußt Du:

  • den Drehgeber auswerten UND
  • Deinen ADC-Wert ermitteln (zwar nur bei jedem 4. Impuls, aber auch das kommt ja vor)

Und jetzt kommt der Knackpunkt: Die Arduino-Komfortfunktion "analogRead" benötigt für einen einzigen Aufruf in der Standardkonfiguration schon ca. 122µs.

Und da beißt sich die Katze in den Schwanz: Wenn Du zwischen zwei Impulsen nur effektive 82 µs Rechenzeit hast, und analogRead schon 122µs alleine benötigt, dann kann die Drehgeberauswertung so schnell sein wie sie will: Es passt nicht!

Also mußt Du optimieren, und zwar kräftig. Und die meisten schönen, einfachen, aber langsamen Arduino-Komfortfunktionen kannst Du in die Tonne treten und mit Hardcore-Mikrocontrollerprogrammierung auf Registerebene anfangen.

Und jetzt kommst Du: Wo kannst Du Abstriche machen und wie tief möchtest Du in die Atmega-Programmierung auf Registerebene einsteigen, um die langsamsten Arduino-Komfortfunktionen und Einschränkungen durch die Arduino-Libraries zu vermeiden?

Ich nenne mal einen relativ einfach realisierbaren Ansatz:

  • Herabsetzung der ADC-Auflösung von 10-Bit auf 8-Bit Auflösung (0...255 statt 0...1023)
  • Vorteil-1: Es sind wesentlich schnellere ADC-Messungen möglich
  • Vorteil-2: Über Serial kann der Messwert jeweils binär in einem einzigen Byte übertragen werden
  • Nachteil: Nur 8-Bit ADC-Auflösung (256 Stufen statt 1024)
    Das wäre relativ einfach machbar, ich habe allerdings noch nicht durchkalkuliert, ob man damit bereits ganz hinkommt.
    Möglich? Oder lieber nicht?

P.S.: Schreibe bitte auch mal das verwendete Board und die beiden Pins, die Du für die Drehgeber A und B Signale verwenden möchtest, möglichst zwei nebeneinander liegende Pins. Dann könnte man da statt "digitalRead" auch was schnelleres auf Registerebene bei der Drehgeberauswertung verwenden, auch wenn das nicht so wahnsinnig viel ausmachen wird.

@jurs. Danke für die ausführliche Antwort.
Fortschrittsbericht:

  1. Die 8-Bit ADC-Auflösung habe ich getestet, sie ist knapp ausreichend in der Versuchsphase.

  2. Das grösste Problem ist die 4-fach zu schnelle Inkrement-Folge. Meine Versuche, das Software-mässig zu korrigieren sind bisher fehlgeschlagen. Ich kann auch einen neuen Drehgeber beschaffen, wenn das die Sache vereinfacht, aber eigentlich möchte ich Auflösung der x-Achse variieren können weil die optimale Schrittlänge noch nicht fest steht.

  3. Wie Programmieren in der Registerebene geht, weiss ich nicht, da muss ich mich erst einarbeiten.

  4. Als Board habe ich den UNO, den DUE und den Leonardo beschafft. analogRead() braucht beim DUE am wenigsten Zeit, 39 ?sec, (Reply 9 von Serenifly - wenn ich das recht verstanden habe) also verwende ich den DUE. Die Drehgeber-Signale A und B habe ich bisher auf den Pins 2 und 3.
    Grüsse AuHa

Man kann auch auf den AVRs die Zeit verbessern wenn man den Prescaler verkleinert (der Frequenzteiler des ADCs, der den ADC Takt vom Prozessortakt ableitet):
http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/

Sampling Zeiten von 20-60µs sind auch da möglich. Das geht aber i.d.R. auf Kosten der Genauigkeit.

In dem vorherigen Link ist aber auch beschrieben, dass man den DUE dazu bringen kann in 4µs zu sampeln, wie er es eigentlich sollte:

REG_ADC_MR = (REG_ADC_MR & 0xFFF0FFFF) | 0x00020000;