Hier eine Drehgeberauswertung, die auf der Basis von Peter Danneggers Code (auf www.mikrocontroller.net) zusätzlich eine dynamische Beschleunigung realisiert. Je schneller am Knopf gedreht wird, umso schneller ändert sich der Wert. Das ergibt ein gutes haptisches Gefühl, und man kann größere Bereiche einstellen, ohne dass umgegriffen werden muß.
volatile int16_t enc_pos; #define PHASE_A (PINA & 1<<PA1) #define PHASE_B (PINA & 1<<PA2) // ISR wird z.B. jede ms aufgerufen ISR(SIG_OUTPUT_COMPARE1A) { #define DYNAMIK 40 static uint8_t enc_ab = 0x01; // speichert Encoderzustand 0..3 static uint8_t enc_accel = 0; // speichert die aktuelle Beschleunigung int16_t p; // (position) lokale Variable für Positionsberechnung int8_t m = 0; // (moved) lokale Variable für Bewegungsberechnung if (PHASE_A) m = 1; // Gray nach binär wandeln if (PHASE_B) m ^= 3; m -= enc_ab; // Differenz zeigt an, ob sich der Encoder bewegt hat // gültige Werte für Differenz (m): -1, 0, +1 // sonst ist die Abtastfrequenz zu niedrig! if (enc_accel) enc_accel--; // solange >0: pro ms um 1 "entschleunigen" if (m) { // wenn m ungleich 0 --> Positionsänderung am Encoder enc_ab += m; // Bewegungsdifferenz auf alten Encoderzustand aufaddieren p = enc_pos; // nicht auf globaler Variable (enc_pos) herumrechnen if (enc_accel<255-DYNAMIK) // neuen Beschleunigungswert berechnen: enc_accel += DYNAMIK; // solange <255 Beschleunigungswert aufaddieren else enc_accel = 255; // sonst auf 255 begrenzen (diese Zeile kann weggelassen werden) if (m&2) // Bit 1 = Vorzeichen = Richtung (+/-) p += 1+(enc_accel>>6); // Erst Beschleunigungswerte >64 (wegen >>6) else // werden berücksichtigt. p -= 1+(enc_accel>>6); // Diese Division (Shift 6) evtl. anpassen... enc_pos = p; // lokale Variable auf globale Variable zurückkopieren } : // ab hier kommt sonstiger Code im Timerinterrupt }
Im Beispiel sind die beiden Spuren an den Portpins 1 und 2 vom Port A angeschlossen. In der Variablen m steht ein Wert für die Bewegung: -1, 0, +1 (11, 00 und 01). Ein Wert ungleich 0 bedeutet also: Bewegung. PeDa fragt das Bit 0 explizit ab (m&1), ich habe das reduziert auf m!=0. Im Bit 1 (m&2) steckt dann die Bewegungsrichtung, mit der die Position hoch- oder runtergezählt wird.
Mit dem #define DYNAMIK lässt sich der "Biss", also die Beschleunigung einstellen. Leider funktioniert das z.B. mit den billigen Pollin-Encodern nur eingeschränkt, weil die pro Raste zwei Schritte machen. Also ist da etwas Spielen und Ausprobieren mit dem Wert angesagt. Ich habe noch jedesmal einen brauchbaren Wert gefunden. Mit einem uint16_t für enc_accel kann der Dynamikbereich wesentlich ausgeweitet werden.
Die Umwandlung vom Gray- in den Binärcode erfolgt mit dem XOR Verfahren wie auf Software/Graycode im letzten Beispiel beschrieben.
Im PDF CY8CKIT-049-4xxx PSoC 4 Rotary Encoder für Cypress Mikrocontroller hat Reiner Wehner das Ganze ab Seite 37 fein säuberlich analysiert. Und im Forum dort wird das im Thread Quadrature decoder at PSoC 4 ausdiskutiert, dort sind dann auch Links zur Umsetzung in Software zu finden.