Pages: 1 [2] 3   Go Down
Author Topic: Magnetische Encoder auswerten  (Read 2969 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 147
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo Dani,
ich habe heir einmal die Encoderauswertung:

void doEncoderA(){

  // look for a low-to-high on channel A
  if (digitalRead(encoder0PinA) == HIGH) {
    // check channel B to see which way encoder is turning
    if (digitalRead(encoder0PinB) == LOW) { 
      encoder0Pos = encoder0Pos + 1;         // CW
    }
    else {
      encoder0Pos = encoder0Pos - 1;         // CCW
    }
  }

  else   // must be a high-to-low edge on channel A                                       
  {
    // check channel B to see which way encoder is turning 
    if (digitalRead(encoder0PinB) == HIGH) {   
      encoder0Pos = encoder0Pos + 1;          // CW
    }
    else {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }
  }
}

void doEncoderB()
{
  // look for a low-to-high on channel B
  if (digitalRead(encoder0PinB) == HIGH)
  {   
    // check channel A to see which way encoder is turning
    if (digitalRead(encoder0PinA) == HIGH)
    { 
      encoder0Pos = encoder0Pos + 1;         // CW
    }
    else
    {
      encoder0Pos = encoder0Pos - 1;         // CCW
    }
  }

  // Look for a high-to-low on channel B

  else {
    // check channel B to see which way encoder is turning 
    if (digitalRead(encoder0PinA) == LOW) {   
      encoder0Pos = encoder0Pos + 1;          // CW
    }
    else {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }
  }
  //  encoder0PosLast = encoder0Pos;
  encoder0PosLast = encoder0Pos;     
}

Wenn Du eine bessere Auswertung kennst würde ich mich sehr freuen.

DrFlopp
Logged

0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3420
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bitte Code mit Code Tags einstellen, dann wird er so lesbar wie mein Beispiel unten.
Dein Code sieht irgendwie merkwürdig aus. Ich würde sowas eher in folgendem Stil implementieren:

Code:
int8_t decode(uint8_t pinA, uint8_t pinB)  {
    return (digitalRead(PinA) == digitalRead(PinB)?  -1:  1);
}

Position0 += decode(encoder0PinA, encoder0PinB);


« Last Edit: June 18, 2011, 10:21:42 am by Udo Klein » Logged

Check out my experiments http://blog.blinkenlight.net

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

....schau dir mal den Befehl increment und decrement an. Das wird schneller ausgeführt wie z.B. a=a+1

Versuch mal A auf einen Interrupteingang zu legen. (steigende Flanke auswerten)
http://arduino.cc/en/Reference/AttachInterrupt
B bleibt an irgendeinem Digitalpin

Wenn an Kanal A die Flanke steigt wird die Interruptroutine gestartet.

Dort prüfst du:
wenn Kanal B = LOW, dann ++encoder0Pos (increment)
ansonsten
--encoder0Pos (decrement)

die Variable encoder0Pos wird somit bei jeder ansteigenden Flanke erhöht oder verringert, je nach Drehrichtung.

Grüße, finu
Logged

0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3420
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bist Du Dir sicher, daß der Optimizer des GCC nicht schlau genug ist sowas wegzuoptimieren? Der Optimizer ist normalerweise so gut, daß er manchmal schnelleren Code erzeugt als der erste Anlauf in Assembler. Wenn der Funktionscalloverhead wirklich ein Problem ist kann man auch noch "inline" dranschreiben. Allerdings hat DrFlopp keine echten Performanceprobleme, sonst würde er nicht "digitalRead" nehmen. Das ist die Stelle die man zuerst optimieren müsste.
« Last Edit: June 18, 2011, 10:22:43 am by Udo Klein » Logged

Check out my experiments http://blog.blinkenlight.net

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 smiley-roll-blue Aua, mein Post hat einen Fehler. Bei der Drehrichtungsänderung geht ein Puls verloren. Zum Ausprobieren ob deine Pegel (bzw. die vom Encoder  smiley-lol) ok sind reicht es aber aus.

@Udo
Wie schlau der Optimizer ist? Keine Ahnung, habe gerade erst mit dem Arduino angefangen.
Logged

0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3420
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@finu: das war eine rhetorische Frage / ein Wink mit dem Zaunpfahl. Der Optimizer des GCC ist besser als Du Dir vorstellen kannst. Insbesondere ist Dein Vorschlag völlig nutzlos. Selbstverständlich wird sowas vom GCC optimiert. Davon abgesehen zäumst Du das Pferd von hinten auf. Bei Performanceoptimierungen schaut man zuerst nach strukturellen Problemen, dann nach Algorithmusoptimierungen bzw. besseren Algorithmen und erst ganz am Schluß nach Codeoptimierungen. Jede andere Vorgehensweise ist ziemliche Zeitverschwendung.
Logged

Check out my experiments http://blog.blinkenlight.net

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Wink mit dem Zaunpfahl

Der Zaunpfahl hat sein Ziel getroffen  smiley-cry

Quote
Insbesondere ist Dein Vorschlag völlig nutzlos

Grrrrrr, stimmt. Habe es ausprobiert.
++a versus a=a+1 bringt keinen Zeitvorteil.

http://www.mikrocontroller.net/articles/Drehgeber
...hier findet man einen interessanten Artikel zu Drehgebern. Dort wird auch das Thema Auswertung behandelt.

Grüße, finu
Logged

AREA COLOGNE
Offline Offline
Edison Member
*
Karma: 15
Posts: 1069
I am 1 of 10 who understands binary
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

=> Ganz Ganz Wichtig Interrupt Funktionen so kurz wie möglich halten <=

Ich schmeiße mal meinen Code hier rein:
Code:
void setup (){
  attachInterrupt(0,CHAInt,CHANGE);        // Interrupt 0 führt CHAInt aus mit wechslende Flanken
  pinMode(2,INPUT);                               // Pin2 als Input
  pinMode(3,INPUT);                               // Pin3 als Input
  digitalWrite(2,HIGH);                            // Interne Pull Ups benutzt
  digitalWrite(3,HIGH);                            // Interne PullUps benutzt
}

void CHAInt (){
  int Aread=0;
  int Bread=0;
  Aread=digitalRead(A);
  Bread=digitalRead(B);
  if (Aread==HIGH && Bread==LOW||Aread==LOW && Bread==HIGH){
    Wert++;
  }
  if (Aread==LOW && Bread==LOW ||Aread==HIGH&& Bread==HIGH){
    Wert--;
  }
}
Logged

So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3420
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Warum nicht so:

Code:
void setup (){
  attachInterrupt(0,CHAInt,CHANGE);        // Interrupt 0 führt CHAInt aus bei wechslende Flanken
  // pins pullup aktivieren
  pinMode(PinA, INPUT);                          
  digitalWrite(PinA, HIGH);   
  pinMode(PinB, INPUT);                          
  digitalWrite(PinB, High);                          
}

void CHAInt (){
  Wert+= (digitalRead(PinA) == digitalRead(PinB)? -1: 1);
}

Problem bei der ganzen Sache ist, daß es in diesem Code eine üble Race Condition gibt. Und zwar: es gibt keine Garantie, daß der Zustand der Pins zum Auslesezeitpunkt so ist wie zum Auslösezeitpunkt des Interrupts. Außerdem werden beide Pins zu verschiedenen Zeiten ausgelesen. Um das zu kompensieren wird man sich den Portzustand "atomar" holen und puffern müssen. D.h. man muß direkt auf die Ports. Dadurch wird die ISR aber auch performanter.

Sobald ich etwas Zeit habe überlege ich mal wie man das korrekt implementiert. So sieht es nur richtig aus wird aber bei starkem Rauschen garantiert nicht sauber funktionieren.
« Last Edit: June 19, 2011, 07:22:37 am by Udo Klein » Logged

Check out my experiments http://blog.blinkenlight.net

AREA COLOGNE
Offline Offline
Edison Member
*
Karma: 15
Posts: 1069
I am 1 of 10 who understands binary
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Komisch Udo wenn ich dich so höre, könnte man den Eindruck gewinnen das alle das hier falsch machen bis auf Einen. smiley-wink
Probiere es mal aus und es funktioniert so ohne Probleme.
Logged

So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3420
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@Volvodani: Klar funktioniert das wenn Du es einfach so probierst. DrFlopp hatte aber was von starkem Rauchen geschrieben und dann funktioniert das nicht mehr. Hast Du das mit verrauschten Signalleitungen probiert oder glaubst Du nur, daß es dann auch funktioniert?

Vieleicht liegt es ja auch daran, daß Ihr es tatsächlich falsch macht? smiley-wink

Nur mal so: was macht der Code bei folgendem Timing:
Code:
Pin A: 0 1 0 1 0 0 0 0 0
Pin B: 0 0 1 1 0 0 0 0 0

Zeit:  0 1 2 3 4 5 6 7 8
         

Und was bei folgendem Timing

Code:
Pin A: 0 1 0 1 0 0 0 0 0
Pin B: 0 0 1 1 1 0 0 0 0

Zeit:  0 1 2 3 4 5 6 7 8
   

In beiden Fällen:

0 = Ausgangssituation
1 = Interrupt triggert und ISR startet
2 = Interrupt triggert wird aber gequeued weil ISR noch nicht fertig
3 = Interrupt triggert wird aber nicht gequeued weil ISR schon läuft und ein IR bereits in der Queue ist
4 = Pin A wird gelesen
5 = Pin B wird gelesen
6 = ISR fertig, aufgelaufener Interrupt startet ISR erneut
7 = Pin A wird gelesen
8 = Pin B wird gelesen

Was wäre das erwartete Ergebniss gewesen?

Ich glaube ohne geeignete externe Beschaltung kann man sowas bei verrauschten Signalen nicht zuverlässig hinbekommen. Wenn man hingegen kein Rauschen hat, dann funktioniert der Code auch.
« Last Edit: June 19, 2011, 07:55:17 am by Udo Klein » Logged

Check out my experiments http://blog.blinkenlight.net

Offline Offline
Full Member
***
Karma: 0
Posts: 147
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@Dani, Also ich habe Deinen Code ausprobiert. Der liefert aber keine Position sondern nur irgend einen Wert wenn sich der Encoder dreht. Wenn der Encoder steht liefert der Code 0.
Da stimmt etwas noch nicht.
Gruß DrFlopp
Logged

AREA COLOGNE
Offline Offline
Edison Member
*
Karma: 15
Posts: 1069
I am 1 of 10 who understands binary
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Da du in der Main ja nicht weiterarbeitest mit der Funktion muss du aus
Wert++ bzw Wert--
++Wert bzw --Wert machen.
Ich werte nämlich bei mir nur die Beweung aus Linksrum halt minus rechtsrum halt Plus
Logged

So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

Offline Offline
Full Member
***
Karma: 0
Posts: 147
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo Dani,
das ist echt immerwieder verblüffend für mich als Neuling mit wie einfachen dingen man unter C dinge beeinflussen kann. Hast Du vielleicht auch noch einen Tipp um die Geschwindigkeit effizient zu berechnen?

Ich habe bei meiner Anwendung noch ein weiteres kleines Problem, ich steuer ein LCD an. Die LCD-Bibliothek benutzt glaube ich festgelegte Pinns, die sich mit den Interrupts überschneiden. Kann ich eigendlich jeden Pinn für die LCD-Anzeige konfigurieren? (Auch die Analogeingänge?)

Gruß
DrFlopp
Logged

AREA COLOGNE
Offline Offline
Edison Member
*
Karma: 15
Posts: 1069
I am 1 of 10 who understands binary
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Du kannst auch die Analog In nutzen A0-A5 =>digital 14-18
also erst als Ausgang deklarieren und dann digital "benutzten"
Logged

So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

Pages: 1 [2] 3   Go Up
Jump to: