Forum: Mikrocontroller und Digitale Elektronik 100PPR Encoder Pulse an Arduino richtig zählen


von Peter (Gast)


Lesenswert?

Guten Tag,

ich versuche einen 100PPR Pulse Encoder an einem Arduino zu betreiben.
https://www.ebay.de/itm/100PPR-6-Terminal-Eletronic-Hand-Wheel-Manual-Pulse-Encoder-Generator-CNC-Lathe/252100823685
Mein Code sieht wie folgt aus:
1
int encoder0PinA = 2;
2
int encoder0PinB = 3;
3
int encoder0negPinA = 4;
4
int encoder0negPinB = 5;
5
int encoder0Pos = 0;
6
int encoder0PinALast = LOW;
7
int current = LOW;
8
9
void setup()
10
{
11
  pinMode (encoder0PinA, INPUT);
12
  pinMode (encoder0PinB, INPUT);
13
  pinMode (encoder0negPinB, INPUT);
14
  pinMode (encoder0negPinB, INPUT);
15
  Serial.begin (9600);
16
  Serial.println("Ready\n0");
17
}
18
19
void loop()
20
{
21
  current = digitalRead(encoder0PinA);
22
  if ((encoder0PinALast == LOW) && (current == HIGH))
23
  {
24
    if (digitalRead(encoder0PinB) == HIGH)
25
    {
26
      encoder0Pos++;
27
    if(encoder0Pos == 100) { encoder0Pos = 0; }
28
    }
29
    else
30
    {
31
      encoder0Pos--;
32
      if(encoder0Pos == -1) { encoder0Pos = 99; }
33
    }
34
    Serial.println (encoder0Pos);
35
  }
36
  encoder0PinALast = current;
37
}

Den Wert encoder0Pos zu erhöhen klappt auch, er wird erhöht, nachdem der 
Encoder eingerastet ist.
Den Wert encoder0Pos zu erniedrigen klapp nicht sauber, da der Arduino 
schon vor dem Einrasten zählt.
So kommt es durch schnelleres Drehen zu anderen Werten, wie beim 
langsamen Drehen.

Der Encoder hat neben A und B auch noch neg. A und neg. B Ausgänge.
Wie kann ich (mit diesen) das Problem umgehen?
Oder gibt es eine andere Lösung?

Danke für eure Hilfe

von Wolfgang (Gast)


Lesenswert?

Peter schrieb:
> if ((encoder0PinALast == LOW) && (current == HIGH))

Und wo wird der umgekehrte Fall behandelt?

Die Auswertung von Inkrementalgebern wurde hier im Forum doch schon oft 
genug und leidenschaftlich diskutiert.

von Günter Lenz (Gast)


Lesenswert?

Peter schrieb:
>Den Wert encoder0Pos zu erniedrigen klapp nicht sauber, da der Arduino
>schon vor dem Einrasten zählt.

Das Einrasten hat nichts mit dem Zählen oder den Kontakten
zu tun, daß ist eine föllig unabhängige mechanische Sache.
Der Fehler liegt woanders, vielleicht in deinem Programm.

>Der Encoder hat neben A und B auch noch neg. A und neg. B Ausgänge.

Was hat er überhaupt für Kontakte? Sind das Mechanische Kontakte,
oder ist da Elektronik drinn?
Wenn das zwei mechanische Umschaltekontakte sind, kann
man damit mit RS-Flipflops prima Kontaktentprellschaltungen
aufbauen, die 100% funktionieren.

von Peter (Gast)


Lesenswert?

Habe nun mal direkt nach Inkrementalgeber gesucht, danke für den 
Hinweis.

