Forum: Projekte & Code Drehgeberauswertung (mit einem Interrupt)


von Sebastian Engel (Gast)


Lesenswert?

Hi,

habe nach langem Stöbern in diversen Foren, selber eine Routine zum 
auswerten eines Drehgebers geschrieben. Die wollte ich hier kurz 
vorstellen:

Der Drehgeber ist an PD2 (INT0) und PD3 (INT1) angeschlossen. Dies auch 
nur aus Platzgründen. Benutzt wird nur INT0.

Die Routine entspricht weitgehend dem Flussdiagramm aus dem Datenblatt 
des Drehgebers von dem großen "C".

Hier erst der code:

Initialisierung:
1
      ;--- External interrupt ---
2
      ldi r16,0b01000000        ;Ext. Interrupt Request 0 Enable
3
      out GICR,r16          ;General Interrupt Control Register
4
      ldi r16,0b00000001        ;INT0, Any logical change
5
      out MCUCR,r16          ;MCU Control Register

Interruptroutine:
1
encoder:  rcall warte            ;ca. 25 Prozessorzyclen warten
2
      in temp,PIND          ;Port D einlesen
3
      mov r17,temp          ;temp(r16) nach r17 kopieren
4
      ror r17              ;r17 ein Bit nach rechts verschieben
5
      andi temp,0b00000100      ;Relevanten Pin ausmaskieren
6
      andi r17,0b00000100        ;Relevanten Pin ausmaskieren
7
      cp temp,r17            ;Sind Port D2 und D3 gleich?
8
      breq rechts            ;Wenn ja, Drehung rechts
9
      dec r10              ;Wenn nein, Drehung links, -1
10
      rjmp enc_end          ;Springe zum Ende der Routine
11
rechts:    inc r10              ;+1
12
enc_end:  reti              ;Ende des Interrupts

Funktion:
Der INT0 ist auf "any Change" eingestellt. Also wird eine 
Interruptroutine ausgelößt, wenn sich der zustand an PD2 von 0-1 oder 
1-0 ändert.

Wenn das passiert, wird eine kurze Pause aufgerufen (ca. 25 Zyclen).
Dann wird der komplette Port D eingelesen.
Einmal in temp(r16) und in r17. r17 wird 1 Bit nach rechts verschoben.
Das gewünschte Bit wird ausmaskiert. Dann wird verglichen.
Wenn beide Bits 1 sind (beide Pins vom Drehgeber), wurde rechts rum 
gedreht, wenn sie ungleich sind, links rum.

Der Hintergrundgedanke: Wenn rechtsrum gedreht wird, ändert sich erst 
z.B. A, dann B. Wenn der INT0 an B ausgelößt wird, sind immer beide Pins 
gleich.

Wenn linksrum gedreht wird, ändert sich erst B, dann A. Wenn INT0 an B 
ausgelößt wird, sind immer beide Pins ungleich.

Die Routine läuft super. Sogar wenn das Register, in dem Gezählt wird, 
Dezimal auf einem LC Display angezeigt wird.
Dafür müssen natürlich, während das Display Daten erhält, die Interrupt 
ausgestellt werden.

Hardwareseitig ist fast nichts entprellt. Nur jweweils ein kleiner 
Kondensator zwischen A & GND und B & GND (20nF oder so :-) ist 
eingebaut.

Mfg
  S. Engel

von Simon K. (simon) Benutzerseite


Lesenswert?

Drehgeber

 Warum Sparvarianten nicht gut sind

Oft sieht man im Netz "clevere" Sparvarianten, welche angeblich 
ebensogut zur Auswertung von Drehgebern gegeignet sind. Ein genaueres 
Hinschauen sowie Tests unter realen Bedingungen zeigen jedoch schnell 
die Schwächen dieser Ansätze.
[bearbeiten]
Flankenerkennung von A und Pegelauswertung von B

Viele Sparvarianten verwenden einen externen Interrupt, welcher auf die 
steigende oder fallende Flanke von Spur A auslöst und dann den Pegel von 
B auswertet. Ist B=0, dann dreht der Encoder nach rechts, anderenfalls 
nach links. Diese Auswertung hat zwei Schwachstellen.

    * Die Auflösung wird auf ein Viertel reduziert, weil nur jede 
