mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Drehimpulsgeber (wiedereinmal.)


Autor: Alex Bürgel (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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'.

Autor: Alex Bürgel (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Alex Bürgel (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
.equ dgp=pinb               ;Eingangsport Drehgeber
    .equ dgmsk=0b00001100       ;Maske auf benutzte Bits
    .equ dgprell=0b00101010     ;Maske auf Togglebits

drehgeber:              ;Drehgeber-Entprellung und -Abfrage
 cbr flags,1<<dgentprell    ;Jobflag löschen
 in wl,dgp                  ;Drehgeber einlesen
 andi wl,dgmsk              ;nur Drehgeber-Bits (Bit 3:2)
 swap wl                    ;nach oben (Bit 7:6)
 or drg,wl                  ;neuen Zustand uebernehmen
 mov wl,drg                 ;Bitmuster merken (neu, alt, aelter, uralt)
 lsr drg                    ;Bitmuster nach unten schieben
 lsr drg                    ;(leer, neu, alt, aelter)
 eor wl,drg                 ;Aenderungen erfassen
 andi wl,dgprell            ;nur Aenderungsbits stehen lassen
 cpi wl,2                   ;nur aeltestes Aenderungsbit gesetzt?
 brne drehgeber3            ;nein...

 ldi wl,1                   ;ja, erstmal normale Schrittweite
 sbrc tas,tdg               ;Shift-Taste (Drehgeber-Taste) betaetigt? - nein...
 ldi wl,32                  ;ja, Geraete-Schrittweite
 sbrs drg,1                 ;steigende Flanke? - ja...
 rjmp drehgeber1            ;nein...
 sbrs drg,0                 ;Richtung 1? nein...
 add haschunu,wl            ;ja, addieren
 sbrc drg,0                 ;Richtung 2? nein...
 sub haschunu,wl            ;ja, subtrahieren
drehgeber1:
 sbrc drg,1                 ;fallende Flanke? - ja...
 rjmp drehgeber2            ;nein...
 sbrs drg,0                 ;Richtung 1? nein...
 sub haschunu,wl            ;ja, subtrahieren
 sbrc drg,0                 ;Richtung 2? nein...
 add haschunu,wl            ;ja, addieren
drehgeber2:
drehgeber3:

 locate 6,21                ;Ausgabeposition Handschussnummer
 push xl                    ;XL sichern (wird von Ausgaberoutine benutzt)
 mov xl,haschunu            ;Kopie von Handschussnummer
 rcall lcd_printsnr         ;Aufruf...
 pop xl                     ;XL wiederherstellen
 rjmp mainloop              ;fertig...

...

Autor: Alex Bürgel (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?? :-)

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

...

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
  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.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

...

Autor: Alex Bürgel (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
INT_OV0:
  in int_sreg_save, SREG      ; SREG sichern
  sbis PINB, A          ; Ist Terminal A High oder LOW?
  rjmp int_low          ; ---> Sprung zu Low

  int_high:            ; Sonst war Pegel High
    sbrc FLAGS, F_LASTPEGEL    ; war lezter Pegel Low --> wechsel
    rjmp int_ende        ; sonst ende --> es hat sich nix verändert
    sbr FLAGS, (1<<F_LASTPEGEL)  ; Pegel fürs nächste mal merken (PEGEL = LOW)
    sbic PINB, B        ; Ist Terminal B Low? --> Wir drehen vorwärts
    sbr FLAGS, (1<<F_UP)    ; --> Flag für Hauptprogram setzen
    sbis PINB, B        ; Ist Terminal B High? --> Wir drehen rückwärts
    sbr FLAGS, (1<<F_DOWN)    ; --> Flag für Hauptprogram setzen
  rjmp int_ende

  int_low:            ; Pegel war Low
    sbrs FLAGS, F_LASTPEGEL    ; lezter Pegel war High --> wechsel
    rjmp int_ende        ; sonst ende --> es hat sich nix verändert
    cbr FLAGS, (1<<F_LASTPEGEL)  ; Pegel fürs nächste mal merken (PEGEL = HIGH)
    sbis PINB, B        ; Ist Terminal B High? --> Wir drehen vorwärts
    sbr FLAGS, (1<<F_UP)    ; --> Flag für Hauptprogram setzen
    sbic PINB, B        ; Ist Terminal B Low? --> Wir drehen rückwärts
    sbr FLAGS, (1<<F_DOWN)    ; --> Flag für Hauptprogram setzen
  int_ende:
  out SREG, int_sreg_save      ; SREG zurückschreiben
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 ;)

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Benedikt K. (benedikt) (Moderator)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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 ?

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.