So, jetzt muss ich doch mal einen Beitrag verfassen. Ich habe mich wirklich mehrere Stunden bemüht das Problem selbst zu lösen, leider vergebens. Es geht um folgendes: Ich habe einen Drehimpulsgeber von diesem Typ: http://www.pollin.de/shop/downloads/D240313D.PDF an einen PIC Mikrocontroller (Hilfe Hilfe PIC...) angeschlossen. Ich möchte die Drehung des Gebers in einem Timer Interrupt (wie z.B. hier von Peter Danegger beschrieben: Beitrag "Drehgeber auslesen") auswerten. Ich verwende genau den dort geposteten Code (main.c im Anhang...). Das Ergebnis enc_delta gebe ich dann auf einem Anzeigeelement aus. Leider kommt immer entweder eine EINS (=0b01) oder eine ZWEI (0b10) heraus. Und das immer abwechselnd. sagen wir enc_delta war eine EINS. Wenn ich nun den Geber um eine Raste in beliebiger Richtung weiter drehe ist enc_delta ZWEI. Drehe ich wiederum weiter kommt wieder eine EINS raus usw.... Wird gar nicht gedreht ändert sich der Wert (erwartungsgemäß) nicht. Ich taste etwa 1x pro Millisekunde ab. Wenn jemand sich der Sache annähme und eine Idee hätte woran dies liegt würde ich mich sehr freuen! Schöne Grüße, Alex
Das kann daran liegen, daß die Codierung dieses Encoders anders ist, als das Programm dies erwartet. Es gibt Encoder, die einen 'Vollschritt' kodieren und nach einer Rastung wieder 0 auf beiden Terminals ausgeben. Dieser Encoder jedoch gibt nach einer Rastung jeweils einen Wechsel an je einem Terminal, also einen 'Halbschritt'.
Mit >Dieser Encoder jedoch gibt nach einer Rastung jeweils einen Wechsel an >je einem Terminal, also einen 'Halbschritt'. meinst du, dass es so, wie beschrieben funktionieren sollte, oder wie war das gemeint?
Ich meine nur, daß es verschiedene Codierungen gibt und die Routine im Programm dies berücksichtigen muß. Aber um vielleicht Abhilfe zu schaffen: vertausche mal A und B Terminal an Deinem Controller und gucke, ob es dann geht. Der Drehencoder von Panasonic ist leicht asymmetrisch in seinem elektrischen Verhalten.
Das ist ja eigenartig. Wenn ich es (softwaremäßig) vertausche wechselt das enc_delta immer zwischen NULL (0b00) und EINS (0b01) anstatt wie vorher zwischen EINS und ZWEI (0b10). Wie kann man sich das denn erklären?
Ich benutze auf dem AVR die folgende Routine für die Pollin-Drehgeber. Es stimmt, dass die asymmetrisch sind, ich musste beim Portieren auf ein anderes Projekt auch schonmal die Anschlüsse vertauschen. Die Routine wird von der Mainloop alle 1 ms aufgerufen.
1 | .equ dgp=pinb ;Eingangsport Drehgeber |
2 | .equ dgmsk=0b00001100 ;Maske auf benutzte Bits |
3 | .equ dgprell=0b00101010 ;Maske auf Togglebits |
4 | |
5 | drehgeber: ;Drehgeber-Entprellung und -Abfrage |
6 | cbr flags,1<<dgentprell ;Jobflag löschen |
7 | in wl,dgp ;Drehgeber einlesen |
8 | andi wl,dgmsk ;nur Drehgeber-Bits (Bit 3:2) |
9 | swap wl ;nach oben (Bit 7:6) |
10 | or drg,wl ;neuen Zustand uebernehmen |
11 | mov wl,drg ;Bitmuster merken (neu, alt, aelter, uralt) |
12 | lsr drg ;Bitmuster nach unten schieben |
13 | lsr drg ;(leer, neu, alt, aelter) |
14 | eor wl,drg ;Aenderungen erfassen |
15 | andi wl,dgprell ;nur Aenderungsbits stehen lassen |
16 | cpi wl,2 ;nur aeltestes Aenderungsbit gesetzt? |
17 | brne drehgeber3 ;nein... |
18 | |
19 | ldi wl,1 ;ja, erstmal normale Schrittweite |
20 | sbrc tas,tdg ;Shift-Taste (Drehgeber-Taste) betaetigt? - nein... |
21 | ldi wl,32 ;ja, Geraete-Schrittweite |
22 | sbrs drg,1 ;steigende Flanke? - ja... |
23 | rjmp drehgeber1 ;nein... |
24 | sbrs drg,0 ;Richtung 1? nein... |
25 | add haschunu,wl ;ja, addieren |
26 | sbrc drg,0 ;Richtung 2? nein... |
27 | sub haschunu,wl ;ja, subtrahieren |
28 | drehgeber1: |
29 | sbrc drg,1 ;fallende Flanke? - ja... |
30 | rjmp drehgeber2 ;nein... |
31 | sbrs drg,0 ;Richtung 1? nein... |
32 | sub haschunu,wl ;ja, subtrahieren |
33 | sbrc drg,0 ;Richtung 2? nein... |
34 | add haschunu,wl ;ja, addieren |
35 | drehgeber2: |
36 | drehgeber3: |
37 | |
38 | locate 6,21 ;Ausgabeposition Handschussnummer |
39 | push xl ;XL sichern (wird von Ausgaberoutine benutzt) |
40 | mov xl,haschunu ;Kopie von Handschussnummer |
41 | rcall lcd_printsnr ;Aufruf... |
42 | pop xl ;XL wiederherstellen |
43 | rjmp mainloop ;fertig... |
...
Hallo Hannes, ich muss gestehen, dass ich mich in Assembler gar nicht auskenne. Ich verstehe vor allem > mov wl,drg ;Bitmuster merken (neu, alt, aelter, uralt) und > sbrc drg,1 ;fallende Flanke? - ja... nicht. Aber ich verstehe auch den Rest leider gar nicht... Ich vermute mal du hast davon kein Prozess-Flow-Chart?? :-)
Alex Bürgel wrote: > ich muss gestehen, dass ich mich in Assembler gar nicht auskenne. Schade eigentlich, der Mikrocontroller kann nur Maschinencode, der 1 zu 1 nur in Assembler notierbar ist... > > Ich verstehe vor allem >> mov wl,drg ;Bitmuster merken (neu, alt, aelter, uralt) MOV steht für Bewege, meint aber Kopiere... Es wird also der Inhalt des Registers, das "drg" heißt in das Register namens "wl" kopiert. In den Registern repräsentieren jeweils zwei zusammenliegende Bits den Zustand der beiden Drehgeber-Schalter zu einer bestimmten Zeit. Der neueste Zustand steht links (Bit 7:6), der vom letzten mal (letzte Runde, letzter Prozeduraufruf) daneben, dann der vorletzte Zustand und ganz rechts der davorige Zustand (uralt). Das Register fasst also die Drehgeberzustände von 4 verschiedenen Zeitpunkten zusammen. >> lsr drg ;Bitmuster nach unten schieben >> lsr drg ;(leer, neu, alt, aelter) Mit diesen beiden Rechts-Schiebebefehlen rücken alle Bitmuster (Drehgeberzustände) einen Schritt (zwei Bits) in Richtung alt. Dabei werden die uralten entsorgt, alle anderen rücken nach, in die obere (neueste) Position werden Nullen eingeschoben. >> eor wl,drg ;Aenderungen erfassen Durch EXOR-Verknüpfung (wobei drg unverändert bleibt) werden die "gealterten" Zustände mit den in wl geretteten Zuständen verglichen, Änderungen (Ungleichheiten) werden 1 (Bitwerte), wo keine Änderung ist, ist das Ergebnis 0. >> andi wl,dgprell ;nur Aenderungsbits stehen lassen AND-Verknüpfung mit der Konstante (siehe Deklaration) mit dem Ziel, nur die Änderungen stehen zu lassen, die für die weitere Betrachtung relevant sind. Es wird die Kopie bearbeitet, das Original (drg) bleibt erhalten. >> cpi wl,2 ;nur aeltestes Aenderungsbit gesetzt? >> brne drehgeber3 ;nein... Verzweigt nach drehgeber3 (beendet die Überprüfung), wenn der Wert des Bytes nicht 2 ist. Der Wert ist 2, wenn nur das Bit 1 gesetzt ist und alle anderen Bits gelöscht sind. Das ist der Fall, wenn Schalter A des Drehgebers zweimal hintereinander denselben Zustand hatte, davor aber eine Änderung stattfand. Dies dient der Entprellung, Änderungen werden also nur übernommen, wenn dere Zustand danach stabil ist (zweimal gleich). > > und >> sbrc drg,1 ;fallende Flanke? - ja... Skip (if) Bit Register (is) Clear ... Überspringt den nächsten Befehl, wenn das Bit 1 im Register drg 0 (clear) ist. Das ist der Fall, wenn am Drehgebereingang eine fallende Flanke war. Ein recht starker ASM-Befehl, der ohne Veränderung des SREG arbeitet... > > nicht. Aber ich verstehe auch den Rest leider gar nicht... Schade eigentlich... > Ich vermute > mal du hast davon kein Prozess-Flow-Chart?? :-) Nein, die Informationen, die Andere in ein Struktogramm oder PAP schreiben, stehen bei mir in den Kommentaren. Da werden ein paar Konventionen eingehalten, z.B. bedeutet bei mir "..." am Ende der Zeile, dass "gesprungen" wird. Ein Fragezeichen kennzeichnet die Frage, die beim PAP im Verzweigungs-Rhombus steht, die Antworten darauf (meist nur ja oder nein) stehen auch in den Kommentaren. Man kann also anhand meiner Kommentare den Algorithmus rekonstruieren. ...
Wenn der Zählerstand immer nur zwischen zwei aufeinanderfolgenden Werten wechselt, wird vermutlich einer der beiden Kanäle nicht richtig gelesen. Ursache kann ein Verdrahtungsfehler, ein Hardwaredefekt oder ein falsch konfigurierter Port sein. Fangen wir mal mit dem letzten an:
1 | TRISA = 0b001100; //I/O direction for PORTA |
Ich habe keine Ahnung von PICs, aber sollten in TRISA die Bits 3 und 4 nicht gleich sein, da beides Eingänge sind? Oder ist der Drehgeber gar nicht an 3 und 4, sondern an 2 und 3 angeschlossen? Dann ist's im Interrupthandler falsch.
> Ursache kann ein Verdrahtungsfehler, ein Hardwaredefekt oder ein > falsch konfigurierter Port sein. Ich hatte den Eindruck, dass diese Drehgeber nicht (nur) "asymmetrisch" sind, sondern dass einer ihrer Schalter (immer derselbe) recht unsauber (stark prellend, Aussetzer) arbeitet. Wenn ich den Schalter zur Flankenerkennung nutze, dann macht meine Routine auch Müll. Wenn ich den ordentlichen Schalter zur Flankenerkennung nutze, dann gibt es keine Probleme, der andere Schalter wird dann ja nur auf Zustand abgefragt. Wenn ich mich nicht irre, wertet Peters Routine beide Flanken aus. Ich halte es für möglich, dass diese Drehgeber dafür ungeeignet sind. Ich selbst kann über diese Drehgeber aber nicht klagen, mit meiner Routine und bei richtiger Polung funktionieren sie sehr präziese. ...
Guten Morgen! Ich muss gestehen, dass es in der Tat daran lag, dass ich am PORTA die Pins 2 & 3 als input eingestellt habe, obwohl der Drehgeber an 3 & 4 angeschlossen ist. Es funktioniert jetzt so ungefähr... Er überspringt oft ein oder zwei Schritte, aber das sollte in den Griff zu bekommen sein... Danke vor allem an Yalu und Hannes für die Mühe. Ich werde auch mal versuchen deinen Code, Hannes, in C zu transferieren. Schönes Wochenende noch! Alex
Ich benutze auf einem Tiny15 folgende Routine im Timerinterupt um den Drehgeber abzufragen (der Timer wurde bei mir für nichts anderes gebraucht) Prescaler hab ich mein ich bei 64 gesezt also wird das ganze bei 1,6Mhz etwa ale 10ms abgetastet, das funktioniert recht zuverlässig. mit Prellen hatte ich dann auch keine Probleme.
1 | INT_OV0: |
2 | in int_sreg_save, SREG ; SREG sichern |
3 | sbis PINB, A ; Ist Terminal A High oder LOW? |
4 | rjmp int_low ; ---> Sprung zu Low |
5 | |
6 | int_high: ; Sonst war Pegel High |
7 | sbrc FLAGS, F_LASTPEGEL ; war lezter Pegel Low --> wechsel |
8 | rjmp int_ende ; sonst ende --> es hat sich nix verändert |
9 | sbr FLAGS, (1<<F_LASTPEGEL) ; Pegel fürs nächste mal merken (PEGEL = LOW) |
10 | sbic PINB, B ; Ist Terminal B Low? --> Wir drehen vorwärts |
11 | sbr FLAGS, (1<<F_UP) ; --> Flag für Hauptprogram setzen |
12 | sbis PINB, B ; Ist Terminal B High? --> Wir drehen rückwärts |
13 | sbr FLAGS, (1<<F_DOWN) ; --> Flag für Hauptprogram setzen |
14 | rjmp int_ende |
15 | |
16 | int_low: ; Pegel war Low |
17 | sbrs FLAGS, F_LASTPEGEL ; lezter Pegel war High --> wechsel |
18 | rjmp int_ende ; sonst ende --> es hat sich nix verändert |
19 | cbr FLAGS, (1<<F_LASTPEGEL) ; Pegel fürs nächste mal merken (PEGEL = HIGH) |
20 | sbis PINB, B ; Ist Terminal B High? --> Wir drehen vorwärts |
21 | sbr FLAGS, (1<<F_UP) ; --> Flag für Hauptprogram setzen |
22 | sbic PINB, B ; Ist Terminal B Low? --> Wir drehen rückwärts |
23 | sbr FLAGS, (1<<F_DOWN) ; --> Flag für Hauptprogram setzen |
24 | int_ende: |
25 | out SREG, int_sreg_save ; SREG zurückschreiben |
26 | reti |
Algemein kann man zu dem Drehgeber sagen, Terminal A wechselt pro Rasterung immer 1/0/1/0 während B je nach Rasterstellung/Drehrichtung 1 oder 0 ist (sollte auch im Quellcode ersichtlich sein). Man hat den Vorteil das man den Drehgeber an die (meist) ungenuzten ISP Pins hängen kann und trozdem Problemlso programmieren kann, falls es nicht geht, einfach eine Rasterstellung weiter... Ach ja Pullups nicht vergessen ;)
> Algemein kann man zu dem Drehgeber sagen, Terminal A wechselt pro > Rasterung immer 1/0/1/0 während B je nach Rasterstellung/Drehrichtung 1 > oder 0 ist Sollte ich mich da sooooo vermessen haben? Ich habe in Erinnerung, dass die Pollin-Drehgeber pro Rastung einen halben Zyklus machen, also in eingerasteter Stellung beide Kontakte offen sind oder beide Kontakte geschlossen. Beim Überwinden einer Raststellung entsteht dann an jedem Kontakt ein Pegelwechsel (keine 4), die Pegelwechsel sind natürlich zeitlich versetzt. Mit 10 ms funktioniert das auch, da darf man aber nicht allzu schnell drehen. Ich habe daher 1 ms gewählt (das bot sich auch aufgrund anderer Synchronisationen im Programm an). Es wird natürlich auch vom Timer-Interrupt (über Flag) synchronisiert, läuft aber in der Mainloop, um die Interrupts (da gibt es noch mehrere) kurz zu halten. Bit-Zugriffe auf die Portpins habe ich bewusst vermieden, um die Prellsicherheit zu erhöhen. Ich wollte mit einer "Kopie" des Port-(Eingangs-)Zustandes arbeiten, um beide Zustände zeitnah zu erfassen. Die Bitschaufelei (Swap) am Anfang meiner Routine rührt daher, dass mir nur noch diese Portpins für den Drehgeber zur Verfügung standen. Meine Routine ist auch deshalb etwas aufgebläht, weil sie nicht nur Flags setzt, sondern gleich den Zähler manipuliert, und das auch noch (abhängig vom Drucktaster des Drehgebers, der mittels PeDa-Entprellung zusammen mit den Tastern entprellt wird) in zwei verschiedenen Schrittweiten. Unter dem Aspekt, dass zur Entprellung des Drehgebers nur ein (stastisches) Register blockiert wird, halte ich den Code schon für halbwegs effizient. Bit- & Bytebruch, Hannes
Also Hannes das kann natürlich auch sein, ich hab leider kein Oziloskop, kann daher nur sagen das es so bei mir funktioniert. Ich benutz das nur für das einstellen eines Countdowns, da ist es nicht schlimm wenn mal eine Rasterung verloren geht :) Da gibts sicher noch Optimierungsbedarf.
Ich greife diesen Thread mal auf, denn ich habe genau das gleiche Problem: Bisher hatte ich die Pollin Drehgeber immer per Interrupt ausgelesen (was auch gut funktioniert hat). Aber da hier ja alle schreien, diese Lösung wäre schlecht, wollte ich es besser machen. Soviel zur Vorgeschichte. Die hier unter Drehgeber empfohlenen Routinen sind für den Pollin Drehgeber eher nicht zu gebrauchen. Zumindest funktionieren sie nicht richtig, wenn man sie wie im Beispiel gezeigt verwendet. Der Grund wird aus dem Bild deutlich (oben: Uhrzeigersinn, unten: Gegenuhrzeigersinn, 16ms/div). Das von Hannes beschriebene asymmetrische Verhalten ist ziemlich stark ausgeprägt. Durch die Rastung wird das ganze noch verstärkt. Selbst wenn man langsam dreht (wenige Hz), dann liegt der Abstand der beiden Signale nicht bei 90° wie im Idealfall, sondern irgendwo im einstelligen Bereich ! Man müsste im Idealfall so schnell wie möglich nach der Flanke das andere Signal abzutasten. In der Praxis muss man also mit mindestens 1kHz die Signale abtasten, damit das sicher funktioniert. Eine einfache Entprellung nur durch eine geringe Abtastrate funktioniert also nicht allzu sicher. Damit es auch bei schnellem Drehen noch gut funktioniert musste ich die Polling Frequenz auf >10kHz einstellen. Daher meine Frage: Hat jemand schonmal eine gute Routine (abgesehen von den anderen hier im Thread) für den Pollin Drehgeber geschrieben, die ohne übertrieben hohe Abtastfrequenzen auskommen ?
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.