steigende Flanke von A ausgewertet wird.
    * Pendelt der Encoder zwischen zwei Codes, bei denen A seinen Pegel 
wechselt,
          o kommt es zu (sehr) vielen Interrupts, die den 
Mikrocontroller vollkommen auslasten können.
          o interpretiert die Auswertung jede steigende Flanke als neuen 
Schritt, der Encoder scheint sich für die Auswertung immer weiter zu 
drehen, obwohl er nur pendelt.

Das Pendeln kann zwei Ursachen haben.

    * Der Encoder pendelt wirklich; das kann z.B. bei hochauflösenden 
Encodern ohne Rastung geschehen, welche an jeder beliebigen Stelle 
stehen bleiben können und durch geringe mechanische Erschütterungen dann 
zwischen zwei Codes pendeln; das kann z.B. bei hochauflösenden Encodern 
in CNC-Maschinen der Fall sein.
    * Die Signale prellen; das kommt vor allem bei billigen 
elektromechanischen Drehknöpfen vor, welche einfache Schleifkontakte zur 
Kodierung nutzen.

Wie man sieht ist diese Methode nicht geeignet, einen Drehgeber solide 
zu dekodieren.

von Sebastian Engel (Gast)


Lesenswert?

Das mag bei Drehgebern zur Positionsbestimung zutreffen.

Aber bei Anwendugen, wo der Drehgeber als "Eingabegerät" arbeitet reicht 
es aus.

Auf nem Steckboard hat das super Funktioniert. Pro schritt wurd 
entwerder +1 oder -1 bei dem Testprogramm gerechnet. Dies Funktioniert 
auch, wenn man "Blind" z.B. 35 Schritte linksrum dreht, werden auch nur 
35 abgezogen.

Und bei dem oben beschriebenem Programm ist der Interrupt als "Any 
Change" eingestellt. Es wird also immer ein Interrupt ausgelößt, wenn 
sich das Signal von High auf Low, oder umgekehrt ändert.

Die Routine entspricht übrigens 100%tig einem Flussdiagramm, welches ich 
in einem Datenblatt von einem Drehgeber gefunden hatte.

Und das ganze funktioniert sogar in verbindung mit einem LC-Display.
Hier wird aber die Eingabegeschwindigkeit begrenzt, da das Display mit 
großzügigen Zeiten angesteuert wird.
Und während der Displayausgabe sind Interrupts ausgeschaltet.

von Thilo M. (Gast)


Lesenswert?

Wir hatten auch den 'C'-Drehgeber in einem Prototyp drin, wurde auch 
aufwändig entprellt (Software), nur halten die Teile nicht lange durch, 
der hat nach kürzester Zeit schon so geprellt, dass eine vernünftige 
Auswertung kaum noch möglich war.
In einem NEC OMICRON - Achtkanalschreiber ist ein APLS-Drehencoder drin, 
dort tritt nach einiger Zeit das gleiche Problem auf. In den 10 Jahren, 
in dem wir das Teil haben, Nicht mal allzuoft eingesetzt, haben wir den 
Encoder schon 3x wechseln müssen.

Ich würde lieber etwas mehr Geld in die Hand nehmen und den optischen 
Enc. von Reichelt nehmen.

von Thomas B. (detritus)


Lesenswert?

Oder man wählt ne Lösung ohne EXT-Interrupt, dann kann das Ding 
problemlos prellen.

von Falk B. (falk)


Lesenswert?

@ Sebastian Engel (Gast)

>Aber bei Anwendugen, wo der Drehgeber als "Eingabegerät" arbeitet reicht
>es aus.

Lies den Artikel nochmal in Ruhe und denk drüber nach.

>Auf nem Steckboard hat das super Funktioniert.

Das haben Laborprototypen so an sich.

>Pro schritt wurd
>entwerder +1 oder -1 bei dem Testprogramm gerechnet. Dies Funktioniert
>auch, wenn man "Blind" z.B. 35 Schritte linksrum dreht, werden auch nur
>35 abgezogen.

