Forum: Compiler & IDEs Drehencoderauswertung alternative


von Steffen K. (fenert)


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++;
    }

  }

von P. S. (Gast)


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.

von Steffen K. (fenert)


Lesenswert?

Was bitte stört dich an den Variablen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Norbert (Gast)


Lesenswert?

Hübsch unübersichtlich dein Code!

von Steffen K. (fenert)


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!

von was-willst-du (Gast)


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?

von ... (Gast)


Lesenswert?

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

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

von Steffen K. (fenert)


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.
1
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.
1
m = (k^(k>>1)&0x55);
1
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...)
1
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.
1
m = (e^(e>>1)&0x55);
1
m |= (m<<1);
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.
1
for (i=0; i<=3; i++){
2
    if (e & 0x03){
3
      set_MOT_inkrement(i, (get_MOT_inkrement(i) + ((e & 0x02) - 1)));
4
    }
5
    e>>2;
6
  }

In dieser For-schleife werden die ermittelten Werte mit dem alten 
inkremnetalwert verrechnet und entweder 1 addiert oder subtrahiert
(
1
set_MOT_inkrement (...)
 und
1
get_MOT_inkrement(...)
sind Funktionen zum Inkrmentspeichern und -auslesen).
1
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

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.