Guten Tag, nachdem ich bei meinem Projekt einfach nicht weiterkomme, wollte ich mal die Community um Rat fragen. Zur Auslese von Linearencodern mit Quadratursignal bin ich auf den Forumsbeitrag von Peter Dannegger (https://www.mikrocontroller.net/articles/Drehgeber) gestoßen. Um meinen Atmega nicht unnötig zu belästigen habe ich die Idee im Text: "Dekoder mit diskreten Logik-ICs" aufgegriffen. Meine -wohl zu naive- Vorstellung war, dass der "Clock Enable" Ausgang [nur] gültige Pulse produziert (also Prellen unterdrückt wird) und "Direction" angibt ob der Puls den Positionswert in- bzw. dekrementiert. In meinem Aufbau füttere ich das Eingang-Clock Signal der Schaltung mit der Frequenz meines Atmega644 Quarzes per CKOUT Pin. (Baudquarz 11,0592 MHz). Die Quadratursignale A und B liegen ebenfalls an und haben im Oszilloskop sichtbar den gewünschten 5V Hub. Die benötigten Chips 74HC174 und 74HC86N sind bei 5V Betrieb schnell genug um so ein Clocksignal zu verdauen und im Oszilloskop sehe ich dass dann die entsprechenden Pulse am Ausgang von "Clock Enable" und "Direction" ankommen. Ein Herunterregeln des Clocksignales ("Div 8") ändert nichts am prinzipiellen Verhalten. Zur Auslese verwende ich einen Atmega644. Bei ansteigender Flanke von "Clock Enable" in den INT0 pin starte ich eine ISR. In der ISR prüfe ich sofort den Pin an dem "Direction" anliegt und bei '1' füge ich meinem Zähler einen Puls hinzu, bei '0' ziehe ich ihn ab. Leider zeigt sich aber dass mein Zähler immer nur in eine Richtung zählt, egal ob ich meinen Encoder nach "links" oder "rechts" bewege, wird also der Zählerwert ständig inkrementiert, die Richtung wird also nicht berücksichtigt. Das Verhalten der "Clock Enable" und "Direction" Pulse im Oszilloskop legt dieselbe Interpretation nahe. Wahrscheinlich liegt also in meinem Verständnis der Schaltung ein fundamentaler Fehler vor, zumal der Satz: "Ausserdem handelt es sich bei CE um ein Clock Enable Signal, nicht um einen Takt, siehe Taktung FPGA/CPLD." meine Verwirrung noch erhöht, ich verstehe ihn schlicht nicht. Also: hat von euch irgend jemand die angegebene Hardware Realisierung schon probiert und die genaue Bedeutung bzw. richtige Benutzung von "Clock Enable" und "Direction" im Schaltkreis verstanden bzw sinnvoll genutzt ? Danke: Hermann
Ist die ISR zu langsam? Quasi - IRQ kommt - Direction steht an - IRQ-Routine wird gestartet - nächster Takt am Dekoder sagt "keine Änderung zu eben" = Takt davor - IRQ-Routine fragt Direction ab = ungültig Der Takt muss soweit ich das verstehe nur wenige Male schneller als die Encoderrate sein. Selbst mit 11MHz:8 = Hausnummer 1,5MHz könntest du also locker 500000 Steps pro Sekunde erfassen, wenn der Prozessor schnell genug wäre, eher Richtung 1Mio. Muss das sein?
:
Bearbeitet durch User
Btw, nicht alle Encoder sind gleich. Code und schaltplan könnten helfen oder wir raten munter
Hermann E. schrieb: > Zur Auslese von Linearencodern mit Quadratursignal bin ich auf den Wie schnell soll der abgetastet werden? > "Dekoder mit diskreten Logik-ICs" aufgegriffen. > Meine -wohl zu naive- Vorstellung war, dass der "Clock Enable" Ausgang > [nur] gültige Pulse produziert Das tut er, denn das Signal kommt direkt aus einem FlipFlop. > (also Prellen unterdrückt wird) Dort prellt nix. > "Direction" angibt ob der Puls den Positionswert in- bzw. dekrementiert. Auch das tut er, wenn gleich der Puls aus Sparsamkeit der Dekoderlogik nur im Zusammenhang mit Clock enable gültig ist. > In meinem Aufbau füttere ich das Eingang-Clock Signal der Schaltung mit > der Frequenz meines Atmega644 Quarzes per CKOUT Pin. (Baudquarz 11,0592 > MHz). Kann man machen. > Zur Auslese verwende ich einen Atmega644. > Bei ansteigender Flanke von "Clock Enable" in den INT0 pin starte ich > eine ISR. AUA! Was soll das? Warum glaubst, daß damit deine Dekodierung schneller ist, wenn du es doch wieder per ISR und Software machst? Dieser Hardwaredekoder ist dafür da, bei hohen Taktfrequenzen direkt einen Hardwarezähler zu steuern! > In der ISR prüfe ich sofort den Pin an dem "Direction" anliegt > und bei '1' füge ich meinem Zähler einen Puls hinzu, bei '0' ziehe ich > ihn ab. Fail. Siehe oben! > Leider zeigt sich aber dass mein Zähler immer nur in eine Richtung > zählt, egal ob ich meinen Encoder nach "links" oder "rechts" bewege, > wird also der Zählerwert ständig inkrementiert, die Richtung wird also > nicht berücksichtigt. Das Verhalten der "Clock Enable" und "Direction" > Pulse im Oszilloskop legt dieselbe Interpretation nahe. Dann ist wohl was falsch verdrahtet. Ach ne, dein Takt ist ja 11,x MHz. D.h., das sowohl das CE-Signal als auch das DIR Signal immer nur für EINEN Takt gültig sind! Das bekommt dein AVR und auch jede andere normale CPU nicht per externem Interrupt und Software ausgewertet! " Zu beachten ist, dass das Signal DIRECTION nur gültig ist, wenn das Signal CE aktiv (= HIGH) ist." > Wahrscheinlich liegt also in meinem Verständnis der Schaltung ein > fundamentaler Fehler vor, zumal der Satz: > "Ausserdem handelt es sich bei CE um ein Clock Enable Signal, nicht um > einen Takt, siehe Taktung FPGA/CPLD." meine Verwirrung noch erhöht, ich > verstehe ihn schlicht nicht. Man darf das CE NICHT direkt an den Takteingang eines Zählers anschließen sondern nur an den CE-Eingang! Der Takt für Dekoder und Zähler wird direkt mit der Taktquelle verbunden. > Also: hat von euch irgend jemand die angegebene Hardware Realisierung > schon probiert und die genaue Bedeutung bzw. richtige Benutzung von > "Clock Enable" und "Direction" im Schaltkreis verstanden bzw sinnvoll > genutzt ? Ich hab die Schaltung erfunden, wenn gleich real nicht aufgebaut. Manchmal reicht auch eine Simulation ;-) Diese Schaltung soll einen Zähler füttern, z.B. einen HEF4029. Siehe Anhang. Wenn man das an einen Mikrocontroller anflanschen will, braucht man einen, der einen externen Takt- und Richtungseingang hat. Ich kenn da aber keinen. Es gibt allerdings Typen mit integriertem Quadraturdekoder in Hardware im Controller, z.B. ATXmega, diverse STM32 und viele andere.
Hermann E. schrieb: > "Ausserdem handelt es sich bei CE um ein Clock Enable Signal, nicht um > einen Takt, siehe Taktung FPGA/CPLD." meine Verwirrung noch erhöht, ich > verstehe ihn schlicht nicht. Dabei ist es doch so einfach: Clock Enable ist kein Clock. Clock hast du ja reingespeist, das ist dein Clock. Wenn du aus Clock und Clock Enable ein getaktetes Clock machen willst, brauchst du noch ein externes UND-Gatter
1 | Clock--------| \ |
2 | | )-- gatedClock |
3 | ClockEnable--| / |
ABER: Clock mit vollen 11MHz in einen AVR zur Interruptbearbeitung reinzustecken, ist doch wohl leicht erkennbar völliger Unsinn, selbst CLK/8 hilf da nicht, die Interrupt-Routine wird mehr als 8 Befehle rauchen. Eher so CLK/100 wird die maximale Interruptfrequenz sein, der der AVR noch folgen kann - je nach dem wie effizient deine Interupt-Routine ist, /100 geht in Assembler, in C /1000, bei Arduino eher /10000.
Das war schnell ! Erst mal vielen Dank für die schnelle Reaktion. Bei meinen Sensoren handelt es sich um Heidenhain Encoder wie zB. der LS477, also 'allererste Sahne' ! (Siehe angeheftete Kopie). Leider habe ich erst heute Abend Zeit auf alle Kommentare zu reagieren, daher bitte Geduld. Nur ein Punkte schon vorab: Der Grund warum ich diese Schaltung (und nicht den uC direkt) verwenden wollte war meinen uC nicht mit unnötigen Interrupts zu belasten die entstehen wenn der Encoder stillsteht und ein Quadraturkanal (A oder B) "auf der Kante" sitzt. Schließlich muss der uC noch das Display mit der Position ansteuern, Endswitches überwachen und bei weiterem Fortgang meines Projektes noch mehr. Mehr heute Abend: Hermann
Hermann E. schrieb: > Der Grund warum ich diese Schaltung (und nicht den uC direkt) verwenden > wollte war meinen uC nicht mit unnötigen Interrupts zu belasten Ach der Arme!!! Ist das ein 8051 mit 100kHz anno 1800? >die > entstehen wenn der Encoder stillsteht und ein Quadraturkanal (A oder B) > "auf der Kante" sitzt. Nö. Mit der richtigen Auswertung (tm), passiert da rein gar nichts. Nicht mehr als bei maximaler Zählfrequenz am Eingang. https://www.mikrocontroller.net/articles/Drehgeber#Warum_Sparvarianten_nicht_gut_sind > Schließlich muss der uC noch das Display mit der > Position ansteuern, Endswitches überwachen und bei weiterem Fortgang > meines Projektes noch mehr. Klingt nach Pille-Palle für jeden mittelmäßigen Controller mit einer Handvoll MHz und gescheitem Softwarekonzept. Siehe Multitasking. Ein kleiner AVR mit 20 MHz kann locker nebenbei eine 50kHz ISR laufen lassen, auch in C. Die braucht dann für deine Dekoderauswertung geschätzt 100 Takt / 20us, macht ~25% CPU-Last. Das ist OK. Wer da was trimmen will schreibt eine ISR in Assembler, die braucht weniger als die Hälfte, macht dann vielleicht 10% CPU-Last. Das ist schon fast vernachlässigbar. Diverse andere uC können das mit 0,0% CPU Last mit integriertem Hardwaredekoder.
Hermann E. schrieb: > Der Grund warum ich diese Schaltung (und nicht den uC direkt) verwenden > wollte war meinen uC nicht mit unnötigen Interrupts zu belasten die > entstehen wenn der Encoder stillsteht und ein Quadraturkanal (A oder B) > "auf der Kante" sitzt. Absolut niemand der noch bei Sinnen ist wird einen Encoder auf diese Art mit Interrupts auswerten. Daher sind deine ganzen Befürchtungen und die abstrusen Methoden auch noch mit wahnwitzigem Hardwareaufwand zur Umgehung völliger Quatsch. http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29
Bei deinem Ansatz muss die Periodendauer des Takts länger sein als die längstmögliche Bearbeitungszeit des Interrupts. Bei den von dir verwendeten 11 MHz hat sich das DIR-Signal bis zum Eintritt in die Interruptroutine längst wieder geändert, so dass du meist einen falschen Wert lesen wirst. Hermann E. schrieb: > Ein Herunterregeln des Clocksignales ("Div 8") ändert nichts am > prinzipiellen Verhalten. Das ist schon besser, aber vermutlich immer noch zu schnell. Ein langsameres Taktsignal kannst du mit einem Timer erzeugen. Wenn die Sache dann immer noch nicht funktioniert, hast du irgendwo einen Softwarefehler. Hermann E. schrieb: > Der Grund warum ich diese Schaltung (und nicht den uC direkt) verwenden > wollte war meinen uC nicht mit unnötigen Interrupts zu belasten die > entstehen wenn der Encoder stillsteht und ein Quadraturkanal (A oder B) > "auf der Kante" sitzt. Schließlich muss der uC noch das Display mit der > Position ansteuern, Endswitches überwachen und bei weiterem Fortgang > meines Projektes noch mehr. Die Rechenleistung des µC muss für die Bearbeitung von Encoder, Display, Endschalter und die anderen Dinge selbst dann ausreichen, wenn alle maximal aktiv sind. Reicht sie nicht aus, kann es bspw. passieren, dass die Endschalter nicht rechtzeitig erfasst werden, was zu einem Versagen des Systems führen kann. Du versuchst jetzt, die mittlere Belastung durch die Interrupts zu reduzieren, ohne dabei an der maximalen Belastung viel zu ändern¹. Damit versagt das System bei zu schwach dimensioniertem µC immer noch, nur seltener. Die Timer-Methode zur Encoderauswertung braucht zwar ständig etwas Rechenleistung, aber zum einen ist der Rechenzeitverbrauch sehr gering, zum anderen ist er konstant, so dass er leichter eingeplant werden kann. Deswegen würde ich mir den ganze Aufwand mit der externen Logik sparen und das Problem so lösen, wie es auch alle anderen tun. Einen praktischen Vorteil bildet die externe Schaltung nur, wenn auch das Zählen extern geschieht (durch ein Up/Down-Counter-IC mit Latch). Dadurch steigt der Hardwareaufwand aber weiter, und du brauchst mehr I/O-Pins am µC um den Zählerstand einzulesen. So eine Hardwarelösung kann dennoch sinnvoll sein, nämlich dann, wenn du den Sensor mit hohen Vorschubgeschwindigkeiten betreibst, so dass die Auswertung nur durch Software zu langsam ist. —————————————— ¹) Bei einem Auswertetakt im Megahertzbereich ist die maximale Belastung sogar noch deutlich höher als bei der klassischen Methode mit den Timerinterrupts, wo typischerweise mit deutlich niedrigeren Taktraten gearbeitet wird.
Sodele... Nach Lektüre des Kommentars von B. Falk (= P. Dannegger ?) wird mir klar warum das so nicht gehen kann. Vielleicht würde es Sinn machen das Bild mit dem Zählregister dem Ursprungsartikel hinzuzufügen um das Verständniss für Unbedarfte wie mich zu erleichtern. Ein anderer Punkt der zu meinem (Un-) Verständniss beitrug war die 'Unschärfe der Clockfrequenz' welche, so die Aussage "von nahezu jeder beliebigen Quelle erzeugt werden kann". Dies soll keine Fundamentalkritik am Artikel sein (der ansonsten sehr gut geschrieben ist !) sondern nur ein Feedback von Laien wie mich. Nur als rein philosophischer Kommentar meinerseits: Grundsätzlich erschien mir die Möglichkeit mich nur um die "guten Pulse" kümmern zu müssen verführerischer als "ständig nachzuschauen", aber wenn es nicht geht, geht's halt nicht. Vielen Dank auch für die geduldige und detaillierte Antwort von 'Yalu X.'. Die sinnvolle Betrachtung zwischen mittlerer Auslastung und Spitzenauslastung werde ich mir zu Herzen nehmen. In der Zwischenzeit habe ich mir mal das Timing meiner Quadraturpulse A/B mit dem Oszi angesehen indem ich per Hand den Encoder ungefähr mit der Geschwindigkeit mit der ich ihn betreiben will verschoben habe. Ich komme dabei auf Kantenabfolgen von 1-2 us herunter. dh zum hohen Wert aufgerundet rund 1Mhz. Da befürchte ich dass der AVR beim Abtasten ins Schwitzen geraden dürfte wenn ich mal > Nyquist mit 5 Mhz als Abtastfrequenz veranschlage ?!. In diesem Fall wird die Hardwarelösung dann vielleicht doch wieder interessant indem ich den (4029 o.ä. bzw schneller) Counter mit dem AVR auslese. Last not least haben diese Encoder eine Auflösung die ich im Grunde gar nicht brauche. Ich habe auch noch andere davon wo das ursprüngliche Sinus-Signal auswählbar (per DIL Schalter) interpoliert wird. So könnte ich auch die Interpolation veringern, da ich nur eine Auflösung von 30-50 um benötige.
Hermann schrieb: > Sodele... > > Nach Lektüre des Kommentars von B. Falk (= P. Dannegger ?) Nein, das sind 2 verschiedene Personen. > wird mir klar > warum das so nicht gehen kann. Vielleicht würde es Sinn machen das Bild > mit dem Zählregister dem Ursprungsartikel hinzuzufügen um das > Verständniss für Unbedarfte wie mich zu erleichtern. Ein anderer Punkt > der zu meinem (Un-) Verständniss beitrug war die 'Unschärfe der > Clockfrequenz' welche, so die Aussage "von nahezu jeder beliebigen > Quelle erzeugt werden kann". > Dies soll keine Fundamentalkritik am Artikel sein Und selbst wenn es das wäre, wäre das absolut kein Problem. Sachliche Kritik ist nicht nur erlaubt sondern ausdrücklich erwünscht! https://de.wikipedia.org/wiki/Kritikkompetenz (der ansonsten sehr > gut geschrieben ist !) sondern nur ein Feedback von Laien wie mich. OK. > In der Zwischenzeit habe ich mir mal das Timing meiner Quadraturpulse > A/B mit dem Oszi angesehen indem ich per Hand den Encoder ungefähr mit > der Geschwindigkeit mit der ich ihn betreiben will verschoben habe. Ich > komme dabei auf Kantenabfolgen von 1-2 us herunter. dh zum hohen Wert > aufgerundet rund 1Mhz. Da befürchte ich dass der AVR beim Abtasten ins > Schwitzen geraden dürfte Das schafft er nicht in Software. > wenn ich mal > Nyquist mit 5 Mhz als > Abtastfrequenz Nyquist hat hier nicht direkt was zu sagen. > In diesem Fall wird die Hardwarelösung dann vielleicht doch wieder > interessant indem ich den (4029 o.ä. bzw schneller) Counter mit dem AVR > auslese. Dann holst du dir andere Probleme an den Hals, nämlich die asynchrone Abtastung eines N-Bit breiten Busses. Lass es, das kostet mehr Aufwand als es wert ist. > Last not least haben diese Encoder eine Auflösung die ich im Grunde gar > nicht brauche. Dann nimm andere ;-) > Ich habe auch noch andere davon wo das ursprüngliche > Sinus-Signal auswählbar (per DIL Schalter) interpoliert wird. So könnte > ich auch die Interpolation veringern, da ich nur eine Auflösung von > 30-50 um benötige. Klingt auch nach Würg-Around. Nimm einfach einen AVR mit Hardwaredekoder, wie z.B. die ATXmega. Die sind den "normalen" AVRs sehr ähnlich, ein Umstieg recht leicht. Und man kann sie mit bis zu 32 MHz takten, macht 60% mehr Power als mit 20MHz. Oder einen der vielen 32 Bitter, STM32 & Co.
Nur rein interessehalber. Hier mal eine handoptimierte ISR in Assembler mit 42 Takten. Die C-Version ist mit 59 Takten nicht soo viel schlechter. Wenn man mal grob 50% CPU-Auslasung durch die ISR zuläßt, sind das bei 20 MHz immerhin satte 240kHz (ASM) bzw. 169kHz (C) Interruptfrequenz! Aber der Rest der Verarbeitung muss immerhin alle ~100 Interrupts einmal den Zähler auslesen, damit der im Grenzfall nicht überläuft, sprich die Hauptschleife muss auch mit ca. 1,7-2,4kHz laufen. Handoptimierter Assembler, 42 Takte
1 | TIMER0_COMPA_vect: |
2 | push r16 |
3 | push r17 |
4 | in r16, _SFR_IO_ADDR(SREG) |
5 | push r16 |
6 | |
7 | ldi r16, 0 |
8 | ldi r17, 1 |
9 | sbic _SFR_IO_ADDR(PHASE_A_PORT), PHASE_A_BIT |
10 | ldi r16, 3 |
11 | sbic _SFR_IO_ADDR(PHASE_B_PORT), PHASE_B_BIT |
12 | eor r16, r17 |
13 | lds r17, enc_last |
14 | sub r17, r16 |
15 | sbrs r17, 0 |
16 | rjmp TIMER0_COMPA_vect_end |
17 | sts enc_last, r16 |
18 | andi r17, 2 |
19 | subi r17, 1 |
20 | lds r16, enc_delta |
21 | add r16, r17 |
22 | sts enc_delta, r16 |
23 | TIMER0_COMPA_vect_end: |
24 | |
25 | pop r16 |
26 | out _SFR_IO_ADDR(SREG), r16 |
27 | pop r17 |
28 | pop r16 |
29 | reti |
avr gcc Ergebnis, 59 Takte (140% der ASM-Version)
1 | ISR( TIMER0_COMPA_vect ) { // 1ms for manual movement |
2 | 84: 1f 92 push r1 |
3 | 86: 0f 92 push r0 |
4 | 88: 0f b6 in r0, 0x3f ; 63 |
5 | 8a: 0f 92 push r0 |
6 | 8c: 11 24 eor r1, r1 |
7 | 8e: 2f 93 push r18 |
8 | 90: 8f 93 push r24 |
9 | 92: 9f 93 push r25 |
10 | |
11 | int8_t enc_new, diff; |
12 | |
13 | enc_new = 0; |
14 | if( PHASE_A ) enc_new = 3; |
15 | 94: 31 9b sbis 0x06, 1 ; 6 |
16 | 96: 02 c0 rjmp .+4 ; 0x9c <__vector_14+0x18> |
17 | 98: 23 e0 ldi r18, 0x03 ; 3 |
18 | 9a: 01 c0 rjmp .+2 ; 0x9e <__vector_14+0x1a> |
19 | 9c: 20 e0 ldi r18, 0x00 ; 0 |
20 | if( PHASE_B ) enc_new ^= 1; // convert gray to binary |
21 | 9e: 32 9b sbis 0x06, 2 ; 6 |
22 | a0: 02 c0 rjmp .+4 ; 0xa6 <__vector_14+0x22> |
23 | a2: 81 e0 ldi r24, 0x01 ; 1 |
24 | a4: 28 27 eor r18, r24 |
25 | diff = enc_last - enc_new; // difference last - new |
26 | a6: 90 91 00 01 lds r25, 0x0100 |
27 | aa: 92 1b sub r25, r18 |
28 | if( diff & 1 ) { // bit 0 = value (1) |
29 | ac: 90 ff sbrs r25, 0 |
30 | ae: 09 c0 rjmp .+18 ; 0xc2 <__vector_14+0x3e> |
31 | enc_last = enc_new; // store new as next last |
32 | b0: 20 93 00 01 sts 0x0100, r18 |
33 | enc_delta += (diff & 2) - 1; // bit 1 = direction (+/-) |
34 | b4: 80 91 01 01 lds r24, 0x0101 |
35 | b8: 81 50 subi r24, 0x01 ; 1 |
36 | ba: 92 70 andi r25, 0x02 ; 2 |
37 | bc: 89 0f add r24, r25 |
38 | be: 80 93 01 01 sts 0x0101, r24 |
39 | } |
40 | } |
41 | c2: 9f 91 pop r25 |
42 | c4: 8f 91 pop r24 |
43 | c6: 2f 91 pop r18 |
44 | c8: 0f 90 pop r0 |
45 | ca: 0f be out 0x3f, r0 ; 63 |
46 | cc: 0f 90 pop r0 |
47 | ce: 1f 90 pop r1 |
48 | d0: 18 95 reti |
:
Bearbeitet durch User
Hm,
mit Assembler kenn ich mich nicht so aus, C geht aber.
Letztlich ist wohl wie vorgeschlagen der ATXMega der beste Weg (u.U. mit
abgesenkter Interpolation) und ja, das Ganze mal im Simulator
durchzuspielen macht natürlich Sinn.
-----------------------------------------------------------------------
"> Last not least haben diese Encoder eine Auflösung die ich im Grunde
gar
> nicht brauche.
Dann nimm andere ;-)"
Jein, die Encoder sind von der Grösse und Robustheit genau das was ich
brauche.
(Stückpreis >1000€) - und dann brauche ich trotzdem immer noch eine
Auslese...
ATXMega Stückpreis < 5€, hört sich irgendwie besser an.
-----------------------------------------------------------------------
"Nyquist hat hier nicht direkt was zu sagen."
In meinen Augen schon, ist aber nicht weiter relevant.
Grüsse & Danke: Hermann
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.