Einmal gestestet, hat einmal funktioniert, wird also immer 
funktionieren?

>Und bei dem oben beschriebenem Programm ist der Interrupt als "Any
>Change" eingestellt. Es wird also immer ein Interrupt ausgelößt, wenn
>sich das Signal von High auf Low, oder umgekehrt ändert.

Eben das ist das Problem.

>Die Routine entspricht übrigens 100%tig einem Flussdiagramm, welches ich
>in einem Datenblatt von einem Drehgeber gefunden hatte.

Was nicht allzuviel heissen muss. Link?

>Und das ganze funktioniert sogar in verbindung mit einem LC-Display.

WOW! DAS Killerkriterium.

>Hier wird aber die Eingabegeschwindigkeit begrenzt, da das Display mit
>großzügigen Zeiten angesteuert wird.
>Und während der Displayausgabe sind Interrupts ausgeschaltet.

Wozu? Traust du deiner Progrmmierkunst doch nicht so?

MFG
Falk

von Simon K. (simon) Benutzerseite


Lesenswert?

Falk Brunner wrote:
>>Hier wird aber die Eingabegeschwindigkeit begrenzt, da das Display mit
>>großzügigen Zeiten angesteuert wird.
>>Und während der Displayausgabe sind Interrupts ausgeschaltet.
>
> Wozu? Traust du deiner Progrmmierkunst doch nicht so?

Ich auch nicht.

Das hier ist ja wohl der Killer:


> Interruptroutine:
1
encoder:  rcall warte            ;ca. 25 Prozessorzyclen warten

Auch wenn es nur 25 Zyklen sind, ist es fast immer eine schlechte Idee 
in einem Interrupt warten zu lassen. Zudem ist es fast immer vermeidbar.

von Falk B. (falk)


Lesenswert?

@ Simon K. (simon)

>encoder:  rcall warte            ;ca. 25 Prozessorzyclen warten

Uups, hab ich gar nicht soo gesehen ;-)

>Auch wenn es nur 25 Zyklen sind, ist es fast immer eine schlechte Idee
>in einem Interrupt warten zu lassen. Zudem ist es fast immer vermeidbar.

Eben. Vor allem, wozu soll das gut sein? Zur Entprellung ? 25 Takte 
bei 1 MHz sind gerade mal 25 us. Taster und billige Encoder prellen 
hundert bis tausendmal solange.

MFG
Falk

von R.Freitag (Gast)


Lesenswert?

Hi all,

ich würde gerne einen Schrittmotor als Geber verwenden. Ist dieses 
Programm hierzu verwendbar?

Gruss

Robert

von Sebastian Engel (Gast)


Lesenswert?

Ich hab mir den Artikel nochmal angeschaut. Und diesen Thread auch.

> >Aber bei Anwendugen, wo der Drehgeber als "Eingabegerät" arbeitet reicht
> >es aus.

> Lies den Artikel nochmal in Ruhe und denk drüber nach.

Zitat des Artikels: "... dass mit Hilfe von sog. Pin Change Interrupts 
Rechenzeit gespart werden kann ... Diese Methode ist besser, aber nicht 
gut genug ... Sie vermeidet Fehler ... aber nicht 2.1, da auch sie durch 
einen pendelnden/prellenden Encoder die CPU stark belastet."

Dies , so stehts im Artikel, passiert wenn (sehr) viele interrupts 
auftreten.
Bei einer menüführung dreht man nicht sehr schnell.


> >Auf nem Steckboard hat das super Funktioniert.

> Das haben Laborprototypen so an sich.

Ich wollte darauf hinaus, das ein entgültiges Gerät Störungssicherer 
ist.


> >Pro schritt wurd
> >entwerder +1 oder -1 bei dem Testprogramm gerechnet. Dies Funktioniert
> >auch, wenn man "Blind" z.B. 35 Schritte linksrum dreht, werden auch nur
> >35 abgezogen.

> Einmal gestestet, hat einmal funktioniert, wird also immer
> funktionieren?

Bisher öfters getestet. Verscheidene Anwendungen, verscheidene 
Drehgeber, verschiedene Controller. Hat immer super Funktioniert.


