mikrocontroller.net

Forum: Compiler & IDEs Drehencoderauswertung alternative


Autor: Steffen Kleinert (fenert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

wer vielleicht schon andere Beiträge von mir gelesen hat, weiß 
womöglich, woran ich derzeit arbeite. Ich habe jetzt eine Frage zum 
auswerten eines,bzw. in meinem speziellen Fall von 4 Drehencodern.
Die Drehgeber werden mit einer Interruptgesteuerten Frequenz von ca. 
8kHz ausgelesen. Hierzu wird das externe Speicherinterface verwendet. 
Die 8 Phasen der Inkremntalgeber liegen also als Datenbyte vor. Zunächst 
hatte ich die "klassische" Mehtode hier aus dem Forum verwendet und dazu 
das Byte entsprechend Maskiert (siehe unteren Quellcodeabschnitt). Um 
Die Auswertung jedoch zu beschleunigen habe ich mir jetzt eine 
alternative überlegt, bei der ich das Byte erst im allerletzten Schritt 
zerlege und eine weitestgehend auf Bitoperationen basierende Auswertung 
vornehme.
Ich möchte euch jetzt bitten, dass ihr mal über den Code schaut, ob er 
funktioniert und ob diese Methode wirklich schneller ist als meine alte 
Methode.

Danke
Steffen

// Zähler neu:

  uint8_t k,m,e,i;

    static uint8_t k_alt = 0xFF;

  uint8_t *p = (uint8_t *) (TREIBER_2);

  //Variablen auslesen:

  e_xmem ();
  k=*p;
  d_xmem ();

  e= k ^ k_alt;        // Vergleich des alten Graycodes mit dem neuen.
                       // Ergebnisswerte von '00' bis '11'.
                       // '00' bei keiner Änderung, '01' oder '10' bei
                       // Einzelschritten, '11' Bei unzulässiger
                       // Änderung.
                       // Wenn A =B mit A und B als Ausgänge des
                       // Inkrementalgebers, Rechts (positiv)  = '10'
                       // und Links = '01'.
                       // Wenn A!=B Rechts = '01' und Links = '10'
  m = (k^(k>>1)&0x55); // Maske zum A- und B-Vergleich,
                       // wenn A = B: Ergebniss '00',
  m |= (m<<1);         // wenn A != B: Ergebniss '11'.
  e ^= m;              // Invertieren der Werte wenn A != B
  m = (e^(e>>1)&0x55); // Maske zum ausblenden der unzulässigen Werte 
'11'.
  m |= (m<<1);
  e &= m2;             // Rechts (positiv) = '10', Links = '01',
                       // Null oder Unzulässig = '00'

  for (i=0; i<=3; i++){
    if (e & 0x03){
      set_MOT_inkrement(i, (get_MOT_inkrement(i) + ((e & 0x02) - 1)));
    }
    e>>2;
  }
  k_alt = k;


// Zähler alt:

  uint8_t i,j,k=0,m;
  uint8_t addr[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

  static uint8_t alt[4] = {1,1,1,1};

  uint8_t *p = (uint8_t *) (TREIBER_2);

  //Variablen auslesen:

  e_xmem ();
  i=*p;
  d_xmem ();


  for (m=0;m<=7;m++) {
      j = 0;

    //umwandeln Gray-code in Binärzahl:
      if( i & addr[m]) {                // wenn 1 an Stelle m dann...
        j = 1;
      }
    m++;
      if( i & addr[m]) {
        j ^= 3;                         // höherwertige Bit wird 
gesetzt,
                                        // niederwertiges invertiert.
      }

     j -= alt[k];                       // vergl. j=j-alt[k]

    if( j & 1 ) {                       // Wenn bit1 von l 
dann...Sprünge
                                        // über 2 Impulse, bzw keine
                                        // Änderung werden ignoriert.
      alt[k] += j;                      // alt[k] aktualisieren

// addition von 1/-1 bei links-/rechtslauf:
         set_MOT_inkrement(k,(get_MOT_inkrement(k)+((j&2)-1)));

      }
    k++;
    }

  }

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steffen Kleinert wrote:

>   uint8_t k,m,e,i;

Sorry, aber genau hier hoere ich schon auf, deinen Code zu lesen. Das 
ganze sieht eher aus wie ein Makroassembler als wie C.

Autor: Steffen Kleinert (fenert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was bitte stört dich an den Variablen?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steffen Kleinert wrote:
> Was bitte stört dich an den Variablen?

Dass die Namen keinerlei Aussagewert haben und man sich die gedachte
Funktion umständlich aus dem Code erschließen muss.

Wenn ich schon Code reviewe, dann möchte ich gern aus dem Code die
gedachte Funktion ersehen können, sodass der Review sich dann darauf
konzentrieren kann, ob die tatsächliche Implementierung auch der
Aufgabe entspricht.

Autor: Norbert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hübsch unübersichtlich dein Code!

Autor: Steffen Kleinert (fenert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
k ist das Inkrementbyte,
m sind Masken
e ist das Ergebnis der Auswertung
i Standardzähler

gut ich hätts vielleicht etwas übersichtlicher benennen können. Das 
passiert halt wenn man die ganze Zeit über seinem eigenen Code sitzt!

Autor: was-willst-du (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ganz schick wärs noch, wenn Du verbal beschreiben könntest was Dein 
Programm machen soll. Dann kann man sich doch viel leichter reindenken.


Hast Du es schon laufen lassen? Ergebnis?

Autor: ... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... und die entsprechenden, hier im Forum dafür vorgesehenen 
Formatierungstags währen auch nicht schlecht.

http://www.mikrocontroller.net/articles/Formatieru...

Autor: Steffen Kleinert (fenert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut, dann beschreibe ich noch ausführlich was das programm machen soll.

Der Untere Bereich (//Zähler alt:) ist eine angepasste Anwendung der 
hier im Forum vorgestellte Methode um Drehgeber auszuwerten: 
Beitrag "Drehgeber auslesen" . Bei dieser Methode wird 
der Graycode von den Inkrementalgebern in Binäre Zahlen umgewandelt und 
verrechnet. Ich musste dieses System anpassen, da ich 4 Drehgeber über 
einen oktalpuffer mit dem externen Speicherinterface abfrage.
Die Alternative die ich mir überlegt habe wandelt den Graycode nicht in 
Binärzahlen um sonder vergleicht direkt den alten Graycode mit dem 
neuen.
e= k ^ k_alt;

Diese Zeile liefert Bit=1 falls eine Änderung zum Letzten Zyklus an 
dieser Bitposition vorliegt. Haben sich zwei benachbarte Bits (0&1, 
2&3,...Anschlusse der Inkrementakgeberphasen) geändert, ist das 
Ergebniss '11' und unzulässig. Keine Änderung führt zu '00' Diese Beiden 
Ergebnisse dürfen zu keiner Änderung des Inkrementalzählers führen.
Die Ergebnisse '01' und '10' sind zulässige Änderungen. Sagen jedoch 
alleine nichts über die Drehrichtung aus. Hirzu müssen die Zustände der 
Bits beim Auslesen überprüft werden. Sind Beide benachbarten Bits 
gleich, Also entweder '00' oder '11' ist eine Änderung des höherwertigen 
Bits einer Rechtsdrehung zuzuordnen, Ergebnis e= ...'10'... und demnach 
eine Linksdrehung e= ...'01'... . Sind die benachbarten Bits ungleich 
ist es umgekehrt.
Um die Zustände auf eine gemeinsame Form zu bringen, in der 
Rechtsdrehungen als '10' dargestellt werden und Linksdrehungen als '01' 
müssen die die Stellen im Ergebnissbyte invertiert werden an denen Beide 
Eingangsbits nicht geich sind.
m = (k^(k>>1)&0x55);
m |= (m<<1);

Diese zwei Zeilen erstellen eine Maske die ausgehend vom Eingabebyte 
bestimmte Bits im Ergebnissbyte invertiert. Beispiel:

k = 00'01'11'10 = A3B3'A2B2'A1... mit A und B Pahsen der 
Inkrementalgeber

     00'01'11'10
  ^   0'00'11'11'0
  =  00'01'00'01
  &  01'01'01'01
m =  00'01'00'01
  | 000'10'00'1
m =  00'11'00'11  Beide Bitstellen '1' wenn An ungleich Bn (n=0,1,2...)
e ^= m;

Anwendung der Maske zum Invertieren bestimmter Bitstellen.
Bleiben noch die unzulässigen Werte '11' diese sollen ebenfalls auf die 
Form '00' gebracht werden, wozu nochmals eine Maske in selber Weise 
erstellt wird, nur das hier das Ergebnisbit verwendet wird.
m = (e^(e>>1)&0x55);
m |= (m<<1);
e &= m;

Diese drei Programmzeilen erstellen eine Maske, die wenn beide 
benachbarten Bits identisch sind, also '00' oder '11' an deren Stelle in 
der Maske '00' schreibt und im Ergebnisbit '11' in '00' ändert.
for (i=0; i<=3; i++){
    if (e & 0x03){
      set_MOT_inkrement(i, (get_MOT_inkrement(i) + ((e & 0x02) - 1)));
    }
    e>>2;
  }

In dieser For-schleife werden die ermittelten Werte mit dem alten 
inkremnetalwert verrechnet und entweder 1 addiert oder subtrahiert
(
set_MOT_inkrement (...)
 und
get_MOT_inkrement(...)
sind Funktionen zum Inkrmentspeichern und -auslesen).
k_alt = k;

aktualiseiren des alten abgespeicherten Graycodes.


Ich hoffe meine Absichten sind klarer geworden. Testen konnte ich das 
Programm noch nicht, da ich heute keine Zeit hatte zur Uni zu fahren. 
Aber ich bin gespannt wie´s morgen läuft. Die wichtigste Frage für mich 
ist eigenlich, ob dieser Code schneller abgearbeitet wird, als die hier 
Beitrag "Drehgeber auslesen" verwendete Methode vor 
allem da es sich um 4 Encoder auf einmal handelt.

Gruß
Steffen

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.