jurs:
OK, ich denk mal drüber nach und poste dann eine geänderte und auf Deinen Anwendungsfall angepaßte Auswerteroutine.
So, drüber nachgedacht und eine angepaßte Auswertung für die Zählung von Einzelimpulsen codiert :
// Drehgeber-Auswertung Demo by 'jurs' for German Arduino forum
#define ENCODER_A 2
#define ENCODER_B 3
#define ERRORCODE 9999
#define TIMEOUT 20
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(ENCODER_A, INPUT_PULLUP);
pinMode(ENCODER_B, INPUT_PULLUP);
encoderImpuls(); // Initialisiert den Anfangszustand des Drehgebers
}
int encoderImpuls()
{
static byte state=0;
state= state<<2;
if (digitalRead(ENCODER_A)) bitSet(state,1);
if (digitalRead(ENCODER_B)) bitSet(state,0);
state= state & 0xF;
switch(state)
{
case 0b0000:
case 0b0101:
case 0b1010:
case 0b1111: return 0; // keine Änderung an den Eingängen
case 0b0001:
case 0b0111:
case 0b1110:
case 0b1000: return -1; // links Impuls an den Eingängen
case 0b0010:
case 0b1011:
case 0b1101:
case 0b0100: return 1; // rechts Impuls an den Eingängen
default: return ERRORCODE; // Error (z.B. wegen verpaßter Impulse)
}
}
long impulseTotal=0;
unsigned long errorImpulse;
long impulsAuswertung()
{
int thisImpulse=encoderImpuls();
if (thisImpulse==ERRORCODE) errorImpulse++;
else impulseTotal+=thisImpulse;
return impulseTotal/4;
}
void updateImpulsAnzeige()
{
static unsigned long lastDisplayTime=0;
static long impulseDisplayed;
long impulseAusgewertet=impulsAuswertung();
if(impulseAusgewertet!=impulseDisplayed && micros()-lastDisplayTime>2000)
{
impulseDisplayed=impulseAusgewertet;
lastDisplayTime=micros();
Serial.println(impulseAusgewertet);
}
if (errorImpulse>0) // Optionale Anzeige von Auswertefehlern
{
Serial.println('*');
errorImpulse=0;
}
}
void loop() {
updateImpulsAnzeige();
}
Das wesentliche an diesem Code ist, dass die Funktionen "impulsAuswertung()" und "updateImpulsAnzeige()" getrennt sind.
Da die Auswertung in der loop erfolgt, müßtest Du darauf achten, dass Dein Code schnell genug läuft, wenn der Drehgeber ausgewertet werden soll. Insbesondere wenn Du ein 4-zeiliges LCD komplett neu beschreiben möchtest, z.B. 4 Zeilen a 20 Zeichen, während der Drehgeber ausgewertet wird, müßtest Du den Schreibvorgang so aufteilen, dass höchstens 2 Millisekunden zwischen zwei Aufrufen von "impulsAuswertung()" vergehen. Also z.B. folgende Pseudologik:
lcd.setCursor(0,0);
ErsteLcdZeileSchreiben();
impulsAuswertung()
lcd.setCursor(0,1);
ZweitecdZeileSchreiben();
impulsAuswertung()
lcd.setCursor(0,2);
DritteLcdZeileSchreiben();
impulsAuswertung()
lcd.setCursor(0,3);
VierteLcdZeileSchreiben();
impulsAuswertung()
Eine Anzeige von Kontaktprellen wird dadurch vermieden, dass mit der Bedingung "micros()-lastDisplayTime>2000" die Anzeige des aktuelle Wertes unterdrückt wird, wenn innerhalb von 2000µs (2ms) bereits ein anderer Wert in der Anzeige aktualisiert worden ist.
Nun könnte man sich noch etwas überlegen, wie man ohne weitere Hardware, nur mit einer intelligenten Auswertelogik, auch große Werteänderungen komfortabel einstellbar machen könnte. Also z.B. wie man einen Einstellwert um 4711 erhöhen könnte, mit weniger 4711 Impulsen am Encoder.
Eine Überlegung dazu wäre, als Zusatzinformation auszuwerten, wie oft der Drehgeber in dieselbe Richtung gedreht wird, und wenn der Drehgeber immer weiter in dieselbe Richtung gedreht wird, irgendwann die Schrittweite beim Zählen zu erhöhen. Beispiel:
- 1 bis 11 mal nach rechts drehen ==> Zähler zählt einzeln immer 1 höher
- 12 mal nach rechts drehen ==> Zähler springt hoch auf den nächsten vollen Zehner
- 13 mal und mehr nach rechts drehen ==> Zähler zählt ab sofort in 10er Schritten
- 22 mal nach rechts drehen ==> Zähler springt hoch auf den nächsten vollen Hunderter
- 23 mal und mehr nach rechts drehen ==> Zähler zählt ab sofort in 100er Schritten
- 32 mal nach rechts drehen ==> Zähler springt hoch auf den nächsten vollen Tausender
- 33 mal und mehr nach rechts drehen ==> Zähler zählt ab sofort in 1000er Schritten
Nach links entsprechend. Bei jedem Drehrichtungswechsel beginnt die Logik von vorne.
Das würde bedeuten, dass viele Werte nicht alleine durch Drehen in eine Richtung eingestellt werden können, sondern dass man links und rechts drehen muss. Dafür lassen sich mit sehr wenigen Drehimpulsen auch sehr große Werte einstellen.
Beispiel, um von 0 auf den Wert 4711 einzustellen:
Wie oben ausgeführt, würde die 32. Rechtsdrehung den Wert auf 1000 springen lassen, beim 33. Rechtsimpuls springt der Zähler auf 2000, beim 34. auf 3000, beim 35. auf 4000, beim 36. auf 5000. Ab jetzt dreht man nach links.
Nach 22 maliger Linksdrehung wäre man auf 4900 herunter, nach 23 maliger auf 4800, nach 24 maliger auf 4700.
Jetzt noch 11 Impulse nach rechts drehen ==> 4711.
D.h. mit nur 36+24+11 = 71 Zählimpulsen ließe sich der Zähler von 0 auf 4711 verstellen.
Wenn man sich mit so einer rechts-links-rechts Einstellerei nach diesem Schema anfreunden kann, ließen sich so sehr hohe Werte mit sehr wenig Kurbelei am Drehgeber einstellen.
Bei Einzelzählung wären 4711 Impulse an einem Drehgeber mit 18 Impulsen pro Umdrehung ja 262 Umdrehungen, und mit der oben skizzierten Logik nur 4 Umdrehungen. Man kann sich erhebliche Drehbewegungen beim Einstellen sparen.
Vielleicht sollte man sich das überlegen, es so auszuwerten, und dafür eine Auswertelogik schreiben.