> >Und bei dem oben beschriebenem Programm ist der Interrupt als "Any
> >Change" eingestellt. Es wird also immer ein Interrupt ausgelößt, wenn
> >sich das Signal von High auf Low, oder umgekehrt ändert.

> Eben das ist das Problem.

Deshalb die paar µS Pause. Kann ja auch erweitert werden.

Zu der Pause im Interrupt: Why not? Bei meinen anwendungen führt das zu 
keinen Problemen.


> >Die Routine entspricht übrigens 100%tig einem Flussdiagramm, welches ich
> >in einem Datenblatt von einem Drehgeber gefunden hatte.

> Was nicht allzuviel heissen muss. Link?

http://www.vlsi.informatik.tu-darmstadt.de/student_area/sep/427z1.pdf
Es ist ein Beispiel, welches super Funktioniert.


> >Und das ganze funktioniert sogar in verbindung mit einem LC-Display.

> WOW! DAS Killerkriterium.

Es Funktioniert auch, wenn der Controller anderen Zeitaufwendigen Code 
erledigen muss.


> >Hier wird aber die Eingabegeschwindigkeit begrenzt, da das Display mit
> >großzügigen Zeiten angesteuert wird.
> >Und während der Displayausgabe sind Interrupts ausgeschaltet.

> Wozu? Traust du deiner Progrmmierkunst doch nicht so?

Ohne die Deaktivierung kam es zu Problemen bei der Datanübertragung zum 
LCD. Es hätte villeicht auch ein paar push und pops geholfen. Hab ich 
aber bisher nicht ausprobiert.


> @ Simon K. (simon)

> >encoder:  rcall warte            ;ca. 25 Prozessorzyclen warten

> Uups, hab ich gar nicht soo gesehen ;-)

S.o.: Why Not? In meinen bisherigen Anwendungen kommt es darauf nicht 
an.

---------------

Jetzt nochmal Allgemein: Das ist EINE Möglichkeit. Es gibt sehr viele 
varianten. Diese ist schlank und Funktioniert für einfache Anwendungen. 
Warum soll ich ein Riesiges Codemonster einsetzten, was ich überall 
einsetzten kann, wenn ich z.B. hohe Umdrehungsfrequenzen nicht erfassen 
muss?

Und könnt ihr, Falk und Simon, mal KONSTRUKTIVE Kritik posten???

Das was ihr da geschrieben habt, ist überflüssig. NICHT Hilfreich!!!
Das klingt so, als habt ihr euch auf den "Artikel" und paar aussagen zum 
Controller festgebissen. Und alles was abweicht wäre schlecht und 
funktioniert generell nicht.

Hat einer von euch das mal ausprobiert?

Soviel noch dazu...

- S. Engel

von Michael (Gast)


Lesenswert?

>Und könnt ihr, Falk und Simon, mal KONSTRUKTIVE Kritik posten???
>Das klingt so, als habt ihr euch auf den "Artikel" und paar
>aussagen zum Controller festgebissen.


Sie haben aber Recht. Und wozu sollen sie noch etwas konstruieren, wo 
doch alles gesagt ist?
Der Code von Peter ist einfach gut durchdacht und hat nicht diese 
Nachteile wie Deiner. Wozu sollte man also Deinen einsetzen?
Nimm doch die Kritik an und sieh ein, daß es sich für andere nicht 
lohnt, sich mit Deinem Code auseinanderzusetzen, wo sie mit Peters Code 
viel besser bedient sind.
Ist doch nicht schlimm, Du hast halt wenig Erfahrung und für Dich reicht 
Dein Code aus. Prima. Andere nutzen halt die pfiffigere Lösung von 
Peter.

von Falk B. (falk)


Lesenswert?

@ Sebastian Engel (Gast)

>gut genug ... Sie vermeidet Fehler ... aber nicht 2.1, da auch sie durch
>einen pendelnden/prellenden Encoder die CPU stark belastet."

>Bei einer menüführung dreht man nicht sehr schnell.

Bis du blind? Es geht nicht um schnelles Drehen sondern um Prellen ! 
Und das machen voer allem die billigen mechanischen Encoder.