Mit folgendem Code klappt es besser aber auch noch nicht richtig.
1
int encoder0PinA=3;
2
int encoder0PinB=2;
3
int encoder0Pos = 0;
4
5
void setup ()
6
{
7
 attachInterrupt(0,CHAInt,CHANGE); // Call Channel A of ENCODER Function while on CH1 Signal Changing
8
 pinMode(encoder0PinA,INPUT);
9
 pinMode(encoder0PinB,INPUT);
10
 digitalWrite(encoder0PinA,HIGH);
11
 digitalWrite(encoder0PinB,HIGH);
12
 Serial.begin (9600);
13
 Serial.println("Ready\n0");
14
}
15
16
void loop()
17
{
18
19
}
20
21
void CHAInt ()
22
{
23
 boolean a=false;
24
 boolean b=false;
25
 a = digitalRead(encoder0PinA);
26
 b = digitalRead(encoder0PinB);
27
 if (a==true && b==false||a==false && b==true){
28
   encoder0Pos++;
29
 }
30
 if (a==false && b==false ||a==true&& b==true){
31
   encoder0Pos--;
32
 }
33
 Serial.println(encoder0Pos/2);
34
}


Ich denke da ist "Elektronik drin".
Da 5V und GND benötigt wird, ohne kommt kein Output zustande.

von Martin B. (ratazong)


Lesenswert?

Dein Algorithmus für den Encoder funktioniert nicht. Kannst ja mal 
folgendes ausprobieren:

int drehencodertask(int A,int B)
{
static int enc_last=0,enc_delta=0;
    char i = 0;

    if (A) i = 1;
    if (B) i ^= 3;
    i -= enc_last;
    if (i & 1)
    {
        enc_last += i;
        enc_delta += (i & 2) - 1;
    }
    return enc_delta;
}

Bei meinem Drehencoder (mechanisch) ändert sich enc_delta von Rast zu 
Rast Stellung jeweils um 4. Das kann bei Dir anders sein. Ergebnis würde 
mich interessieren.

