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++; } }
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.
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.
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!
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?
... und die entsprechenden, hier im Forum dafür vorgesehenen Formatierungstags währen auch nicht schlecht. http://www.mikrocontroller.net/articles/Formatierung_im_Forum
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.