>Bisher öfters getestet. Verscheidene Anwendungen, verscheidene
>Drehgeber, verschiedene Controller. Hat immer super Funktioniert.

Du musst noch einges zum Thema Fehleranlayse und Logik lernen. Mussten 
wir alle. Du wählst den scmerzhaften Weg. Machen auch viele ;-)

>Deshalb die paar µS Pause. Kann ja auch erweitert werden.

Die reichen hinten und vorne nicht. Das Prellen dauert 
Grössenordnungen länger.

>Zu der Pause im Interrupt: Why not? Bei meinen anwendungen führt das zu
>keinen Problemen.

Die berühmten Labormuster in geringer Stückzahl. Und JA, bei Encodern 
für Menüs ist es im allgemeinen unkritisch, wenn die mal einen Schritt 
weiter springen. Ist nur ggf. nervig.

>http://www.vlsi.informatik.tu-darmstadt.de/student...
>Es ist ein Beispiel, welches super Funktioniert.

Die Schalter werden sich bedanken, wenn sie permanent einen geladenen 
33nF Kondensator kurzschliessen müssen. Die Pulsströme liegen im 
Ampere-Bereich. Auch ne Möglichkeit die Lebensdauer zu verkürzen und für 
Umsatz zu sorgen.

> >encoder:  rcall warte            ;ca. 25 Prozessorzyclen warten

> Uups, hab ich gar nicht soo gesehen ;-)

>S.o.: Why Not? In meinen bisherigen Anwendungen kommt es darauf nicht
>an.

Ach auf einmal? Zitat von vor 3 Minuten

"Es Funktioniert auch, wenn der Controller anderen Zeitaufwendigen Code
erledigen muss."

Ausserdem ist die Zeit wie bereits gesagt viel zu kurz.

>Und könnt ihr, Falk und Simon, mal KONSTRUKTIVE Kritik posten???

Das tun wir permanent. Aber Du bist nicht kritikfähig und 
lernresistent.

>Das was ihr da geschrieben habt, ist überflüssig. NICHT Hilfreich!!!

Der Herr belieben zu scherzen.

>Das klingt so, als habt ihr euch auf den "Artikel" und paar aussagen zum
>Controller festgebissen. Und alles was abweicht wäre schlecht und
>funktioniert generell nicht.

Irrtum. Alles andere funktioniert nur zu 99%. Das kann für ein 
Hobbyprojekt ausreichen. Für ein wasserdichtes, proessionelles Design 
aber nicht.

>Hat einer von euch das mal ausprobiert?

Sicher. Es gibt leider sogar professionelle Produkte, die keine solide 
Auswertung der Drehgeber machen. hab ich mal bei einem Oszi von TEK 
gesehen.

MFG
Falk

von Sebastian Engel (Gast)


Lesenswert?

Es wird schon besser.

Nun kann ich endlich ein wenig Informationen aus deinem Posting 
entnehmen.

Kritik vertrage ich sehrwohl. Ich hab ja darum gebeten.
Aber ein "Eben das ist das Problem." hilft mir nicht sonderlich weiter 
;-)

Sowas verstehe ich unter Konstruktiv:
> "Die Schalter werden sich bedanken, wenn sie permanent einen geladenen
> 33nF Kondensator kurzschliessen müssen. Die Pulsströme liegen im
> Ampere-Bereich. Auch ne Möglichkeit die Lebensdauer zu verkürzen und für
> Umsatz zu sorgen."

(auch wenn das jetzt nicht die "Fehler" der Routine betrifft, ist es 
dennoch hilfreich)

Was mich aber immer noch interessiert: Warum keine Wartezeiten in 
Interruptroutinen? Ich seh das so, das es dem Controller doch egal ist, 
ob er 25x "nichts" macht, oder ob er "nützlicher" code bearbeitet.


> Das tun wir permanent. Aber Du bist nicht kritikfähig und
> lernresistent.

Wozu schreib ich sonst hier ins Forum?
Dieser Thread ist dafür da, um zu Kritisieren.
Im Forum "µC & Elektronik" stell ich öfters Fragen.