Bei Dir einfach in loop() folgende Zeile:
Serial.println 
(drehencodertask(digitalRead(encoder0PinA),digitalRead(encoder0PinB));

von Peter (Gast)


Lesenswert?

Martin B. schrieb:
> Bei meinem Drehencoder (mechanisch) ändert sich enc_delta von Rast zu
> Rast Stellung jeweils um 4. Das kann bei Dir anders sein. Ergebnis würde
> mich interessieren.

Ist bei mir genauso.

von Martin B. (ratazong)


Lesenswert?

Peter schrieb:
> Ist bei mir genauso.

Das ging ja schnell. Danke für den Test.

Solltest Du verwenden können, wenn Du enc_delta um 2 shiftest. Ich 
initialisiere Enc_deta mit 2, weil der Encoder bei manchen 
Raststellungen die Kontakte nicht sauber stehen. Dann gibts beim shiften 
weniger Fehler.


P.S.
Der Code ist schwer verständlich, weil optimiert. Nur eine if Abfrage!

von Peter (Gast)


Lesenswert?

Martin B. schrieb:
> Solltest Du verwenden können, wenn Du enc_delta um 2 shiftest.

Wie genau mache ich das? :D

von Martin B. (ratazong)


Lesenswert?

Peter schrieb:
> Martin B. schrieb:
>> Solltest Du verwenden können, wenn Du enc_delta um 2 shiftest.
>
> Wie genau mache ich das? :D

Ups, ganz am Anfang? Mit dem Shiftoperator.

encoder0Pos = enc_delta >> 2;

von Peter (Gast)


Lesenswert?

Shiftoperator habe ich noch nie verwendet. Ich stehe grade etwas auf dem 
Schlauch.
1
int encoder0PinA = 2;
2
int encoder0PinB = 3;
3
int encoder0Pos = 0; 
4
5
void setup()
6
{
7
  Serial.begin(9600);
8
  Serial.println("Ready\n0");
9
}
10
11
void loop()
12
{
13
  Serial.println(drehencodertask(digitalRead(encoder0PinA),digitalRead(encoder0PinB)));
14
  Serial.println(encoder0Pos);
15
}
16
17
int drehencodertask(int A,int B)
18
{
19
  static int enc_last=0,enc_delta=2; //vorher enc_delta=0
20
  char i = 0;
21
  encoder0Pos = enc_delta >> 2; 
22
23
    if (A) i = 1;
24
    if (B) i ^= 3;
25
    i -= enc_last;
26
    if (i & 1)
27
    {
28
        enc_last += i;
29
        enc_delta += (i & 2) - 1;
30
    }
31
    return enc_delta;  
32
}

Wo ist "ganz am Anfang", außerhalb von int drehencodertask(int A,int B) 
geht es ja nicht oder doch?

"Ich initialisiere Enc_deta mit 2", also static int 
enc_last=0,enc_delta=2;?

von Peter (Gast)


Lesenswert?

So, neue Erkenntnis, ich habe den folgenden Code und die Libary dazu 
verwendet.
1
/* Encoder Library - TwoKnobs Example
2
 * http://www.pjrc.com/teensy/td_libs_Encoder.html
3
 *
4
 * This example code is in the public domain.
5
 */
6
7
#include <Encoder.h>
8
9
// Change these pin numbers to the pins connected to your encoder.
10
//   Best Performance: both pins have interrupt capability
11
//   Good Performance: only the first pin has interrupt capability
12
//   Low Performance:  neither pin has interrupt capability
13
Encoder knobLeft(2,3);
14
15
void setup()
16
{
17
  Serial.begin(9600);
18
  Serial.println("Encoder Test:");
19
}
20
21
long positionLeft  = -999;
22
23
void loop() {
24
  long newLeft;
25
  newLeft = knobLeft.read();
26
  if (newLeft != positionLeft)
27
  {
28
    Serial.print("Left = ");
29
    Serial.print(newLeft);
30
    Serial.println();
31
    positionLeft = newLeft;
32
  }
33
  // if a character is sent from the serial monitor,
34
  // reset both back to zero.
35
  if (Serial.available())
36
  {
37
    Serial.read();
38
    Serial.println("Reset knobs to zero");
39
    knobLeft.write(0);
40
  }
41
}

Wenn ich mal schneller und mal langsamer drehe, habe ich wieder eine 
Differenz von 4, mal von 20, mal von 60. Je nachdem wie oft ich drehe.

Verwende ich nun aber die neg. Kontakte also A Strich und B Strich, kann 
ich 3x, 10x oder auch 20x in unterschiedlichen Geschwindigkeiten drehen, 
stelle ich den Encoder dann wieder auf Null (Skala), steht im 
SerialMonitor auch wirklich 0...

Ist also ein Hardwaredefekt/-problem.

Dennoch würde mich das mit dem Shiftoperator interessieren.

von Martin B. (ratazong)


Lesenswert?

Peter schrieb:
> Wenn ich mal schneller und mal langsamer drehe, habe ich wieder eine
> Differenz von 4, mal von 20, mal von 60. Je nachdem wie oft ich drehe.
>
> Verwende ich nun aber die neg. Kontakte also A Strich und B Strich, kann
> ich 3x, 10x oder auch 20x in unterschiedlichen Geschwindigkeiten drehen,
> stelle ich den Encoder dann wieder auf Null (Skala), steht im
> SerialMonitor auch wirklich 0...
>
> Ist also ein Hardwaredefekt/-problem.
>
> Dennoch würde mich das mit dem Shiftoperator interessieren.

Irgendwie hast Du doch jetzt eine Lösung. Verwende A' und B'

Die Ausgänge des Encoders müssen halt zum Decoderalgorithmus passen. Da 
muss man manchmal einfach spielen oder probieren.

Du bekommst jetzt immer Vielfache von 4, weil der Encoder das halt so 
macht. Von Rast zu Raststellung ändern A,B halt viermal ihren Zustand. 
Damit Du 1,2,3,4.... rausbekommst, musst Du halt einfach durch 4 teilen 
oder eben um 2 (nach rechts) shiften.
Um 2 (nach rechts) shiften teilt für positive Zahlen durch 4. Das musst 
Du Dir mal in einem Grundlagenbuch "C lernen" mal angucken. Es gibt 
einen kleinen Unterschied zwischen shiften und Teilen für negative 
Zahlen.
Dreh mal den Encoder von der Nullstellung nach links. Dann müsstest Du 
negative Zahlen bekommen. (-4,-8,-12 . . .)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.