Hallo,
Vorweg, ich nutzte den Encoder Code von Peter D.
https://www.mikrocontroller.net/articles/Drehgeber
Soweit so gut, funktioniert auch. Mittlerweile habe ich einen ALPS EM20B Handdrehencoder der 4 Steps pro Rastung macht.
https://www.alps.com/prod/info/E/HTML/Encoder/Incremental/EM20B/EM20B_list.html
Der prellt auch nicht dank Hallsensoren. Auch mit Datalogger überprüft, alles bestens. Ich kann vorwärts und rückwärts drehen, der "Absolutzähler" macht pro Rastung im Sketch genau +1 oder -1.
Dann habe ich einen Relativzähler hinzugefügt den ich bei Bedarf nullen kann oder auf einen anderen Wert je nach Anforderung. Dieser Relativzähler soll aktuell nur zwischen 0 und 30 zählen. Von 31 auf 0 springen und von -1 auf 30 springen. Je nach Drehrichtung.
Jetzt zu meinem Problem. Die Korrektur von 31 auf 0 klappt immer. Jedoch von -1 auf 30 klappt nicht. Er geht immer auf 29 statt 30. Ich weiß zum Henker nicht warum. Nur äußerst selten klappt es von -1 auf 30. Phasen vertauschen bringt nichts, Problem bleibt genauso bestehen nur das ich anders herum drehen muss. Diverse Debugausgaben sind alle okay. Die Phasensumme (0-3) ist auch okay. Der Absolutzähler funktioniert auch einwandfrei.
Ist meine Korrektor setRelCounter falsch?
Übersehe ich etwas in der Encoder Klasse?
Hat jemand irgendeine Idee?
Uno Pinout http://www.pighixxx.net/portfolio-items/uno/?portfolioID=314
Mega2560 Pinout pighixxx.net
class GrayEncoder // Klassenname "GrayEncoder"
{
protected: // private wird zu protected, nur intern zugängliche Elemente ...
volatile byte const *PORT; // verwendeter Port
byte const PinA; // Pin Port.Bit erste Phase
byte const PinB; // Pin Port.Bit zweite Phase
long enc_delta;
int last;
volatile long rel_counter; // Zähler
volatile long abs_counter; // Zähler
int direction; // Richtungsanzeige +1 / -1
byte Phase_A; // erste Phase
byte Phase_B; // zweite Phase
public: // von außen zugängliche Elemente ...
GrayEncoder (volatile byte *p_Port, byte _A, byte _B):
// Initialisierungsliste
PORT(p_Port),
PinA(_A),
PinB(_B),
rel_counter(0), // Zähler
abs_counter(0), // Zähler
direction(0) // Richtungsanzeige +1 / -1
{ }
void init()
{
int n = 0; // new
Phase_A = (*PORT >> PinA & 1); // einzelnes Bit heraus fischen
Phase_B = (*PORT >> PinB & 1);
if ( Phase_A ) n = 3;
if ( Phase_B ) n ^= 1;
last = n; // power on state
enc_delta = 0;
}
void encode()
{
int n = 0; // new
Phase_A = (*PORT >> PinA & 1); // einzelnes Bit heraus fischen
Phase_B = (*PORT >> PinB & 1);
if ( Phase_A ) n = 3;
if ( Phase_B ) n ^= 1; // convert gray to binary
int diff = last - n;
if ( diff & 1 ) { // bit 0 = value (1)
last = n; // store new as next last
enc_delta = (long) (diff & 2) - 1; // bit 1 = direction (+/-), Zähler
abs_counter += enc_delta;
rel_counter += enc_delta;
direction = enc_delta; // Richtungsanzeige (+1 / -1)
}
}
int getDirection() {
return direction; // Richtungsabfrage
}
};
// Klasse "ALPS_EM20B" erbt von "GrayEncoder"
class ALPS_EM20B : public GrayEncoder
{
public: // von außen zugängliche Elemente ...
// Phasen vertauscht
ALPS_EM20B(volatile byte *p_Port, byte _B, byte _A) : GrayEncoder (p_Port, _A, _B)
{ }
void setRelCounter( long value ) { // relativen Zählwert ändern
rel_counter = value << 2; // 4 Steps pro Rastung
}
long getRelCounter() { // relativen Zählwert abfragen
return rel_counter >> 2; //
}
long getAbsCounter() { // absoluten Zählwert abfragen
return abs_counter >> 2; // 4 Steps pro Rastung
}
};
ALPS_EM20B Encoder1 (&PINC, 1, 0); // Phase A/B, Pin 36/37 > Port.C Bit.1 / Bit.0
int Encoder1_Direction;
int Encoder1_RelCounter;
int Encoder1_AbsCounter;
void setup() {
Serial.begin(250000);
pinMode(36, INPUT_PULLUP);
pinMode(37, INPUT_PULLUP);
Encoder1.init();
Encoder1.setRelCounter(5);
}
void loop() {
update_Encoder();
serieller_Monitor();
}
// ****** Funktionen ******
void update_Encoder ()
{
Encoder1.encode();
Encoder1_Direction = Encoder1.getDirection();
Encoder1_RelCounter = Encoder1.getRelCounter();
Encoder1_AbsCounter = Encoder1.getAbsCounter();
if (Encoder1_RelCounter < 0) {
Encoder1.setRelCounter(30); // Variable geht auf 29 statt 30
}
else if (Encoder1_RelCounter > 30) {
Encoder1.setRelCounter(0);
}
}
void serieller_Monitor ()
{
static const unsigned int INTERVAL = 150;
static unsigned long last_ms = 0;
if (millis() - last_ms < INTERVAL) return; // Zeit noch nicht erreicht, Funktion abbrechen
last_ms += INTERVAL;
Ueberschriftszeile();
Serial.print(Encoder1_Direction); Serial.print('\t');
Serial.print(Encoder1_RelCounter); Serial.print('\t');
Serial.print(Encoder1_AbsCounter);
Serial.println();
}
void Ueberschriftszeile ()
{
static int counter = 33;
counter++;
if (counter < 30) return; // Zeilen noch nicht erreicht, Funktion abbrechen
counter = 0;
Serial.print(F("DIR")); Serial.print('\t');
Serial.print(F("Relat")); Serial.print('\t');
Serial.print(F("Absol"));
Serial.println();
}