Ich bin mir da ziemlich sicher, das das deine Aussage wiederlegt!

von Meister E. (edson)


Lesenswert?

>Was mich aber immer noch interessiert: Warum keine Wartezeiten in
>Interruptroutinen?

Weil dann das Hauptprogramm länger als nötig unterbrochen wird.

>Ich seh das so, das es dem Controller doch egal ist,
>ob er 25x "nichts" macht, oder ob er "nützlicher" code bearbeitet.

Dem Controller ist es egal, und mir ist es auch egal wenn du das machst 
;)
Trotzdem ist es bei den meisten Anwendungen ein Pferdefuss (Interrupts 
können übersehen werden), nachträgliche Änderungen führen dann zu 
unerwarteten Fehlern...

von Meister E. (edson)


Lesenswert?

>Kritik vertrage ich sehrwohl. Ich hab ja darum gebeten.

In deinem ersten Post lese ich davon nichts, nur:

>Die Routine läuft super.

Klingt nicht nach einer Anregung für konstruktive Kritik, oder? Im 
übrigen ist es wegen dieser 'Geschichte' nicht wahr:

>Dafür müssen natürlich, während das Display Daten erhält, die Interrupt
>ausgestellt werden.

Die Routine läuft gar nicht, sie muss während der Anwendung sogar 
deaktiviert werden...

von juppi (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

Hatte mir einen Drehgeber aus einer Mausmechanik
aufgebaut.
Schon mächtig alt.
MfG

von Hans-jürgen H. (hjherbert) Benutzerseite


Lesenswert?

> Die Routine läuft gar nicht, sie muss während der Anwendung sogar
> deaktiviert werden...

Weil der Status, r16 und r17 nicht gerettet werden.

push r16
push r17
in r16,sr
push r16
...
pop r16
out sr,r16
pop r17
pop r16
reti

oder so ähnlich

das Programm sollte auch ohne call warte laufen.

Der Drehgeber aus der Maus ist optisch, nicht mechanisch. Sollte nicht 
prellen.

von Falk B. (falk)


Lesenswert?

@ Sebastian Engel (Gast)

>Was mich aber immer noch interessiert: Warum keine Wartezeiten in
>Interruptroutinen?

Weil diese das normale Programm unterbrechen und andere, wichtige 
Interrupts solange blockieren. Ist einfach schlechter Stil, und man 
fällte damit nur allzuoft auf die Nase.

> Ich seh das so, das es dem Controller doch egal ist,
>ob er 25x "nichts" macht, oder ob er "nützlicher" code bearbeitet.

Die 25 NOPs sind viel zu kurz, um als wirksame Entprellung zu dienen.

MfG
Falk

von Sebastian DGJ (Gast)


Lesenswert?

Hi,
hatte auch schon mal einen billigen mech. Hand-Drehimpulsgeber per 
Interrupt on change ausgewertet. Wenn das Prellen NICHT länger dauert 
als die Zeit bis zur zweiten Flanke eines Drehschrittes (d.h. die Flanke 
an Leitung B, wenn vorher Flanke an A und umgekehrt), sollte man 
saubererweise den Interrupt für die Zeit des Prellens deaktivieren. da 
ich das Datenblatt dieses Pulsgebers jetzt nicht parat habe, kann ich 
nicht sagen, wie kurz diese Zeitdifferenz mindestens (dh bei sehr 
schnellem Drehen) ist.
Am besten: Mit 2-Kanal-Oszi analysieren und erst mal überlegen.
Warten im Int. finde ich auch schlecht (Falk hat recht) - absolut 
indiskutabel in professionellen bzw kommerziellen Projekten.

Im Grunde genommen verhält sich diese "Prellerei" ganz ähnlich wie bei 
Tasten, siehe Forum "Entprellen und trotzdem schnell reagieren", da 
gibts einige Anregungen dazu.

von Simon K. (simon) Benutzerseite


Lesenswert?

Oder einfach im Timer-Interrupt pollen. Aber das ist hier schon zu oft 
durchexerziert worden, als dass man da jetzt drauf eingeht.

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.