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; // 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( enc_accel ) enc_accel--; // solange >0: pro ms um 1 "entschleunigen"
if( PHASE_A ) m = 1; // Gray nach binär wandeln
if( PHASE_B ) m ^= 3;
m -= enc_ab; // berechnen, ob sich der Encoder bewegt hat
// gültige Werte für Differenz (m): -1, 0, +1
// sonst ist die Abtastfrequenz zu niedrig!
if( moved ) { // Positionsänderung am Encoder?
enc_ab += m; // Encoderzustand speichern
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 // sonst
enc_accel = 255; // auf 255 begrenzen
if (i&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. 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.