Forum: Projekte & Code Drehgeber auslesen


von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Die Encoder liefern einen Gray-Code.
Anbei ein C-Programm.

Für mittlere Geschwindigkeiten oder manuelle Bedienung ist das Abtasten
im Timerinterrupt das Optimale. Damit umgeht man sämtliche Probleme mit
der Flankenumschaltung beim externen Interrupt. Außerdem kann man auch
mehrere Encoder anschließen. Der Rechenzeitaufwand ist
vernachlässigbar.


Die Funktion get_gray_delta() liefert die Anzahl der Impulse seit dem
letzten Aufruf zurück.
In Zeile 8 und 9 kann man auswählen, ob bis zu 127 oder 32767 Impulse
seit der letzen Auswertung gespeichert werden sollen.

Die Decodierroutine arbeitet mit einer Tabelle aus den 16 möglichen
Kombinationen der 2 aktuellen und der 2 vorherigen Bits.
Bei den Übergängen:
0->1->3->2->1 steht eine "+1" in der Tabelle und bei:
0->2->3->1->0 eine "-1".
D.h. der Counter graycount wird dadurch um 1 erhöht oder erniedrigt.


Diese Routine habe ich z.B. auch für die hochgenaue X-Y-Positionierung
bei einer Steppermotorsteuerung verwendet (+/-50µm). Dabei wurden
optische Encoder verwendet.


Peter

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Anbei eine 2. Variante ohne Tabelle, die noch schneller und kleiner
ist.

Das Codebeispiel ist diesmal für den AVR geschrieben, die Änderungen
für den 8051 sind aber nur minimal (Definition der Portpins,
Timerinitialisierung).


Funktionsweise:

Das Einlesen der beiden Signale erfolgt mit:
  if( PHASE_A )
    ...
  if( PHASE_B )
    ...
Dadurch kann man beliebige Pins von beliebigen Ports nehmen.

Wenn man die beiden Encoder-Signale als Binärzahl darstellt, ergeben
sich folgende Zustände:
00 - 01 - 11 - 10 -10
Dieser Code wird auch Gray-Code genannt. Das besondere Merkmal des
Gray-Code ist, daß sich zwischen aufeinanderfolgende Werten immer nur
ein Bit ändert. Dadurch können keine Fehldekodierungen auftreten.

Würde man nun die Differenz zwischen zwei Codes bilden, käme nur Müll
heraus, da die CPU ja im Binärcode rechnet.
Eine Lösung ist die obige, wobei mittels einer Wertetabelle eine
Gray-Code Subtraktion realisiert wird.

Einfacher ist jedoch eine Umwandlung des Gray-Code nach Binär, wie sie
in diesem 2.Programmbeispiel erfolgt:

Gray-Code   Binär-Code
00          00 (0)     o.k.
01          01 (1)     o.k.
11          10 (2)     ändern
10          11 (3)     ändern

Wie man sieht, muß man also nur das niederwertige Bit umdrehen, sobald
das höherwertige Bit gesetzt ist.

Diese Anweisung:
  if( PHASE_B )
    i ^= 3;
setzt das höherwertige Bit und invertiert das niederwertige, fertig ist
die Codeumwandlung.

Danach kann man nun die Differenz zwischen 2 aufeinanderfolgenden
Auslesungen bilden:
  i -= enc_last;

Erfolgt keine Änderung, ist die Differenz 0.

Erfolgt eine Änderung über 2 Schritte, ist die Differenz 2. Das kann
aber nur bei Störungen passieren oder wenn die Abtastgeschwindigkeit zu
langsam ist. Die Drehrichtung läßt sich dabei nicht bestimmen. Deshalb
wird auch eine solche Änderung ignoriert:
  if( i & 1 ){
    enc_last += i;

Bei einer Änderung über einen Schritt, ergeben sich je nach
Drehrichtung folgende Werte (in Klammern der 2-Bit Wert als
Dezimalzahl):

Vorwärts:
00 - 11 = 01 (1)
01 - 00 = 01 (1)
10 - 01 = 01 (1)
11 - 10 = 01 (1)

Rückwärts:
00 - 01 = 11 (3)
01 - 10 = 11 (3)
10 - 11 = 11 (3)
11 - 00 = 11 (3)

Maskiert man nun das höherwertige Bit (2) heraus und zieht 1 ab,
ergeben sich die Byte-Werte +1 bzw. -1, die man zu dem Zählerwert
addiert, um ihn rauf bzw. runter zählen zu lassen:
    enc_delta += (i & 2) - 1;



Peter

von nobody0 (Gast)


Lesenswert?

Naja, da fehlt noch Fehlerkorrektur, wie man merkt, wenn man einen
Treiber für einen mechanischen Drehgeber macht.
Die beiden Zähler für eine Flanke, die einer halben Raster-Drehung nach
rechts/links  entsprechen, resete ich deshalb wenn eine stationäre
Position (d. h. input_l == input_r) erreicht ist.
Damit kann man auch stark prellende Drehgeber gut entprellen, denn
dadurch werden durch Prellen entstehende halbe Raster-Drehungen
ignoriert (fehlerkorrigiert) ;-)

von Peter D. (peda)


Lesenswert?

@nobody0,

also ich verstehe nur Bahnhof.
Welche "beiden Zähler" meinst Du denn, da ist doch nur einer ?

Prellungen werden nämlich durch den Gray-Code automatisch kompensiert.
Wenn Du aber Zweifel an der Funktion hast, dann probiere es doch bitte
erstmal aus, anstatt nur irgendwas zu vermuten.

Bzw. erkläre bitte etwas genauer, was Du eigentlich meinst.


Es ist natürlich möglich, daß man Schritte verliert, wenn man sehr
schnell dreht. Dann muß man aber nur die Abtastzeit verkürzen und schon
gehts wieder.
Der Wert in meinem Beispiel (11,0592MHz  256  8 = 5,4kHz) sollte in
der Regel ausreichend sein.


Peter


P.S.:
Wenn man aber Drehgeber nimmt, die nur alle 2 oder 4 Phasen einrasten,
muß man den Zählwert nach dem Auslesen /2 bzw. /4 teilen.

von nobody0 (Gast)


Lesenswert?

Ich meine einfach einen Zähler für die halben Linksdrehungen und einen
für die halben Rechtsdrehungen. Von einem zum anderen Rasterpunkt hat
man ja zwei halbe Drehungen und am Rasterpunkt einen stationären
Zustand (beide Adern 0 oder 1).
Deshalb setze ich an einem Rasterpunkt beide Zähler auf 0 und logge die
Fehler. Dadurch kann man diagnostizieren wie zuverlässig der Drehgeber
ist und ihn austauchen bevor das Prellen so stark wird, dass es nicht
mehr zu 99,9 % korrigierbar ist.
Ich habe das in einer ISR gemacht und es funktioniert gut, wobei aber
aus Kostengründen auf das Austauschen u. loggen verzichtet wird.

von Peter D. (peda)


Lesenswert?

"auf das Austauschen u. loggen verzichtet wird"

Wenn Du sie nicht auswertest, dann streich sie gleich ganz aus Deinem
Programm. Ist so doch nur toter Code.


Wie gesagt, das Prellen stört bei meinem Code nicht.
Wenn durch eine Störung mal zu weit gezählt wird, wird sofort in der
nächsten Abtastung, wo die Störung vorbei ist, zurück gezählt und alles
stimmt wieder. Deshalb nimmt man ja den Gray-Code.


Peter

von nobody0 (Gast)


Lesenswert?

Den toten Code sollte der Compiler wegoptimieren und wenn es eng wird,
kann ich den betreffenden Code mit defines kapseln.

Dass das Prellen bei mechanischen Drehgebern sehr wohl stören kann,
merkt man wenn einige tausend Geräte produziert werden und einige
reklamierte ein starkes Prellen des Drehgebers zeigen. Da zeigt sich
dann der Unterschied zwischen Theorie und Praxis. Mit Fehlerkorrektur
kann man da noch einiges machen.

Übrigens hat der Gray-Code allein nichts mit Fehlertoleranz zu tun; der
Gray-Code minimiert nur die Hamming-Distanz benachbarter Codeworte,
aber beim Prellen hilft das nicht, weil der Gray-Code allein keine
Fehlerkorrektur macht; er ist kein ECC-Code.

von Peter D. (peda)


Lesenswert?

"Übrigens hat der Gray-Code allein nichts mit Fehlertoleranz zu tun"

Das ist falsch.

Der Trick beim Gray-Code ist nämlich, daß sich immer nur ein Bit
gleichzeitig ändert.
D.h. es kann immer nur ein Signal prellen und das bewirkt nur das Hin-
und Herzählen zwischen 2 aufeinanderfolgenden Zählwerten.
Sobald das Prellen vorbei ist, liegt also immer der richtige Zählwert
vor.


Übrigends ist die Polling-Methode im Timerinterrupt automatisch viel
sicherer, als die Flankeninterrupt-Methode.
Beim Timerinterrupt muß nämlich die Störung zufällig auch noch
gleichzeitig mit dem Abtastzeitpunkt zusammenfallen.

Der Flankeninterrupt wartet dagegen geradezu sehnsüchtig auf jede
Störung und kann dadurch auch auf jeden noch so kurzen Störimpuls (z.B.
elektrostatisch aufgeladene Kleidung) fehlreagieren.


Peter

von nobody0 (Gast)


Lesenswert?

> Der Trick beim Gray-Code ist nämlich, daß sich immer nur ein Bit
> gleichzeitig ändert.

Ja, aber durch Prellen ändern sich kurz hintereinander mehrere Bits und
wenn man die nicht fehhlerkorrigiert, hat man ein (unnötig) starkes
Prellen.
Praktisch sieht das so aus, dass eine Drehung des Drehgebers um ein
Raster meist +/-=2 (statt +/-=1) bewirkt und machmal auch +/-0 (statt
(+/-=1) bewirkt. Mit der Fehlerkorrektur bekommt man diese Fehler fast
immer beseitigt.


> D.h. es kann immer nur ein Signal prellen ...

Falsch; es könen sehr wohl beide Adern gleichzeitig ein Prellen zeigen.
Die Annahme, das zu einem Zeitpunkt nur ein Fehler auftreten kann, ist
einfach falsch. Deshalb sind. z. B. in Kernkraftwerkten die wichtigen
Teile mindestens doppelt redundant, damit zwei gleichzeitig auftretende
Fehler nicht zum GAU führen.
Aus Kosten- oder anderen Gründen wird aber meist mehr als ein Fehler
außerhalb der Vorstellungskraft verlagert ...


> Beim Timerinterrupt muß nämlich die Störung zufällig auch noch
> gleichzeitig mit dem Abtastzeitpunkt zusammenfallen.

Ich nehme natürlich keinen Timer-Interrupt; davon habe ich nix
geschrieben. Ich verwende einen Port-Interrupt.


> Der Flankeninterrupt wartet dagegen geradezu sehnsüchtig auf jede
> Störung und kann dadurch auch auf jeden noch so kurzen Störimpuls
> (z.B.
> elektrostatisch aufgeladene Kleidung) fehlreagieren.

Logischerweise ist vor jedem Eingang mit enabletem Interrupt ein
Tiefpass, der sowas wie Elektrostatische Entladungen rausfiltert.
Bei MCs ohne ausgeprägte Hysterese, wie dem Samsung S3C2410, verwende
ich zwischen dem Tiefpass u. dem MC Schmitt-Trigger.

von nobody0 (Gast)


Lesenswert?

Nachtrag: Hosted (z. B. unter embedded Linux) Polling zu betreiben wäre
keine gut Idee; das benötigt einiges an CPU-Leistung und unterbricht
andere wichitge Tasks.
Mit einem eigenen Tastatur-Contoller ist Polling natürlich immer
optimal, aber aus Kostengründen ist sowas ja selten und sowas wie einen
Tiefpass zum Rausfiltern von elektrostatischen Entladungen kann man
damit nicht komplett ersetzen.

von Peter D. (peda)


Lesenswert?

"das benötigt einiges an CPU-Leistung"

In meinem Beispiel sind das maximal 5%, wobei die Abtastfrequenz sehr
hoch angesetzt ist und bei Bedarf noch reichlich verringert werden
kann.

Ich habe allerdings kein embedded Linux laufen sondern nur nen schnöden
AVR und dem machen die 5% nicht das geringste aus.
Insbesondere, da dieser Timerinterrupt noch ne Menge anderer Aufgaben
mit erledigt, relativiert sich das reine Abtasten auf etwa 2%
CPU-Last.
Bei Mikrokontrollern ist die Verarbeitungsgeschwindigkeit ja noch
linear zur Taktfrequenz. Also ein 16MHz AVR mit 5% CPU-Grundlast ist
exakt gleichschnell wie ein 15,2MHz AVR ohne Grundlast.


Dagegen reagiert der Flankeninterrupt schon auf sehr kurze Impulse
(AVR: wenige ns). Da reichts manchmal, daß man beide Signalleitungen
wenige cm ungeschirmt nebeneinander führt und schon koppelt sich die
Schaltflanke kapazitiv von einem zum anderen Signal über, d.h. beide
Interrupts können auslösen.


Du hast natürlich recht, daß bei absolut schrottigen Drehgebern, z.B.
durch Verschmutzung, lockere Kontaktnieten usw. auch auch auf dem
anderen gerade nicht betätigten Kontakt ein Impuls entstehen kann.
Dagegen ist aber auch jede noch so komplizierte Fehlererkennung
machtlos.
Jede Kette ist nur so stark, wie ihr schwächstes Glied.
Deshalb wird keiner auf die Idee kommen in einem KKW Schrott
einzusetzen und dann an anderer Stelle das mit Software auszugleichen
versuchen, d.h. dieses Beispiel ist einfach hirnrissig.


In Low-Cost Konsumgütern aber zählt kein Mensch die Rastungen mit,
sondern schaut aufs Display was dort angezeigt wird. Und wenn da nach
einer kompletten Umdrehung nur 99 statt 100 angezeigt wird, wen störts,
einfach einen Schritt weiter drehen.


Ich benutze aber auch das gleiche Programm zur Positionsbestimmung, wo
es auf absolute Genauigkeit ankommt. Allerdings werden dort
grundsätzlich optische Positionsgeber verwendet, d.h. die prellen
nicht.
Auch habe ich den Code einfach 3* hintereinander geschrieben, da alle 3
Koordinaten ausgelesen werden müssen. Ich wüßte jetzt gerade keinen µC,
der 6 Flankeninterrupts hat.


Ich denke mal, weitere rein theoretische Vermutungen, daß mein Code
fehleranfälliger sein müßte, nur weil er kürzer ist, sind überflüssig,
solange Du ihn noch nicht einmal ausprobiert hast.
Die Praxis ist doch immer noch der beste Test.

Ich weiß, er ist nicht gerade einfach zu verstehen, aber dann sieht
man, daß er sehr fehlertolerant ist.


Peter

von nobody0 (Gast)


Lesenswert?

Also die Kunden zählen schon mit und wenn die z. B. genau 200 einstellen
wollen aber die Anzeige (mit Einheit 5) mal auf 210 springt oder auf
195 stehen bleibt dann nervt das schon; da kann man schon verstehen,
dass deshalb ausgetauscht wird.

Das mit den 6 Flanken-Interrupts verstehe ich nicht, denn z. B. ein
MSP430F149 hat 16 Eingänge die flankengetriggert sind und der S3C2410
noch einige mehr.

Und Koppeln von Eingängen habe ich noch nie gesehen; ich habe nur mal
Leitungsreflektionen auf einem IIS-Bus gefunden, die aber mit
Tiefpässen problemlos weggefiltert werden konnten.

von Ingo Henze (Gast)


Lesenswert?

Ich würde mal sagen, das hängt wie immer vom speziellen Anwendungsfall
ab :-)

Für mich hat die Timerinterrupt-Abfragemethode den großen Vorteil, das
ich mehrere Drehgeber multiplexen kann.
So benötige ich z.B. für die Auswertung von 8 Drehgebern nur 5
I/O-Leitungen (und etwas Zusatzelektronik: 1aus8-Decoder, Dioden), mit
einer weiteren Leitung (und einem weiteren 1aus8-Decoder) komme ich
dann auf 16 Drehgeber.

von nobody0 (Gast)


Lesenswert?

Für 8 Drehgeber und 5 Leitungen braucht man doch keine
Zusatz-Elektronik, außer eine Diode pro Schalter.
Mit 5 Leitungen kann man doch ganz einfach 4 + 3 + 2 + 1 = 9 Schalter
einzeln abfragen.

von Ingo Henze (Gast)


Lesenswert?

Hmmmm, dat versteh ich nicht ganz !?
Andererseits haben 8 Drehgeber ja zusammen schon 16 Schalter, zumindest
die, die ich verwende (den Drucktaster zähle ich da mal nicht mit, den
brauch ich eh nicht, sonst wären es sogar drei :-).
Kannst Du das bitte mal etwas näher erläutern.
Danke!

von nobody0 (Gast)


Lesenswert?

Achso; bei 16 statt 8 Schaltern ist es etwas anders.

Also bei einer einfachen Matrix-Schaltung braucht man 4+4 Leitungen,
aber es geht effizienter: Man kann ja einfach von der Leitung n zu den
Leitungen n-1 ... 0 je einen Schalter (m. serieller Diode) anschließen,
also insgesammt 0 + 1 + 2 + 3 ... + n-1.
Bei 7 Leitungen kommt man so auf schon 6+5+4+3+2+1=21 Schalter; bei 8
zweiadrigen Drehgebern kann man also bei 7 Leitungen noch 5 Taster
verwenden.
Das ist natürlich nur für den einfachen Fall, dass die Dioden nur den
Strom in eine globale Richtung durchlassen, also von Leitung k nach l >
k oder umgekehrt; allgemein kann man natürlich (n-1)! Schalter
abfragen, also bei n=7 kann man 6*5*4*3*2=720 Schalter abfragen.
Natürlich kann man das auch noch ausbauen, indem man Schalter (mit
Diode) nicht nur zwischen den Daten-Leitungen sondern auch noch +UB und
GND sowie NC verwendet.

von nobody0 (Gast)


Lesenswert?

Korrektur: Mit NC geht's bei Schaltern natürlich nicht ;-)
Mit +UB und GND (über ausreichend hochohmige Widerstände), und weil man
pro Verbindung 2 Schalter (mit antiparallelen Dioden) verwenden kann,
kann man insges. 2*(n-1)! + 2*n Schalter abfragen, also mit 7 Leitungen
1454 Schalter. Zum Dekodieren brauch man aber mehr Rechenzeit als bei
einer einfachen Matrix-Schaltung.

von Ingo Henze (Gast)


Lesenswert?

Ich würde mal sagen, das hängt wie immer vom speziellen Anwendungsfall
ab :-)

Für mich hat die Zusatzelektronik-Methode den großen Vorteil, das
ich die Teile bereits habe, die Schaltung nebst Software erprobt,
übersichtlich und kompakt ist, und der Rechenleistungsbedarf in einem
vertrebaren Rahmen bleibt.
Mit einer weiteren Leitung (und einem weiteren 1aus8-Decoder) kann ich
das ganze bei Bedarf mit nur kleinsten Änderungen der Abfrageroutine
auf 16 Drehgeber erweitern (sofern ich mal eine wirklich günstige
Quelle für die Teile finde sollte:-).

von nobody0 (Gast)


Lesenswert?

Ja, eine Auswertung für 1454 Schalter (an 7 Leitungen (+UB u. +GND) habe
ich bisher auch nur theoretisch gemacht und in der Firma wird bisher
praktisch nur ein Schalter pro Eingang verwendet, obwohl es kaum
ausgenutzt wird; Shortcuts gibt's bisher noch nicht.

Nachtrag zur Grey-Dekodierung: Die einfachen Routinen, vom Anfang des
Threads, habe ich so in vorhandener Software gefunden und durch meine
Variante mit Fehlerkorrektur ersetzt; die ist also praxis-erprobt und
wirksam.

von Ingo Henze (Gast)


Lesenswert?

Andererseits hat das was, 1454 Schalter, das wären ja dann mehr als 700
Drehgeber (wenn ich jeweils zwei Kontakte pro Geber annehme). Ein
unbestimmte Gefühl sagt mir aber auch, das es bestenfalls, wenn
überhaupt, theoretisch funktionieren würde.

Aus meiner Sicht kommt man mit 16 Drehgebern ganz gut hin, denkbar wäre
noch eine Erweiterung auf 24 oder höchstens 32 (ja, dann bin ich schon
bei 7 Leitungen + zwei weiteren 1aus8-Decodern).

Es gibt zwar auch Geräte mit mehr Drehreglern (z.B. Drehbank mit 64),
aber da wird das schon leicht unübersichtlich.
Ich würde dann eher noch 8 Schieberegler und ein oder zwei
Mini-Joysticks dazunehmen.

Falls ich meine Gerät jemals fertig bekomme, kann ich es ja dann mal
kurz hier vorstellen...

von Peter D. (peda)


Lesenswert?

"Die einfachen Routinen, vom Anfang des Threads"

Ich muß gestehen, daß es zwischen beiden Varianten einen kleinen aber
feinen Unterschied gibt:

Die Tabellenversion (1.Beispiel) zählt nicht weiter, wenn ein Übergang
über 2 Stufen erkannt wird, speichert ihn jedoch trotzdem ab. Dadurch
kann es passieren, wenn es sich um ein Prellen beider Kontakte während
eines Übergangs gehandelt hat, daß dann die nächste Abtastung einen
Zähler in die falsche Richtung macht.

Die Differenzmethode (2.Beispiel) ignoriert einen Übergang über 2
Schritte auch, aber speichert ihn nicht ab. Sie zählt also erst weiter,
wenn nur ein einstufiger Übergang erkannt wurde, also die Prellung
vorbei ist.

Die obigen Aussagen bezüglich der Fehlerfestigkeit beziehen sich daher
ausschließlich auf das 2.Programmbeispiel.

Es liegt ja in der Natur der Sache, daß eine spätere Codevariante in
der Regel weiter entwickelt und daher besser ist.

Es würde auch keinen Sinn machen eine gleichartige Funktion zu
veröffentlichen, wenn sie keinerlei Vorteile hätte.


Es gibt im Prinzip folgende Drehgeberaufbauten:

Billige Drehgeber arbeiten mit einer Scheibe mit metallisierten
Segmenten, auf der 3 Schleifkontakte aufliegen. Dann ist es in der Tat
möglich, daß durch Verschmutzungen auch der 2. Kontakt unterbrochen
wird, während er auf der metallisierten Fläche gleitet.

Etwas bessere Drehgeber arbeiten mit einer Art Nockenscheibe, die 2
Mikrotaster abwechselnd betätigt. Damit ist eine gleichzeitige
Umschaltung beider Kontakte ausgeschlossen. Beide können zwar prellen
aber eben nicht gleichzeitig.

Das beste sind aber optische Drehgeber (Mausprinzip). Sie schalten
nicht gleichzeitig und prellen auch nicht.


Und wenn die Portpins nicht ausreichen, kann man an je einen 74HC165 je
4 Drehgeber anschließen und davon beliebig viele per SPI über insgesamt
nur 3 Leitungen einlesen.


Peter

von Andi (Gast)


Lesenswert?

Ich habe festgestellt, das die "billigen", aber bei Conrad sehr teuren
;-), Drehgeber sehr stark prellen können, wie der ddm427, auch wenn man
nicht all zu schnell dreht.
Da gibs entweder nur die passenden Kondensatoren oder, wie Nobody0
meint, Hochpassfilter einzusetzen, oder per Software entprellen.
Habe leider keine passenden Kondensatoren da gehabt (zu klein oder zu
groß) und den Drehgeber per Pin Change IRQ ausgelesen und per Software
entprellt.
Hier der Ausschnitt aus dem Prog für nen Tiny12 mit Pin Change IRQ:

PinIRQ:
.....
rjmp Dreher
.....
PinIRQ1:
  reti

Dreher:
  in r16,pinb         Neuen Wert von A und B auslesen
  andi r16,0b11000    A und B an PB5 und PB4 ausmaskieren
  cp r16,KeyAlt       Hat sich was verändert?
  breq DrExit         Wenn nicht, dann raus

  ldi r16,250         Ca. 1 ms warten, bis evtl. prellen weg ist
Dreher1:
  nop
  dec r16
  brne Dreher1

  in r16,pinb         Neuen Wert erneut einlesen
  andi r16,0b11000    und maskieren
  cp r16,KeyAlt       Vielleicht doch nur ein prellen?
  breq DrExit         Dann raus

  mov r17,r16         Neuen Wert kopieren
  lsr r17             2 mal nach rechts schieben
  lsr r17
  or r17,KeyAlt       und mit dem alten Wert verknüpfen
  mov KeyAlt,r16      Neuen AB-Wert sichern
  ldi r20,0b11110     XOR-Maske für ABAB
  sbrs r17,4          Ist Bit 4 bzw 3 gesetzt?
  eor r17,r20         Wenn nicht, letzen und vorigen AB-Wert
invertieren
  cpi r17,0b10000     War die letzte Bit-Folge von ABAB 1000?
  breq DrLinks        Dann wurde 1 Raster nach links gedreht
  cpi r17,0b10110     War es 1011?
  brne DrExit         Wenn nicht, ein falscher Wert (prellen?)

DrRechts:                   Ansonsten war es eine Rasterstelle nach
rechts
  cpi VZeit,VZeitMax  Abhandlung zur Rechts-Drehung
  breq DrExit
  ldi r16,VZeitStep
  add VZeit,r16
DrExit:
  rjmp PinIRQ1

DrLinks:
  cpi VZeit,VZeitMin  Abhandlung zur Linksdrehung
  breq DrExit
  subi VZeit,VZeitStep
  rjmp PinIRQ1

Bin damit am besten zurecht gekommen und habe es in eine Pin Change
Interruptroutine geschmissen.
Da muß man schon sehr schnell drehen, ca. in 0,3 Sekunden einmal um die
Achse, damit das Prog den Faden bzw. die Impulse oder Prellungen
empfängt verliert.
Und das trotz der Wartezeit von ca. 1 ms die ja als Entprellung dienen
soll.
Und wenn keiner am Geber dreht wird das Sub-Prog nicht ausgeführt.

Gruß
Andi

von nobody0 (Gast)


Lesenswert?

Das Problem bei 700 drehgebern an 7 Leitungen wäre das Abfragen - es muß
mit Pin-Wackeln (ein Pin high, alle anderen, bis auf den einen auf low
usw.) geprüft werden ob der Schalter zwischen Leitung 0 u. 1 und der in
umgekehrte Richtung geschlossen ist usw. - also 1400 einzelne Abfragen.
Damit wäre ein Tastatur-Controller wohl voll ausgelastet.
Aber man kann so viel Hardware sparen ...

von Andi (Gast)


Lesenswert?

Ja wie denn?
Ich check immer noch nicht, wie man an 7 Leitungen 700 Drehschalter
oder 1400 Taster dranbekommen soll.

Gruß
Andi

von nobody0 (Gast)


Lesenswert?

Ganz einfach: Ein Schalter mit eine Diode, so dass Strom nur von Leitung
0 nach 1 fließen kann, einer in entgegengesetzter Richtung usw..
Dann muß beim Abfragen ein Pin auf low gelegt werden und alle anderen,
bis auf einen (Eingang mit pullup) auf high. Wenn der eine Eingang low
ist, dann ist der Schalter von der Leitung auf low zu dem einen Eingang
geschlossen.

So komme ich nun je Eingang auf 2*(n-1) Schalter und insgesammt auf
2*n*(n-1) also 2n^2-2n; bei 7 also 35.
Da ist mir wohl ein Flüchtigkeitsfehler unterlaufen ...

Jedenfalls bekommt man so deutlich mehr als mit einer Matrix-Schaltung;
bei 7 Leitungen wären mit einer Matrix-Schaltung nur maximal 3*4=12
Schalter anschließbar.

Das fakultative Ansteigen, das ja stärker als ein exponentielles
Ansteigen ist, bekommt man hin, wenn man n Leitungen mit n Leitungen
verbindet, denn das entspricht einer Permuation von n Elementen und von
denen gibt es bekanntlich n!. Das hatte ich mit Schaltern verwechselt,
weil es verwandte Sachen sind.

von nobody0 (Gast)


Lesenswert?

Naja, um diese Zeit stimmt das Beispiel nicht ganz; 2*n(n-1) ist mit n=7
natürlich 84. Gegenüber der einfachen Matrix-Schaltung hat man damit 7
mal mehr Schalter!

von nobody0 (Gast)


Lesenswert?

Nachtrag: Je nach verwendeten Pegeln muß man die Dioden ggf. geeignet
auswählen (höhere Schwellspannung), damit nicht Strom über mehrere
Schalter (u. den seriellen Dioden) fließt. Bei sowas wie 1N4148 braucht
man sonst einen MC mit einer Versorgungsspannung um 2 V, aber viele MCs
sind ja bis 1,8 V spezifiziert.

von nobody0 (Gast)


Lesenswert?

Also das Abfragen habe ich mir nochmal mit einem MC mit Pullups
überlegt: Es muß Leitung m auf GND geschaltet werden, während alle als
Eingänge mit Pullups geschaltet sind. Dann sind alle diejenigen
Eingänge auf 0, bei denen der Schalter zw. m u. der Leitung geschlossen
ist. So testet man insgesamt n mal durch. Bei einem 16-Bit-Port kann
man so mit 16 Port-Abfragen 240 Schalter abfragen.

Da fällt mir auch auf, dass es natürlich nur n*(n-1) Schalter sind (d.
h. ohne Faktor 2), die man so abfragen kann ...

Jedenfalls hat man so n^2-n gegenüber (maximal) (n/2)^2 gegenüber der
Matrix-Schaltung, also bei n=7 schon 3,5 mal mehr Schalter.

von philip (Gast)


Lesenswert?

hmms

könnte bitte einer mal das programm für nen 2313 umportieren ?
und wenn an dreht das ein kurzer impuls für jede richtung an einem
pin ausgegeben wird?

währ ich echt dankbar für!!!! ich komme einfach nicht weiter

von avusgalaxy (Gast)


Angehängte Dateien:

Lesenswert?

Ich glaube, so müßte es gehen...

von Philip (Gast)


Lesenswert?

schon mal danke, kannst du mir auch die pins duch sagen ?
b1 zb oder b2 ... d etc.. das ich die pins weiss werd da net so ganz
schlau raus

von avusgalaxy (Gast)


Lesenswert?

An PORT D,0 und PORT D, eins kommt jeweils eine Led.

Ab PORT D... 4 und 3 den Drehgeber.. Ah ja, so solls ausehen:


.include "2313def.inc"

.set DIPGPin=PinB    ;Port mit Drehimpulsgeber
.set DIPGChA=4       ;Pin mit Channel A
.set DIPGChB=3       ;Pin mit Channel B
.set DIPGBT=2        ;Pin mit Button
.def DIPGAlt=r4      ;Vorriger Zustand von Channel A
.def DIPG=r5         ;Drehimpulsgeber-Aktion. Nach Abfrage löschen
.def ButtonAlt=r6    ;Vorriger Zustand des Buttons

 ldi r16, RAMEND  ;Stackpointer initialisieren
 out SPL, r16

 ldi r24, 0xff
 out DDRD, r24

 ldi r24, 0xff
 out PORTD, r24

 ldi r24, 0xff
 out DDRb, r24

main:

 in r17,DIPGPin      ;1   Drehimpulsgeber lesen
 mov r18,r17         ;1   und in die Working-Register
 mov r19,r17         ;1   kopieren

 andi r18,1<<DIPGChA ;1   Channel A des Drehgebers ausmaskieren.
 cp r18,DIPGAlt      ;1   Hat es sich verändert?
 breq DrButton       ;1/2 Wenn nicht, dann Button prüfen.
 mov DIPGAlt,r18     ;1   Aktuellen Zustand von Channel A sichern
 lsl r19             ;1   Aus der Kopie des Drehgeberports
 andi r19,1<<DIPGChA ;1   Channel B ausmaskieren.
 cp r18,r19          ;1   Ist Channel A = Channel B?
 breq DrLinks        ;1/2 Wenn ja, dann wurde nach links gedreht
DrRechts:
 rcall rechts
 rjmp DrButton
DrLinks:
 rcall links
 rjmp DrButton
DrButton:

 tst DIPG           ;Wurde vorher abgeholt?
 brne main        ;Wenn nicht, dann Ende
 mov DIPG,r16
 rjmp main

links:
 cbi PORTD,0
 rcall pause
 sbi PORTD,0
 ret

rechts:
 cbi PORTD,1
 rcall pause
 sbi PORTD,1
 ret

pause:


          ldi  R21, 0x72
schleife1:ldi  R22, 0xF2
schleife2:dec  R22
          brne schleife2
          dec  R21
          brne schleife1

      ret

von avusgalaxy (Gast)


Lesenswert?

Kann es momentan leider nicht testen, aber ich glaube, ads es geht..

von Philip (Gast)


Lesenswert?

ich werde mal schnell die schlatung aufbauen und das ganze auf den avr
laden, könntest du mir eventuell noch schnell die hex machen ?
dann gehts schnell weiss net wo mein compiller is..

von avusgalaxy (Gast)


Lesenswert?

????? Soll ich dir auch noch einen 2313 schicken?

von Philip (Gast)


Lesenswert?

ne danke hab 4 stück hier liegen, ne scho okay trozdem hab den compiler
gefunden^^ werds gleich mal auf spielen such gerade noch widerstände...

von Philip (Gast)


Lesenswert?

habs mal aufgebaut, aber so richtig funz es net...
hmms auf wie viel mhz hast du es laufen ? ich hab derzeit nen 10mhz
quarz dran...

von Dominik (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

habe versucht den zweiten Code von Peter zum laufen zu kriegen. Ich
verwende einen AT90S2313 und den Drehgeber dessen Datenblatt im Anhang
ist.
Ich habe den gemeinsamen C - Anschluss auf 5V gelegt und A und B über
10k Widerstände gegen Masse. Dazwischen gehts jeweils zu einem Port-Pin
(PD.0 und PD.1) vom µC.

Habe am PortB LED's angeschlossen um zu schauen was die Variable
enc_delta macht, aber es leuchtet dauernd nur die LED an PB.0 (auch
keine Frequenz). Ich kann den Drehgeber drehen wie ich will, es tut
sich nichts.

Kann mir jemand weiterhelfen? Programmiere in CodevisionAVR.

Hier mein Code:


#include <90s2313.h>


volatile char  enc_delta;    // -128 ... 127




interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
 static char enc_last = 0x01;
  char i = 0;

  if( PORTD.0 )
    i = 1;

  if( PORTD.1 )
    i ^= 3;        // convert gray to binary

  i -= enc_last;      // difference new - last

  if( i & 1 ){        // bit 0 = value (1)
    enc_last += i;      // store new as next last

    enc_delta += (i & 2) - 1;    // bit 1 = direction (+/-)
  }
}


void main(void)
{

State7=0
PORTB=0x00;
DDRB=0xFF;

PORTD=0x00;
DDRD=0x00;

TCCR0=0x04;
TCNT0=0x00;


TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
OCR1H=0x00;
OCR1L=0x00;


GIMSK=0x00;
MCUCR=0x03;
GIFR=0x40;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x02;


ACSR=0x80;

// Global enable interrupts
#asm("sei")
while (1)
      {
      // Place your code here
      PORTB = enc_delta;
      };
}



Gruß, Dominik

von Wolle (Gast)


Lesenswert?

Wenn ich nicht irre, ist der Code so ausgelegt, dass "C" an 0V liegt.
Demzufolge werden die Pins dann wechselweise (Gray-Code) nach 0V
gezogen.
Probiers halt mal.

von Dominik (Gast)


Lesenswert?

Hab's geändert, aber es tut sich immernoch nicht mehr :-(

von Peter D. (peda)


Lesenswert?

if( PORTD.0 )
    i = 1;

Da kannste lange warten.

Du must schon das Input-Register nehmen.


Peter

von Dominik (Gast)


Lesenswert?

AAAAAAAAARRRRGGGGGHHHH, sowas passiert mir immer wieder...


Danke Peter!

von Dominik (Gast)


Lesenswert?

Funktioniert nun prima, allerdings wird die Variable bei jedem Schritt
um 2 verändert, wie kann ich das ändern?

Danke, Dominik

von Peter D. (peda)


Lesenswert?

Drehgeber für manuelle Bedienung machen oft 2 oder 4 Pegelwechsel je
Rastung.

Einfach dann den Wert vor der Auswertung 1* nach rechts schieben:

int count;

cli();
count += enc_delta >> 1;
enc_delta = 0;
sei();


Peter

von philip (Gast)


Lesenswert?

könnte man den ganzen code nun korigiert noch mal posten?

von Dominik (Gast)


Lesenswert?

Wieso? Im Code waren doch keine Fehler?!?!

von Philip (Gast)


Lesenswert?

Drehgeber für manuelle Bedienung machen oft 2 oder 4 Pegelwechsel je
Rastung.

Einfach dann den Wert vor der Auswertung 1* nach rechts schieben:

int count;

cli();
count += enc_delta >> 1;
enc_delta = 0;
sei();


Peter



angeblich schon?
und ich hatte auch probleme mit dem programm
die led ging nimma aus ?!

von Dominik (Gast)


Lesenswert?

Ich werte das ganz anders aus, lasse auch die Interupts an, da der Rest
von meinem Programm sonst streikt.

von peter dannegger (Gast)


Lesenswert?

Üblicher Weise will man ja mit einem Drehgeber mehrere Parameter
einstellen, je nach Menüpunkt.

Und count ist hier nur stellvertretend für irgend einen Parameter in
irgend einem Menü.

Die Beispielroutine betrifft das nicht, sondern eben nur die
Weiterverarbeitung.
Ist ja nur ein Beispiel und keine komplette Anwendung.


@Dominik

Eine Interruptsperre ist immer notwendig, wenn man Variablen
bearbeitet, die auch ein Interrupt in den Fingern hat.
Im Beispiel ist das eine Sperre von etwa 1µs, kann also gar keinen
Einfluß auf andere Programmteile haben.



Peter

von Philip (Gast)


Lesenswert?

kann einer das eventuell so umbauen, das ich bei ner endsprechenenden
drehbewegung zb nach rechts nen kurzen impuls bekomme und nach links
wieder einen auf nen bestimmten port´?

so dasich von auß0en weiss das das teil gedreht wird endweder nach
links oder nach rechts....

währ einer so nett?

von nobody0 (Gast)


Lesenswert?

Geht nicht; so einen Drehgeber für Dummys gibt's nicht.
Du mußt die aktuelle Flanke (steigentd/fallend) und dabei den Zustand
der anderen Ader (high/low) auswerten.
Wenn man alle Flanken auswertet, kommt man auf halbe Schritte, durch
die man die meisten Fehler rausfiltern kann.

von Hermann (Gast)


Lesenswert?

ich habe eure unerhaltung -hoffentlich ganz - gelesen. sie wure mir von
peter danegger empfohlen. Doch glaube ich nicht, sie in meinem fall
anwnden zu können.
Ich weiss zwar noch nicht welchen controller ich schussendlich
verwenden werde, doch besteht meine aufgabe ... mein ziel... darin
dieses signal über den controler mittels profi bus an eiene sps
weiterzuschicken!!
ich habe scho einmal ein reines empfang und anzeigeprogramm
geschreiben, doch hier werden mehrere takte benötigt!
so denke ich, dass ich zu langsam für einen impulsgeber werde. sollte
das nicht stimmen bitte ich um antwort.

von nobody0 (Gast)


Lesenswert?

Du solltest den Gray-Encoder in den Controller packen und den Status des
Gray-Encoders über den Bus schicken, wenn sich der Status geändert hat.
Je nach Anwendung sollte das limitiert sein, also z. B. nach jedem
Datenpaket vom Controller eine Sendepause von mindestens 100 ms.

von Hermann (Gast)


Lesenswert?

soweit ich das mitbekommen habe, ist der grey code nichts anderes als
die beiden signale, die ich vom impulsgeber bekomme, und aus denen ich
die information über vor - rück und "stand" holen kann.
was mache ich wenn ich ein signal übersehe, also wie ich meine zu
langsam bin???
oder ist das direkt schicken abhilfe genug?

von nobody0 (Gast)


Lesenswert?

Also entweder muß man die Flanken über Interrupts einlesen oder über
eine Timer-ISR die Leitungen mit mindestens 10 kHz auslesen.

von Hermann (Gast)


Lesenswert?

aso jetzt verstehe ich:

auswerten am controller (mittels tabelle) aber status nur bei änderung
oder nur in bestimmten intervallen

von nobody0 (Gast)


Lesenswert?

Ja, die Information, daß sich nichts geändert hat, braucht man ja
normalerweise nicht übertragen. Sofern im System keine Daten verloren
gehen, ist sowas komplett überflüssig.

von Hermann (Gast)


Angehängte Dateien:

Lesenswert?

noch eine frage:
ich habe eine schalturg empfhlen bekommen, die extern decoded und einen
insgesamt 32 bit zähler enthält??
was soll ich davon halten?
die schaltung (im .doc format ist von der hctl 2020 verbindung mit 051)

von Hermann (Gast)


Lesenswert?

verbindung mit 8051 natürlich!!

von Hermann (Gast)


Lesenswert?

bei dieser schaltung ist jedoch insgesamt 3x zu demultiplexen
und das is nicht was ich mir unter sinnvoll und einfach vorstelle!!!!

von Peter D. (peda)


Lesenswert?

Nimm doch einfach einen AT89C2051 der den Drehgeber einliest und dann in
den Profibus umsetzt.

Dürfte wesentlich billiger sein als der HCTL2020.

Ob Du dann 32 oder 64 Bit zählst ist auch egal.

Ist der HCTL2020 nicht außerdem abgekündigt (last order 06/2005) ?


Peter

von Hermann (Gast)


Lesenswert?

du meinst einen anderen controller???
ich hatte zuerst vor die 90er serie zu verwenden, da ich da das 200stk
besitze!
der externe zähler wäre wahrscheinlich wegen der geschwindigkeit!

ich habe eben bedenken wegen der geschwindigkeit, wenn extern ein 32
bit zähler vorgeschlagen ist!!!!

von Peter D. (peda)


Lesenswert?

Das war nur ein Beispiel, ein ATTiny26 oder ähnliches geht natürlich
auch.

Für die Abtastgeschwindigkeit ist nur die maximale Drehgeschwindigkeit
entscheidend, also wieviele Phasenwechsel pro Sekunde.
Der Timerinterrupt sollte mindestens doppelt so oft kommen.

Die Zählbreite ist uninteressant.


Peter

von Jörg (Gast)


Lesenswert?

@Peter
>Nimm doch einfach einen AT89C2051 der den Drehgeber einliest und >dann
in
>den Profibus umsetzt.

auch wenn es etwas am Thema vorbei ist, aber was machst Du denn mit
einem AT89C2051 am Profibus? Ich dachte bisher, dass da nur etwas vom
Schlage eines SPC3 o.ä. zu finden ist. Die eigentliche Übertragung ist
zwar nur RS485 und UART, aber das ganze Protokoll...? Sollte das
wirklich in einen 2k-8051er passen?

Jörg

von Hermann (Gast)


Lesenswert?

du meinst es ist von grund auf sinnlos??
also ist das projekt abzublasen???

von peter dannegger (Gast)


Lesenswert?

"du meinst es ist von grund auf sinnlos??
also ist das projekt abzublasen???"


Aber wer wird denn gleich aufgeben.

Die maximale Datenrate von 12MBaud schafft der zwar nicht, aber
93,75kBaud geht.
Bzw. mit nem ATMega8 oder AT89LP4052 bis zu 500kBaud.

Das Protokoll zu implementieren dürfte eher eine Frage Deiner
Programmierkünste sein oder du kriegst irgendwo was fertiges.


Oder Du nimmst irgendein fertiges Profibus-IO-Modul und der ATTiny26
(oder was auch immer) übergibt nur die Zählwerte (seriell oder
parallel).


Peter

von Hermann (Gast)


Lesenswert?

Danke für deine weiteren Bemühungen. ich habe jetzt eine Lösung
gefunden:
             Ich lese das Signal mittels HCTL2032 aus und lese dann
alle x ms ein. Denn mit dem Profi BUS übertragen wird der Controller
genug zu tun haben.

von holm (Gast)


Lesenswert?

Scahue Dir mal den LS7366 von LSI/CSI an, hat einen Quadraturdecoder
und
wird über eine SPI angehängt.  Distributor ist die Scantec GmbH in
Germering.
Der hat auch einen internen 32 Bit Counter sowie Carry/Borrow Ausgänge
zur externen Kaskadierung.

Ich habe hier auch so was vor, allerdings arbeite ich mit optischen
Encodern mit
2500 Impulsen/Umdrehung und bis zu 80Khz Impulsfrequenz im 4x Mode.
Ich muß mir dazu noch eine Regelung einer PWM mit AVR einfallen
lassen.

Momentan weiß ich da noch gar nicht recht wie ich da anfangen soll...
2 LS7366 habe ich als Samples bekommen.

Gruß,

Holm

von peter dannegger (Gast)


Angehängte Dateien:

Lesenswert?

@Holm,

das Problem dürfte aber sein, den LS7366 zu beschaffen und billig
dürfte so ein Exot auch nicht gerade sein.

Aber die 80kHz sind auch ohne weiteres auch mit einem µC zu schaffen.
Wenn man mit 160kHz abtastet, hat der ATTiny bei 16MHz internem Clock
immer noch massige 100 Zyklen Zeit.

Und wenn man in Assembler optimiert, braucht man nur max 26 Zyklen im
Interrupt.
D.h. man kann ohne weiteres alle 32 Zyklen abtasten, also noch Signale
bis 250kHz fehlerfrei einlesen.

Anbei die Encoder-Routine in Assembler.
Nur Timer Initialisierung und SPI fehlt noch.


Auch 80kHz sind also noch lange kein Grund, teure und schwer
beschaffbare Exoten zu nehmen.


Peter

von keksohr (Gast)


Lesenswert?

währ einer bereit für die conrad drehimpuls potis be routint zu coden ?
für einen S2313 ?avr

?

das bit muster der 2 pins kann ich gerne raus geben..

was ich brauche ist ne ganz einfache schaltung die 2 bins jeweils auf
high setzt und dann wieder auf low, so das ich nen kurzen impuls nur
habe, für jede dreh richtung einen pin, sprich dreht man nach links ->
pin 1 auf high, dreht man nach rechts -> pin 2 auf high,....

schalt plan kann ich gerne mit geben, wo die pins stehen und das bit
muster was den avr vom dreh impuls geber erwartet... sind 2 leitungen
vom impulsgeber...

währ echt sehr sehr danbakar hab das teil seid 2 monaten und komme
einfach nicht mit der software im avr klar, hab das www ach schon wie
blöde durchsucht...

von holm (Gast)


Lesenswert?

@peter:

Ja.
Ich habe auch schon daran gedacht einen 2313, von denen hier einige
herumliegen, für sowas zu mißbrauchen. Irgendwo gibt es auch eine
Implementation mit einem 90S1200 in Assembler.
Momentan habe ich den Decoder in ein GAL(16V8) gebrannt und da kommt
ein Richtungssignal und ein Clock heraus. Die Mimik wird mit 1,8432
Mhz
getaktet und der Ausgangsimpuls ist nur eine halbe Periode breit.
Diese Mimik habe ich an einen AtMega16 gehängt und befeuere damit  den
externen Int0. Die ISR hat nicht mehr zu tun, als nach am Port nach der
Richtung zu fragen und den 32 Bit Counter zu incrementieren oder zu
decrementieren.
In der Hauptschleife zeige ich auf einem LCD Drehzahl und sowas an. Das
Ganze in C (gcc). Der mit 16Mhz getaktete AtMega16 verliert dabei aber
Interrupts. (Die sind Flankengetriggert!)
Ich habe die Clockimpulse mit einem 74LS74 aufgefangen und bestätige
diese
mit einer Art INTACK Signal um das FF wieder zurückzusetzten.
Das geht besser, Allerdings gefiel es mir halt selber nicht.

Dazu käme eigentlich noch ein digitales Filter für die A und B
Phasensignale
aus einem weiteren GAL und 2 74LS72. (oder halt CMOS, aber die GALs
sind
ja auch schon heftig mit der Stromaufnahme). An der Stelle habe ich
mich umgesehen, was es sonst noch so gibt. Ich habe irgendwo mal 2
HCTL2016
ausgeschlachtet, aber deren Interner Zähler ist zu klein (16 Bit) und
es gibt außen kein Signal das irgendwie Bescheid gibt, daß sich am
Geber was getan hat. Man muß das Ding also pollen.... find ich doof.
Ein HCTL2020 war mir zu teuer, ist aber dem LS7366 ähnlich und enthält
wie dieser schon die digitalen Filter.

In AVR Assembler bin ich überhaupt nicht firm, habe ich noch nicht
gebraucht.
Ich kann das Zeug zwar lesen, aber nicht schreiben :-) Ich kenne aber
Assembler diverser anderer Micros, Z80 Maschine teilweise noch aus dem
Kopf, auch Ekeldinger wie 8048 hatte ich schon mit teilweise
selbst(um)gebauten Assemblern zwischen den Fingern aber auch 51er
68000er und 6809/11.

Bei dieser speziellen Sache hier geht es mir um Nichts weiter, als die
Steuerung
meiner im Bau befindlichen 2. Trafowickelmaschine. (Ich mache auch noch
mit Röhren rum und brauche ab und an Ausgangstrafos).

Ich bräuchte da vielleicht mal ein paar Hinweise oder mal ein Beispiel
in irgend einer Form, welche Algorithmen es gibt um einen
Gleichstrommotor mittels Drehgeber und PWM  bestimmte Positionen
anfahren zu lassen.
Ich habe aber keine PWM Brücke gebaut, sondern habe da ein Relais für
die Drehrichtungsumkehr, einen 100W Getriebemotor und eine PWM Stufe
mit einem IGBT, das Zeug klappt soweit ganz gut.
Ich habe aber natürlich, weil das ein Bastelobjekt ist, keinerlei Daten
über Massenträgheiten oder ähnlichen Kram, des noch nicht fertigen
mechanischen Systems. Irgendwie soll das Ding mal "weich" die
Drehzahl regeln, gegen Ende einer Wicklungslage langsamer werden und
stehen bleiben damit man Lagenisolation einfügen kann usw. usf. Die
Drahtverlegung soll ein Schrittmotor mit einer Spindelmimik machen, der
mittels programmierbarem Teilerverhältnis von den Drehgeberimpulsen
angesteuert wird, natürlich soll das Ding auch noch selber ausrechnen
wie das Teilerverhältnis bei unterschiedlichen Drahtstärken auszusehen
hat.
Den Schrittmotor werde ich mit einem TA8345H Ansteuern, der ist
programmierbar von Voll- bis Achtelschritt, sowas liegt hier gerade
herum (fertige kleine Endstufen).
Die Drahtspannung, und damit natürlich auch die Last des Motors soll
natürlich auch variabel sein, also wo und wie fange ich an ....?

Suggestions?

Danke,

Holm

von Hermann (Gast)


Lesenswert?

Hallo Holm

Ich habe die 20xx (keinen!!!) bekommen.
doch habe ich jetz eine Seite gefunden, wo ich 7366 kaufen(scantec
schickt nicht nach Ö) kann.

Was hast du mit deinen IC gemacht?
Wie funktioniert deine Steuerung bzw Regelung?
Könnte ich vielleicht die SPI Kommunikations Source haben?


danke hermann

von Birger* (Gast)


Lesenswert?

Wo bekommt man denn diese Drehgeber? Hab in der Vergangenheit den DDM427
von Conrad verwendet, doch nun soll er angeblich nicht mehr lieferbar
sein. Bei RS hab ich auch noch keinen gesichtet und bei Reichelt erst
recht nicht.

Noch ne Anmerkung zur Programmierung. Die DDM427 sind eigentlich nur im
Interruptbetrieb einsetzbar, weil dieser Drehgeber im Vergleich zu
anderen nicht statisch abfragbar ist.
Nimmt man das im Datenblatt vorgeschlagene RC-Glied zum Entprellen, so
geht das ganz wunderbar.

von Andi (Gast)


Lesenswert?

"Die DDM427 sind eigentlich nur im
Interruptbetrieb einsetzbar, weil dieser Drehgeber im Vergleich zu
anderen nicht statisch abfragbar ist."
So ein schmarrn!
Ich setze den DDM427 sowohl im PKW im Pin Change Interrupt an einem
Tiny26 mit RC-Glied und zu Hause im Polling-Modus ohne RC-Glied, wo der
Geber aus dem Timer-Interrupt mit 10KHz abgefragt wird, ein.
Beides geht wunderbar.

MfG
Andi

von Birger* (Gast)


Lesenswert?

Na, jetzt mal nicht so deftig dahergeplappert. Die Treffsicherheit im
Pollingmodus ist deutlich geringer als wenn man Interrupts verwendet.
Ich hab's ausprobiert. Wenn mann wenig Rechenzeit verbraten möchte,
ist der Pollingbetrieb jedenfalls nicht optimal.

Und wo krieg ich jetzt neue Drehgeber her?

von Andi (Gast)


Lesenswert?

War das so heftig?
Tschuldigung!
Mal im Ernst.
Im Polling-Modus, und vor allem ohne RC-Glied, sollte man natürlich
eine Soft-Entprellung mit einbauen, welche man für den Button gleich
mit verwenden kann, oder das Verfahren von Peter, hier ganz oben,
verwenden.
Auf jeden Fall, gehn tut das, habe ja beides erfolgreich ausprobiert.
Und wenn man sowieso einen 10KHz-Timer wegen viele anderer Dinge im
Einsatz hat ist das auch nicht mehr die Welt, zumindest in ASM.

Das Conrad die nicht mehr hat verstehe ich nicht, immer hin haben die
bei deren Preis wohl recht gut daran verdient.
Wahrschinlich zu geringe Mengen davon verkauft und dann ausgemustert.
Weis auch nicht, wo man den selben Typ her bekommt und Reichelt hat
leider immer noch keine Geber.

MfG
Andi

von Elektrikser (Gast)


Lesenswert?

Hallo,

warum sollte der DDM427 bei Conrad nicht mehr lieferbar sein? Im
Online-Katalog sind die als sofort verfügbar gekennzeichnet.
(Bestellnr.: 705514-07; 705526-07; 705538-07)
Hast du nähere Infos?

Gruß Elektrikser

von Birger* (Gast)


Lesenswert?

Für meine Diplomarbeit brauch ich noch dringend 'nen neuen Drehgeber.
War deswegen bei Conrad in der Filiale Dortmund. Dort waren keine
vorrätig und auch nicht lieferbar (Best.-Nr. 705514) - laut Aussage des
"Fachmanns" hinterm Tresen.

von JojoS (Gast)


Lesenswert?

bei Neuhold Elektronik gibts einen guten und günstigen (5 Euro):
http://www.neuhold-elektronik.at/catshop/default.php?cPath=41_56_153
der liefert hier auch ohne Entprellung gute Ergebnisse.

von Ampel (Gast)


Lesenswert?

Tach zusammen,

ich hab grad auch eine Anwendung, wo ich ein Dreh-Encoder (auch Jog-Rad
genannt) einsetze. Damit will ich in einem Menue rumdrehen und mit der
Taste am Dreh-Encoder meine Auswahl treffen (Eigentlich wird nur ein
Zähler auf- oder abwärts gezählt).
Die Spur A ist auf einem Interrupt gelegt, Spur B liegt auf einem Port
ohne Interrupt. Erfolgt eine Drehung, springt der Interrupt mit der
Spur A an. Dann kommt eine Auswertung wie Spur A steht, gleichzeitig
wie Spur B steht. Der Wert wird mit dem letzten Wert verglichen. Ist es
unterschiedlich, wird entschieden, ob ein Zähler auf- oder abwärts
zählt.
Aber irgendwie ist das nicht das wahre: drehe ich langsam, kommt
manchmal Mist raus, drehe ich zu schnell ebenso.
Wie habt Ihr die Abfrage des Dreh-Encoders realisiert? Sollte ich
anstatt des Interrupts einen Timer nutzen (wenn ja, wie)?

Gruss,
Ampel

von Thorsten (Gast)


Lesenswert?

> Wie habt Ihr die Abfrage des Dreh-Encoders realisiert? Sollte ich
> anstatt des Interrupts einen Timer nutzen (wenn ja, wie)?

Schau dir mal den ersten Beitrag an. Funktioniert einwandfrei!

von Rolf F. (Gast)


Lesenswert?

Ich habe es mal auf MSP430 und ARM9 mit Fehlerkorrektur gemacht, da ja
von einer Position zur nächsten zwei Interrupts kommen, und folglich
jeder als ein halber Schritt gezählt werden sollte. Zählt man jeden
Interrupt als halben Schritt, dann sind auch prellende Drehgeber kein
Problem, wie auch Praxis-Tests zeigten. Das langsame Drehen bekommen
man mit der Hand hin; das schnelle mit einer Bohrmaschine.
Hier der Code für MSP430:
1
// Macro for setting the IES flags for the gray encoder consitent.
2
// E. g. BIT6 set -> set the associated IES (for IRQ on falling edge).
3
// Has to be called e. g. at the start of main.
4
#define mc_CONSISTENT_J \
5
{ \
6
if (P2IN & BIT6) \
7
 P2IES |= BIT6; \
8
else \
9
P2IES &= ~BIT6; \
10
if (P2IN & BIT7) \
11
  P2IES |= BIT7; \
12
else \
13
  P2IES &= ~BIT7; \
14
}
15
16
signed char c_gc_c = 0;         // grey code (interrupt) counter with
17
sign for direction: + means right
18
unsigned char uc_l = 0;         // counter for the irqs from left
19
output (port2, Bit6) of grey encoder
20
unsigned char uc_r = 0;         //                           right     
21
 (port2, Bit7)
22
uint32_t uli_errors = 0;
23
24
// macro for resetting the grey encoder variables (above)
25
// Has to be called e. g. at the start of main.
26
#define mc_RESET_J \
27
{ \
28
P2IFG &= ~(BIT6 | BIT7); \
29
c_gc_c = 0; \
30
uc_l = 0; \
31
uc_r = 0; \
32
}
33
34
#define mc_c_gc_cP {if (c_gc_c < 100) ++c_gc_c;}   // one step with
35
direction, increment with saturation
36
#define mc_c_gc_cM {if (c_gc_c > -100) --c_gc_c;}  // decrement
37
38
#define mc_uc_lP {if (c_gc_c < 100) ++uc_l;} // one step left;
39
increment with saturation
40
#define mc_uc_rP {if (c_gc_c < 100) ++uc_r;} // one step right
41
42
43
In der ISR:
44
    switch (P2_IRQs & (BIT6 | BIT7))     // Mask for BIT6 and BIT7.
45
    {
46
      case 0:                  // no irq; should never happen
47
        uli_errors++;
48
        break;
49
50
      case (BIT6 | BIT7):      // 2 irqs; should never happen
51
        mc_uc_lP;
52
        mc_uc_rP;
53
        uli_errors++;          // error
54
        break;
55
56
      case BIT6:
57
        mc_uc_lP;
58
        switch (P2IES & (BIT6 | BIT7))
59
        {
60
          case 0:              // 00 -> 01 (P2IN, bit6 = 0  and bit7 =
61
1), right
62
            mc_c_gc_cP;
63
            break;
64
65
          case (BIT6):         // 01 -> 00, left
66
            mc_c_gc_cM;
67
            break;
68
69
          case (BIT7):         // 10 -> 11
70
            mc_c_gc_cM;
71
            break;
72
73
          case (BIT6 | BIT7):  // 11 -> 10
74
            mc_c_gc_cP;
75
            break;
76
77
          default: // can never happen
78
            uli_errors++;
79
            break;
80
        }
81
        break;
82
83
      case BIT7:
84
        mc_uc_rP;
85
        switch (P2IES & (BIT6 | BIT7))
86
        {
87
          case 0:              // 00 -> 10
88
            mc_c_gc_cM;
89
            break;
90
91
          case (BIT6):         // 01 -> 11
92
            mc_c_gc_cP;
93
            break;
94
95
          case (BIT7):         // 10 -> 00
96
            mc_c_gc_cP;
97
            break;
98
99
          case (BIT6 | BIT7):  // 11 -> 01
100
            mc_c_gc_cM;
101
            break;
102
103
          default: // can never happen
104
            uli_errors++;
105
            break;
106
        }
107
        break;
108
109
      default: // can never happen because only PIN6 and PIN7 are
110
interrupt enaled
111
        uli_errors++;
112
        break;
113
    }
114
    mc_CONSISTENT_J;
115
116
    if (((P2IN & BIT6) >> 6 == (P2IN & BIT7) >> 7)      // equal
117
inputs
118
        && (uc_l)               // left irq
119
        && (uc_r)               // right irq
120
      )                         // stationary position
121
    {
122
      if (c_gc_c <= -2)
123
      {
124
        if (c_gc_c < -2)
125
          uli_errors++;          
126
        KEYBOARD.key[KEYBOARD.start] = KEY_JOG1PLUS; // one step right
127
        KEYBOARD.start++;       // new input
128
        mc_RESET_J;
129
      }
130
      else
131
      {
132
        if (c_gc_c >= 2)
133
        {
134
          if (c_gc_c > 2)
135
            uli_errors++;
136
          KEYBOARD.key[KEYBOARD.start] = KEY_JOG1MINUS; // one step
137
left
138
          KEYBOARD.start++;     // new input
139
          mc_RESET_J;
140
        }
141
      }
142
    }

Man kann es natürlich auch umschreiben auf einen Timer-Interrupt, der
die
Eingänge ausliest.

Bei einem Prozessor, bei dem man die Eingänge zweifach
flankengetriggert
einstellen kann, ist der Code kleiner.

Hierbei hat left u. right irq nichts mit der Drehrichtung zu tun; die
beiden
sind für die beiden Adern des Drehgebers; die Information der
Drehrichtung ist
zeitlich codiert (durch Phasenverschiebung).

Bei einem 4-er-Drehgeber ist es etwas komplizierter, aber es können
auch noch
3-Flanken-Fehler korrigiert werden.

Durch den Fehler-Zähler kann man angeben wie zuverlässig der Drehgeber
ist,
indem man den Fehler-Zähler durch die Anzahl der Steps (Rechts-
u. Links-Schritte) zählt.

von Peter Dannegger (Gast)


Lesenswert?

@Rolf,

wirklich ein imposantes Codemonster, wenn ich doch bloß erkennen
könnte, was daran besser sein soll.


Warum probierst Du nicht mal mein kleines schnuckeliges Progrämmchen
(Encode.c) aus ?

Du wirst verblüfft sein, wie zuverlässig es entprellt und dekodiert.


Für Ängstliche, die denken, ein Timer ist zu aufwendig, es muß auch
nicht im Timerinterrupt aufgerufen werden.

Man kann genausogut einen Pin-Change-Interrupt nehmen, Hauptsache der
Interrupt reagiert auf alle 4 Flanken.


Peter

von Andi (Gast)


Lesenswert?

Hallo rote Ampel :-)

Im ersten Beitrag von mir hier habe ich meinen ersten Versuch mit einem
Drehgeber über IRQ von Kanal A (Pin Change IRQ) abgebildet.
Ist zwar am Ende etwas anders geworden aber im Prinzip geht das über
Pin Change IRQ wie folgt:

 Drehgeber ändert Kanal A -> IRQ wird ausgelöst.
 Kanal A und B auslesen.
 Kanal A und B mit zuvor gemerkten Kanal A und B vergleichen.
 Ist der aktuelle Wert von Kanal A und B anders als der vorige dann:
  Aktuellen AB-Wert merken (Variable).
  Ist Kanal A = Kanal B dann wurde nach links gedreht.
  Ist Kanal A <> Kanal B dann wurde nach rechts gedreht.

Das ist alles.
Entweder mit 10K und 10nF jeden Kanal und den Button entprellen oder
per Timer-Software.

MfG
Andi

von Rolf F. (Gast)


Lesenswert?

Der Code von mir wird in einigen Geräten eingesetzt und der funktioniert
sehr zuverlässig. Bei Drehgebern, bei denen es mit nur einfacher
Flanken-Zählung (nur fallende oder steigende Flanken) deutliches
Prellen gibt, funktioniert mein Code ohne Prellen.
Die Fehlerzählung habe ich drinn für Features wie den extrapolierten
Zeitpunkt des Totalausfalls oder Ferndiagnose, aber bisher ist es
ungenutzt.

von Andi (Gast)


Lesenswert?

@Rolf F:
Es ist einfach nur irsinnig so viel Code zur Drehgeberauswertung zu
machen.
Ich habe Peters Code in ASM umgesetzt was ein paar Befehle sind und es
funtzt ohne Probleme genauso wie die Version A = B ist links und A <> B
ist rechts mit Soft-Entprellung per Timer (0,3ms).

MfG
Andi

von Rolf F. (Gast)


Lesenswert?

Ok, mit
  Ist Kanal A = Kanal B dann wurde nach links gedreht.
  Ist Kanal A <> Kanal B dann wurde nach rechts gedreht.
kann man meinen Code noch optimieren.
Beim MSP430 hat man etwas mehr Code als z. B. beim ARM9 dadurch, daß
die Eingänge nicht doppelt flankengetriggert eingestellt werden können,
so daß man das emulieren muß.

von Andi (Gast)


Lesenswert?

>daß die Eingänge nicht doppelt flankengetriggert eingestellt werden
>können
Dann wäre ja gerade beim MSP430 ein Polling im Timer der beiden Kanäle
sinnvoller.

>Ok, mit
>  Ist Kanal A = Kanal B dann wurde nach links gedreht.
>  Ist Kanal A <> Kanal B dann wurde nach rechts gedreht.
>kann man meinen Code noch optimieren.
Du meinst wohl ersetzen.
Oder mit Peters Methode welche komplett ohne Hard- oder
Soft-Entprellung auskommt.

MfG
Andi

von JojoS (Gast)


Angehängte Dateien:

Lesenswert?

ich hatte bevor ich hier die C-Variante gefunden habe auch mal eine asm
Version mit Tabelle gebaut, d.h. die Schritte müssen wenn die zwei Bits
binär codiert in der Reihenfolge 1,3,0,2 oder andersrum kommen. Wenn man
prüft ob der neue Zustand genau einen davor oder dahinterliegt wird es
auch einfacher als die bitweise Prüfung. In meinem Beispiel wird + oder
- je nach Step ausgegeben. Zusätzlich gibt es noch ein paar Tasten die
dann Ziffernausgaben machen (allerdings noch nicht ordentlich
entprellt, nur über das delay durch serielle Ausgabe zwischen zwei
Abtastungen). Das soll mal mein Drehgeber für einen CarPC werden.

von Thomas (Gast)


Lesenswert?

Hallo,
ich habe gerade den Code von Peter mit einem Drehgeber von Conrad
getestet (427), funktioniert auch sehr gut (besser als mein eigener mit
Flankenwechsel im Interrupt).
Jedoch ändert sich der Wert bei jeder Rasterstellung um zwei anstatt um
eins.
Peters Tip mit:

> Einfach dann den Wert vor der Auswertung 1* nach rechts schieben:
> int count;
> cli();
> count += enc_delta >> 1;
> enc_delta = 0;
> sei();

funktioniert bei mir nicht.
Was meiner Meinung nach daran liegt, dass wenn enc_delta negativ ist,
und ich dieses Zweiekomplement nach rechts schiebe, mein Wert nicht
mehr negativ ist.
Beispiel: enc_delta = -2
0b 1111 1110 // -2
und um eine Stelle nach rechts verschoben:
0b 0111 1111 // +127

Oder habe ich irgendwo einen Denkfehler?

von Peter D. (peda)


Lesenswert?

@Thomas

Stimmt, ganz so einfach geht es nicht. Die Halbschritte gehen
verloren.


So sollte es gehen:

cli();
if( !(enc_delta & 1)){
  count += enc_delta >> 1;
  enc_delta = 0;
}
sei();

Das Schieben selber funktioniert auch mit negativen Zahlen, nennt sich
arithmetisches Shift (Befehl ASR).


Peter

von Ralf (Gast)


Lesenswert?

@Peter Dannegger:

Du hast in einem Beitrag vom 17.03.2005 den AT89LP4052 erwähnt. Das
Teil interessiert mich brennend. Hast du schon mit dem gearbeitet? Wenn
ja, woher hast du ihn bekommen?

Gruß Ralf

von Gerd (Gast)


Lesenswert?

Das Problem bei allen Softwarelösungen ist dass sie nicht alle Flanken
auswerten und damit an Auflösung einbüßen. Die "Drehgeber" sind
Quadraturencoder und liefern 4 Zustände von denen nur 2 zu
Richtungsermittlung und 2 für den Weg benutzt werden können. Entweder
werden nur 0 oder 1 ausgewertet. Steigende- und Fallende Flanken sind
mit den üblichen Kontrollern nicht auswertbar zum anderen ist der
Kontroller mächtig beschäftigt.
Die eine arbeitet sehr zuverlässig und arbeitet mit 4 CMOS Gatter und
ein paar R und C's. Sie wertet alle 4 Flanken aus und liefert Takt für
den Weg und ein Bit für Rechts/Links-Lauf. ich benutze den Counter der
8051 Derivate zur Wegermittlung (Zählerstand) und ein Portbit für die
Richtung. Von Hand habe ich es mit einem Incrementalgeber mit
200Ticks/-1 nicht geschafft Schrittverlusste zu erzeugen.
Eine andere Lösung ist weniger Aufwändig jedoch muss man CPLD's von
Xilinx Programmieren können. Etwas teuerer ist sie liefert aber sofort
6 Auswerter. Dazu wird ein XC9536 mit einem TTL-Takt Generator
eingesetzt. Die Ausgangssignale sind ebenfalls Takt und Richtung. Evtl.
will ich auch mal einen Zähler implementieren. Man könnte das Ding dann
direkt an einen Bus koppeln und die Zähler via Register auslesen. Mal
sehen.
Wenn interesse kann ich das Zeug mal Posten
Gruß Gerd

von JojoS (Gast)


Lesenswert?

das kommt eben darauf an wofür der Encoder eingesetzt wird:
die meisten hier vorgeschlagenen Routinen sind für die digitalen
Drehknöpfe wie sie z.B. an Audiogeräten zu finden sind und die werden
nicht so schnell gedreht. Wenn der Encoder an einer drehenden Welle
sitzt dann muss man rechnen ob man da noch schnell genug abtastet.

von Peter Dannegger (Gast)


Lesenswert?

"Das Problem bei allen Softwarelösungen ist dass sie nicht alle Flanken
auswerten und damit an Auflösung einbüßen."


Häää ???

Wenn man etwas zu einem Thread zu sagen zu haben meint, dann sollte man
ihn doch auch bitteschön erst einmal lesen.

Bzw. wenn man etwas nicht verstanden hat, dann kann man ja erst einmal
fragen.


"ich benutze den Counter der 8051 Derivate zur Wegermittlung
(Zählerstand) und ein Portbit für die Richtung."

Seit wann kann denn der internen Zähler vorwärts und rückwärts zählen
?


Peter

von Rolf F. (Gast)


Lesenswert?

Ja, sehe ich auch so.
Meinen obigen Code habe ich zwar nur für einen Drehschalter für Menüs
gemacht, aber testweise auch mit einer Bohrmaschine angetrieben.
Übrigens gibt's auch Drehgeber die von einer Raster-Position zur
nächsten nicht zwei sondern vier Flanken liefern.

Bei sehr hohen Drehzahlen muß man einen MC nehmen, der nichts weiter
macht als nur den Drehgeber auswerten und das Ergebnis ohne IRQ, z. B.
als Gray-Code parallel ausgibt. Damit kann man bis ca. eine Million
Flanken pro Sekunde zählen.

von Uli Huber (Gast)


Lesenswert?

Hallo Gerd,

das mit

'Steigende- und Fallende Flanken sind
mit den üblichen Kontrollern nicht auswertbar zum anderen ist der
Kontroller mächtig beschäftigt.'

ist eher eine historische Betrachtung, oder ?

Bei den ATTinys jedenfalls hast Du mit den PCINT natürlich die
Möglichkeit  auf alle Flanken zu triggern.

Gruß
Uli

von Christian K. (christiank)


Lesenswert?

Hallo,

nach diesem ewig langen Thread blickt ja keiner mehr durch, daher poste
ich hier nocheinmal Peter's Code, angepasst für Drehgeber wie den von
Contrad Elektronik, d.h. die Rast-Stellung ist entweder bei 00 oder 11.

Dafür habe ich eine winzige Erweiterung eingebaut (variable tmp), so
dass der Zählerstand pro Raststellung nur um eins, nicht um zwei
weiterzählt.

Den ganzen quatsch mit cli() und shiften und murksen und sei() kann man
sich dann nämlich sparen.

Ich musste allerdings auch feststellen, dass Peters Code bzgl.
Entprellung nicht optimal ist. Es passiert leider häufiger, dass
Drehimpulse verloren gehen, besonders wenn man etwas vorsichtig dreht.
Das werde ich mir später mal genauer ansehen. Vielleicht hilf ja eine
externe Filterung.

Hier der Code: (Drehimpulsgeber ist angeschlossen an PE4 und PE3)


---- globaler Speicher des Drehwertes

volatile int8_t  enc_delta=0;    // -128 ... 127

---- innerhalb der Timer Routinte ----

  static int8_t enc_last = 0x01;
  int8_t i;
  uint8_t tmp;

  i=0;
  // digiswitch polling
  tmp=PINE;
  if( (tmp & _BV(PINE4)) )
    i = 1;

  if( (tmp & _BV(PINE3)) )
    i ^= 3;      // convert gray to binary 00->11, 01->10

  tmp=i;         // save value in binary code for test of increment

  i -= enc_last;       // difference new - last

  if( i & 1 )         // bit 0 = value (1)
  {
    enc_last += i;     // store new as next last
    if (!(tmp & 1))    // change only for 00/10 in binary code
      enc_delta += (i & 2) - 1;   // bit 1 = direction (+/-)
  }

------------ end ---------------

von Peter D. (peda)


Lesenswert?

@Christian

"Den ganzen quatsch mit cli() und shiften und murksen und sei() kann
man sich dann nämlich sparen.
...
Es passiert leider häufiger, dass Drehimpulse verloren gehen"


Ja das kommt davon.
Ich hab mir nämlich bei dem "ganzen Quatsch" schon was gedacht.

Und das cli/sei kann man erst recht nicht sparen, da man ja die
Variable gleichzeitig lesen und löschen muß (atomar).


Peter

von ChristianK (Gast)


Lesenswert?

Hallo Peter,

ich verändere/lösche die Variable enc_delta nicht. Warum sollte ich
auch, ich brauche sie absolut.

Trotzdem gehen Impulse verloren, im ungüstigsten Fall zählt er sogar
mal in die falsche Richtung. Die Conrad Drehgeber scheinen wahre
Prell-Wunder zu sein.

Im Moment fehlt mir die Zeit, aber bei Gelegenzeit werde ich mir die
Signale mal mit dem Speicher-Osci. anschauen was da so los ist und ob
eine SW Entprellung Sinn macht.

Grüße
  Christian

P.S:
(Wenn man enc_delta ausserhalb des Interrupts verändert, muss man
natürlich die Interrupts blockieren, ich denke das ist klar.)

von ChristianK (Gast)


Lesenswert?

Das Prellen des Conrad rotary switch bekommt man übrigens recht gut in
den Griff, wenn man den Timer Tick stark reduziert. Ich habe den jetzt
auf 100Hz eingestellt (waren bisher 1000Hz). Damit ist das Prellen
ziemlich stark reduziert. (laut Datenblatt ist die Prellzeit 2ms und
die Pulsezeit 6ms bei 60rpm! (d.h. 30pulse/sec))

Natürlich gehen - wenn man schnell dreht - Impulse verloren, aber bei
meiner Anwendung stört das nicht, Genauigkeit beim langsamen drehen ist
mir wichtiger.

Grüße
  Christian

Wenn man Lust hat, könnte man natürlich die Pulsedichte (Pulse/sec)
auswerten und die Sample-Zeit dynamisch anpassen...

von Rolf (Gast)


Lesenswert?

Bei dem Drehgeber von Conrad kommt von einer Raster-Position zur
nächsten nur einen Puls; besser ist einer der zwei Flanken (statt
einer) ausgibt, bei dem man also halbe Schritte zählen kann.

von Andi K. (Gast)


Lesenswert?

Seltsam.
Wenn Du den ddm427 meinst, den habe ich mit Peters Code, in ASM
umgeschrieben, und auch mit eigenem Code bei 10KHz Timer erfolgreich
betrieben.
Bei dem eigenen Code brauchte ich zum Entprellen für alle 3 Signale, A,
B und Button, nur 1 Filterung von 2 Timer-Ticks.

MfG
Andi

von Peter D. (peda)


Lesenswert?

@Christian,

daß eine geringere Abtastung helfen soll, klingt äußerst merkwürdig.

Hast Du denn die Variante mit dem Schieben überhaupt probiert ?

Ich hab jetzt Deine Code nicht in allen Einzelheiten überprüft, würde
aber sagen, daß er die Entprellfunktion aushebelt.

Auch ist ein ASR wesentlich weniger Code, als ein zusätzliches Register
im Interrupt (+PUSH/POP).



Peter

von ChristianK (Gast)


Lesenswert?

@Andi,
ja laut Conrad Datenblatt heisst er ddm421. Ich betreibe ihn auch
erfolgreich mit Peters Code, nur halt nicht 100% ohne Prellen, ich
benutze aber auch keinerlei zusätzlicher Entprellung so wie du. Und er
ist nagelneu. Das Prellen ist übrigens nur bei wenigen der
30-Raststellungen festzustellen. Ist vielleicht auch ein
Montagsgerät...

@Peter,
der Code ist 99.5% identisch mit deinem.
Änderungen:
- Samplen des Inputregisters nur einmal (vmtl. irrelevant)
- Berechnen des Ausgangswertes nur wenn Zustand 00/11 vorliegt, Das
sind die Raststellungen des Drehgebers (bei dir wurde er immer
berechnet d.h. bei 00/01/11/10 - darum zählt er doppelt)

Die Graycode Entprellung wird dadurch aber nicht beeinflusst. Das
Prellverhalten war mit 100% Peter genauso wie mit 99.5% Peter.

Performance:
Eine tmp Variable habe ich sowieso in meiner Timer Tick Routine, aber
darauf kam es mir ja auch nicht an, ich möchte mir das Rechnen im
Hauptprogram sparen.

Warum bei langsamen Timer-Tick weniger prellen?
Die Wahrscheinlichkeit, dass man die 2ms Prellzeit trifft, nimmt
natürlich ab je weniger schnell man sampled. Mit 1kHz (1ms) treffe ich
zwei mal den undefinierten Zustand während der Prellzeit, mit 10ms nur
noch mit Wahrscheinlichkeit 1:5. (Die Prellzeit sollte dabei natürlich
nicht stark von der Drehgeschwindigkeit abhängen...)

Grüße
  Christian

von Peter D. (peda)


Lesenswert?

"Die Graycode Entprellung wird dadurch aber nicht beeinflusst. Das
Prellverhalten war mit 100% Peter genauso wie mit 99.5% Peter."


Gibs doch zu, Du hast es garnicht erst probiert.
Deine 0,5% setzen nämlich die Entprellung außer Kraft:

Du zählst bei 00->10 rauf aber bei 11->10 runter.
D.h. ein Preller 00->10->00 zählt nur rauf und damit falsch.


Prinzipbedingt kann mein Code erst dann ein Prellen nicht mehr
korrigieren, wenn beide Signale gleichzeitig prellen, d.h. kein
Graycode mehr rauskommt (nur ein Signal ändert sich).
Eventuell gibt es ja ein Übersprechen, probier doch mal kleinere Pullup
Widerstände.


Peter

von ChristianK (Gast)


Lesenswert?

Asche auf mein Haupt, ich ziehe alle vorherigen Postings zurück und
behaupte das Gegenteil....

Der Conrad Drehgeber scheint sehr wenig zu Prellen, ansonsten hätte ich
wohl doppelte Zählungen sehen müssen. Komischerweise habe ich nur
fehlende Pulse beobachtet...

> Gibs doch zu, Du hast es garnicht erst probiert.
Doch und das ist genau das Problem, einfach mal eben in der Hardware
geändert... läuft und gut ist. Solche Dinge sollte man u.U. doch besser
erst am PC simulieren....

von Peter Dannegger (Gast)


Lesenswert?

"Der Conrad Drehgeber scheint sehr wenig zu Prellen, ansonsten hätte
ich
wohl doppelte Zählungen sehen müssen. Komischerweise habe ich nur
fehlende Pulse beobachtet..."


Ob der Geber prellt, kann man mit meinem Code nicht feststellen, da er
ja entprellt.

Fehlende Pulse deuten auf eine zu langsame Abtastung hin. Eventuell
sind ja andere Interrupts zu lange beschäftigt.


Peter

von The Daz (Gast)


Lesenswert?

@Peter
Ich plane auch gerade mal diese Drehgeber zu verbauen. Ist bei deiner
Routine die Benutzung externer RC-Glieder ueberfluessig oder hilfreich
(bei manueller Geber-Betaetigung) ? Koente mir moeglicherweise ne Menge
Bauteile und Platinenflaeche sparen.

von Rolf (Gast)


Lesenswert?

Also die Drehgeber, die ich programmiert habe, liefen beim MSP430 ohne
Tiefpass, aber beim ARM9 mussten Tiefpässe genommen werden (und es
wurden freiliegende Schmitt-Trigger verwendet); das hängt vom Prozessor
und Drehgeber ab.

von Peter Dannegger (Gast)


Lesenswert?

@The Daz

die Routine ist entprellend, Du brauchst also keine extra Tiefpässe.


Peter

von Michael Demuth (Gast)


Lesenswert?

Hallo zusammen,
wir stellen alle Arten von Drehgebern her (auch die vom Conrad).
Das Problem mit der Entprellung ist vor allem dann ein echtes wenn man
1/2 Schritt vor und dann wieder zurück dreht. Für einen echten Schritt
müssen 2 (4) Zustandswechsel (gepollt oder per IRQ) ausgewertet werden.
Dann klappt's auch.
Dazu ein bissl Source Code:

void lesen()
    {
    const signed int table[16] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  // 16 erlaubte Bit-codes

    old=old<<2;      // die alten Daten 2 nach links schieben

    if (input(PIN_B4))     // Spur /A abfragen (A0)//B4
      bit_set(new,0);
  else
          bit_clear(new,0);

    if (input(PIN_B5))     // Spur /B abfragen (A2)//B5
      bit_set(new,1);
  else
            bit_clear(new,1);
    old |=(new & 0x3);          // alte und neue bits verodern
    angle_1 += table [(old & 0xf)];   // aktion aus dem Feld auswählen
  }

Dann etweder durch 2 oder durch 4 teilen:

void teiler_4()
  {
  if (angle_1>7)    // unterlauf?
    {
    angle++;
    if (angle > 99) angle = 0;  // Überlauf abfangen
    angle_1=4;
    }
    if (angle_1<1)
    {
    angle--;
    if (angle > 250) angle = 99;    // Unterlauf abfangen
    angle_1=4;
    }
   }
/****************************************************************/
void teiler_2()
  {
  if (angle_1>5)    // unterlauf?
    {
    angle++;
    if (angle > 99) angle = 0;  // Überlauf abfangen
    angle_1=4;
    }
    if (angle_1<3)
    {
    angle--;
    if (angle > 250) angle = 99;    // Unterlauf abfangen
    angle_1=4;
    }
   }
Alle anderen Methoden funktionieren eigentlich nicht wirklich.
Zur Umwandlung von Qudratursignalen in Impuls-Richtungssignale gibt es
ICs oder GALs. Viel Erfolg!

www.ebe-gmbh.de

von mgiaco (Gast)


Lesenswert?

Wie schnell sollte man so ein Drehgeber einlesen wenn man ihn für die
Bedienung eines Gerätes verwenden will? Ich habe die vom Conrad.

Ich meine die Funktion lesen() ==> die muss man ja Zeitgesteurert
ausführen oder?

mfg mathias

von SuperUser (Gast)


Lesenswert?

Für Drehgeber zur Geräte-Bedienung (z.B. der von Conrad) welche in den
Stellungen AB=00, AB=11 einrasten funktioniert auch dieser Code

http://www.mikrocontroller.net/forum/read-4-250095.html#new

einwandfrei - auch beim Zurückdrehen aus halben Stellungen. Er zählt
aber - was normalerweise auch so gewünscht ist - nur die
Raststellungen.

Die Pollgeschwindigkeit hängt von der Applikation ab. Wenn man viele
Feineinstellungen braucht (+/- ein paar Stellungen) reicht z.B. 500 mal
pro Sek. pollen aus. Muss viel gekurbelt werden (d.h. grosse Schritte),
muss man schneller samplen da sonst je schneller man dreht weniger
Pulse gezählt werden.

Wer sicher gehen will und sich das leisten kann nimmt Interrupts.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

>Wer sicher gehen will und sich das leisten kann nimmt Interrupts.

Eben nicht!

von Rolf (Gast)


Lesenswert?

Interrupts sind am besten, wenn die CPU hauptsächlich anderes machen
soll, aber zum Entprellen per Software ist Polling etwas besser.
In der Regel ist der Unterschied aber nur marginal; es ist also
hauptsächlich Geschmackssache.

von Christoph Kessler (Gast)


Lesenswert?

Hallo
ich benutze am Atmel 8515 die beiden Interrupt-Eingänge:

ExtInt0:
  push  Temp1    ; save Temp1
  in  Temp1,SREG  ; save flag register
  push  Temp1
  in  Temp1,MCUCR  ; Int0  _/~ or ~\_ ?
  sbrc  Temp1,0    ; skip next line if  ~\_
  rjmp  UpA    ; was _/~ so jump to UpA
  ori  Temp1,$01  ; MCUCR-bit0 = 1
  out  MCUCR,Temp1  ; Int0 next change will be _/~
  sbic  PinD,3    ; skip next line if channel B=0
  rjmp  DecRot    ; if B=1 and A=~\_ -> decrement
  rjmp  IncRot    ; if B=0 and A=~\_ -> increment
UpA:
  andi  Temp1,$FE  ; MCUCR-bit0 = 0
  out  MCUCR,Temp1  ; Int0 next change will be ~\_
  sbic  PinD,3    ; skip next line if channel B=0
  rjmp  IncRot    ; if B=1 and A=_/~ -> increment
  rjmp  DecRot    ; if B=0 and A=_/~ -> decrement

ExtInt1:
  push  Temp1    ; save Temp1
  in  Temp1,SREG  ; save flag register
  push  Temp1
  in  Temp1,MCUCR  ; Int1  _/~ or ~\_ ?
  sbrc  Temp1,2    ; skip next line when ~\_
  rjmp  UpB    ; was _/~ so jump to UpB
  ori  Temp1,$04  ; MCUCR-bit2 = 1
  out  MCUCR,Temp1  ; Int1 next change will be _/~
  sbic  PinD,2    ; skip next line if channel A=0
  rjmp  IncRot    ; if A=1 and B=~\_ -> increment
  rjmp  DecRot    ; if A=0 and B=~\_ -> decrement
UpB:
  andi  Temp1,$FB  ; MCUCR-bit2 = 0
  out  MCUCR,Temp1  ; Int1 next change will be ~\_
  sbic  PinD,2    ; skip next line if channel A=0
  rjmp  DecRot    ; if A=1 and B=_/~ -> decrement
  rjmp  IncRot    ; if A=0 and B=_/~ -> increment

IncRot:
  mov  Temp1,RotVal  ; max limit = +127 reached ?
  cpi  Temp1,$7F  ;
  breq  Exit    ; yes, so don't increment
  inc  RotVal    ; no, increment
  rjmp  Exit    ;
DecRot:
  mov  Temp1,RotVal  ; min limit = -128 reached ?
  cpi  Temp1,$80  ;
  breq  Exit    ; yes, so don't decrement
  dec  RotVal    ; no, decrement
Exit:
  pop  Temp1    ; restore Flag register
  out  SREG,Temp1  ;
  pop  Temp1    ; restore Temp1
  reti

das ganze muß natürlich noch gestartet werden
Das Hauptprogramm fragt gelegentlich die Variable RotVal auf Werte
ungleich Null ab
Durch die schnelle Antwortzeit des Interrupt habe ich keine Problem mit
Prellen, vermutlich zählt die Interruptroutine auch alle Preller vor und
zurück mit.
Ich benutze auch die Conrad-Drehgeber DDM427 von hopt-schuler.com ,der
leider nur auf jeder zweiten Flanke rastet

73
Christoph

von Rolf (Gast)


Lesenswert?

Ja, bei dem Auswerten der Interrupts sollten natürlich auch die Preller
komplett ausgewertet werden; ansonsten hat man ja wieder das Prellen
drinn. Durch die Preller wird der Wert aber nur für ein paar
Mikrosekunden geändert.
Wenn das unerwünscht ist, kommt man um Polling nicht herum, braucht
dafür aber mehr CPU-Zeit und kann schnelles Drehen des Drehgebers nicht
mehr auswerten.
Optimal wäre natürlich ein Drehgeber mit mehr als zwei Adern,
beispielsweise mit 8-Bit-Gray-Code-Ausgabe (256 Schritte/Vollkreis) und
einem Inkrementieren/Dekrementieren alle N>2 Schritte, denn dann werden
alle Preller automatisch exakt eleminiert und man braucht weder
Interrupts noch Polling. Nur bei mehr als 360 Grad bräuchte man einen
Timer-IRQ um die Nulldurchgänge zu zählen. Der Nachteil ist natürlich
die teurere Hardware.

von SuperUser (Gast)


Lesenswert?

Ähm...

Eine Interrupt Auswertung sollte sich eigentlich grundlegend von der
Polling Implementierung unterscheiden. Ich halte es für risikoreich
darauf zu hoffen, dass der Interrupt schon alle Preller mitbekommt...

Z.B. so (noch nicht getestet mit Drehgeber):
a) wir reagieren auf die erste Änderung mit b)
b) wir stellen uns blind für die erwartete Prellzeit
c) nach deren Ablauf lesen wir den derzeitigen Zustand und entscheiden
was zu tun ist
d) wir warten auf die nächste Änderung

(Prellzeit für DDM427 z.B. 3ms nach Datasheet)

von Rolf (Gast)


Lesenswert?

Das ist aber empfindlich auf Preller.
Ich mache es beim Polling so, dass der aktuelle Wert derjenige ist, der
zuletzt 30x in Folge (konstant) eingelesen wurde.

von Christoph Kessler (Gast)


Lesenswert?

Hallo
Ich habe auch so einen Drehgeber mit 8Bit-Absolutcodierung von Bourns.
Leider gibt es nicht nur DEN Graycode, sondern viele verschiedene. Den
von Bourns kann man soweit ich sehe nur mit einer Tabelle in Dualzahlen
umcodieren. Es gibt eine speziellen Graycode beliebiger Breite, der
systematisch mit EXOR-Gattern hin- und zurück codiert werden kann (
wenn man mal von der Laufzeit in den hintereinandergeschalteten Gattern
absieht, die den Vorteil des Gray-Codes zunichte macht, dass sich nur
ein Bit pro Stufe ändert - die Glitches müssen wieder berücksichtigt
werden)
73
Christoph

von Rolf (Gast)


Lesenswert?

Ja, man kann den Gray-Code natürlich auch genau anders rum verwenden,
also z. B. in der ersten Stufe so kodieren:
0 -> 0
1 -> 0xff
2 -> 0xfe
...
ohne die grundsätzlichen Eigenschaften zu ändern, aber die Variante mit
den Gattern ist das zu 99,9 % verwendete auch in den Lehrbüchern.
Die Glitches kann man mit einem Mikrocontroller vermeiden.
Man kann dafür auch den Parallelport am PC nehmen.

von Peter D. (peda)


Lesenswert?

@Christoph

"Leider gibt es nicht nur DEN Graycode"

Kannst Du mir denn einen anderen zeigen ?

Ich habe noch nirgends einen anderen Gray-Code gefunden.

Die Bedingung ist ja, daß sich nur ein Bit ändern darf und das geht
eben nur mit der bekannten Bildungsregel, jedes nächste Bit spiegelt
alle darunter liegende Bits (EXOR).

Und der Gray-Code muß natürlich vollständig sein, d.h. 256 Werte bei 8
Bit.


Peter

von Christoph Kessler (Gast)


Lesenswert?

http://www.bourns.com/pdfs/ace.pdf
das ist ein absoluter Drehgeber mit total wirrem Graycode, auch Bourns
empfiehlt eine Tabelle zu verwenden

von Rolf F. (Gast)


Lesenswert?

Naja, da hat man einiges Abzutippen.
Ungewöhnlich ist ja schon die Bezeichnung p1..p8 bei den Adern, denn
normalerweise wird statt p1 stattdessen p0 (etspr. für n*2^0)
verwendet.

Aber man findet ja schon im Datenblatt vom Conrad einen Algorithmus,
der nur eine Sorte Flanken auswertet und entsprechend viele Preller
gibt.

von Christoph Kessler (Gast)


Lesenswert?

Abtippen bei PDF kann man ja sparen, besser kopieren und in
openoffice-calc einlesen und umformen
aber der Graycode ist hier auch unvollständig, 128 Stufen mit 8 Bit ist
eines zuviel, scheint aber kein Korrekturbit zu sein, das wenigstens
nützlich wäre
So einen Schalter hat mir mal ein Vertreter auf einer Spoerle-
Regionalausstellung geschenkt, ich habe dann irgendwann an ein Eprom
angeschlossen, um ihn als Kanalwähler für eine PLL zu benutzen, da
spielen Glitches keine Rolle.

von Rolf F. (Gast)


Lesenswert?

Tatsächlich, 8 Adern für nur 127 Positionen; das ist ja richtig
pervers!
Dabei ist der übliche Gray-Code ganz einfach:

http://www.peg.si/electro/angle.html

von Christoph Kessler (Gast)


Lesenswert?

ja genau das meinte ich mit den hintereinadergeschalteten EXORs, das ist
wie beim ripple-counter, die Bits ändern sich alle nacheinander um je
eine Gatterlaufzeit verzögert, also genau was man mit dem Graycode
vermeiden wollte, glitches von einigen Nanosekunden

von Rolf F. (Gast)


Lesenswert?

Ja, stimmt; eigentlich muss man dafür einen Mikrocontroller-Port nehmen
und per Software dekodieren, also mittels

  x ^= (x >> 4);
  x ^= (x >> 2);
  x ^= (x >> 1);

Weil unter dem Link nur eine LED-Anzeige ist, sind die Glitcher aber
egal, weil nicht sichtbar.

von Der T. (Gast)


Lesenswert?

Hallo Peter!

Damit ich vom Conrad-Drehgeber nur bei jeder vollen Rasterstellung den
Wert aktualisiere, habe ich deinen Code ein bischen erweitert!

_______________________
// 3. Drehimpulsgeber auswerten
 static int DIG_enc_last = 0x01;
  char DIG_i = 0;
  if( PHASE_A ) { DIG_i = 1; }
  if( PHASE_B ) { DIG_i ^= 3; } // convert gray to binary
  DIG_i -= DIG_enc_last; // difference new - last
  if( DIG_i & 1 ) // bit 0 = value (1)
  {
   DIG_enc_last += DIG_i; // store new as next last
   DIG_enc_delta += (DIG_i & 2) - 1; //Halbschrittzähler
   if ((DIG_enc_delta - DIG_enc_delta2) > 1) { DIG_value++;
DIG_enc_delta2 = 0; DIG_enc_delta = 0; }
   if ((DIG_enc_delta2 - DIG_enc_delta) > 1) { DIG_value--;
DIG_enc_delta2 = 0; DIG_enc_delta = 0; }
  }
_______________________

Im Prinzip wird der Zähler aus deinem Code mit einem 2. Zählerwert
verglichen (Startwert von DIG_enc_delta2 = 1). Weicht der
Halbschrittzähler mehr als 1 ab, so wird der aktelle Vollschritt
übernommen (DIG_value) und beide delta-Zähler wieder zurückgesetzt.

Der Code funktioniert, bin aber für Verbesserungsvorschläge -wie immer-
dankbar! (z.B. Code minimieren..)

Gruß,
Techniker

von Der T. (Gast)


Lesenswert?

Hallo!

Hab gerade festgestellt, dass ich oben einen alten Code eingefügt
hatte! ;)

Hier der richtige:

_____________________
// 3. Drehimpulsgeber auswerten
 static signed int DIG_enc_last = 0x01;
 static signed char DIG_enc_delta = 0, DIG_enc_delta2 = 1;
  char DIG_i = 0;
  if( PHASE_A ) { DIG_i = 1; }
  if( PHASE_B ) { DIG_i ^= 3; } // convert gray to binary
  DIG_i -= DIG_enc_last; // difference new - last
  if( DIG_i & 1 ) // bit 0 = value (1)
  {
   DIG_enc_last += DIG_i; // store new as next last
   DIG_enc_delta += (DIG_i & 2) - 1; //Halbschrittzähler
   if ((DIG_enc_delta - DIG_enc_delta2) > 1) { DIG_value++;
DIG_enc_delta -= 2; DIG_enc_delta2 = DIG_enc_delta; }
   if ((DIG_enc_delta2 - DIG_enc_delta) > 1) { DIG_value--;
DIG_enc_delta += 2; DIG_enc_delta2 = DIG_enc_delta; }

  }
_____________________

von SuperUser (Gast)


Lesenswert?

n' bisschen einfacher (und leichter zu verstehen...)

http://www.mikrocontroller.net/forum/read-4-250095.html#new

von Der T. (Gast)


Lesenswert?

@SuperUser:
Den hatte ich schnomal probiert, hatte aber nicht funktioniert...

Nun habe ich es nochmal ausprobiert und er funktioniert auf anhieb
einwandfrei. :) Keine Ahnung, was damals schiefgelaufen ist.

Gebe mich damit geschlagen... ;)

(muß mir jetzt mal den Code vom Christian genau vornehmen, weil ich
noch nicht ganz über den Funktionsablauf dahintergekommen bin..)

Gruß,
Techniker

von Philipp Kälin (Gast)


Lesenswert?

Kann mir jemand sagen, wie ich einen Drehgeber mit der C-Control von
Conrad in Basic auslesen kann. Die Idee von peter dannegger (oberster
Beitrag dieser Seite) klingt für mich eigentlich logisch, nur kann ich
mit C nichts anfangen. Kann das Jemand für mich in Worte oder
Flussdiagramm übersetzen, damit ich es verstehe und dann in Basic++
programmieren kann?

MfG

Philipp

von Kersten D. (unbenannt-editor)


Lesenswert?

Hi!
Ich probiere gerade den 2. Code von Peter Dannegger. Drehgeber ist ein
Poti-ähnliches Ding von Alps aus einer alten Maus.

Die Erkennung funktioniert soweit, allerdings muss man sehr langsam
drehen. Der Drehgeber ist aber auch sehr fein und ohne Rasterung. Wie
kann ich den Code ändern, dass nur z.B. alle 10 oder alle 100 Impulse
ausgewertet wird?
Danke!
Kersten

von (geloescht) (Gast)


Lesenswert?

(Dieser Beitrag wurde geloescht)

von Thomas Lamparter (Gast)


Lesenswert?

Jetzt dachte ich in meinem jugendlichen Leichtsinn, hier in dem Forum
etwas über: "wie lese ich einen Absolutwertgeber aus" zu erfahren.
Das es mit Clock, und Data und n Bits geht, ist klar, ... nur suche in
nach einem Sourcecode....

Wer ne Idee hat, melden. Danke

von peter dannegger (Gast)


Lesenswert?

@Thomas

"Jetzt dachte ich in meinem jugendlichen Leichtsinn ..."

... es gibt weltweit nur einen einzigen Absolutwertgeber.


Nein, es gibt natürlich viele verschiedene.

Und keiner kann hellsehen, welchen Du gerade meinst.

Du mußt also schon nach Deinem bestimmten Typ suchen bzw. ein Blick ins
Datenblatt könnte auch nicht schaden. Manchmal enthalten Datenblätter
sogar Beispielcode.


Peter


P.S.:
In der sozialistischen Staatengemeinschaft gab es von einigen Geräten
wirklich nur einen einzigen Typ, aber das ist doch schon über 15 Jahre
her.

von Thomas Lamparter (Gast)


Lesenswert?

Hallo peter dannegger,

Es mag sein, dass in der Planwirtschaft, so was möglich war....

Scherz beiseite, die Drehgeber mit Synchron Seriellem Interface oder
kurz SSI. haben eine relativ klare Vorschrift, was die Datenblätter
angeht ;-) die habe ich schon durch, sei es von dem Maxe Stegmann, oder
von T&R um hier nur 2 stellvertretend zu nennen, da ist kein
Beispielcode daargestellt.

Den C-Quelltext könntest Du , wenn Du gewillt bist ihn mir zu
schreiben, auch variabel halten, (12 Bit... 31 Bit) Denke aber ich
kriege das selber hin, dachte ich geh nur den Weg des kleinsten
Wiederstandes, (Elektrokermentalität eben)


Also, lass es gut sein, lg, Tommy

von peter dannegger (Gast)


Lesenswert?

"Also, lass es gut sein"

Wird mir wohl nichts anderes übrig bleiben, wenn Du keine Lust hast,
eine genaue Typenbezeichnung und einen Link aufs Datenblatt zu geben.

Als Elektroniker sollte man eigentlich in der Lage sein, seine Fragen
präzise zu stellen.

Keiner kann in Deinen Kopf schauen. Es ist ja Dein Bier, wenn Du kein
Interesse an Hilfe hast.


Peter

P.S.:
Was ist ein "Elektroker" ?
Ein Elektroniker kennt jedenfalls keine "Wiederstände".

von Thomas Lamparter (Gast)


Lesenswert?

Es handelt sich um einen Siemens Geber :6FX2001-5FS12

oder um ein optisches Absolutwertmesssystem, der Firma Leuze
electronic, welches sich BPS37 nennt. Hier ist die Anzahl der
auszutaktenden Bits, sehr variabel, kann frei konfiguriert werden (ab
12 Bit, bis 31 Bits, je nach Auflösung).  Die Taktrate kann zwischen
90kHz und 1 MHz liegen.
Die Totzeit nach dem LSB (least signifcant bit = letztes oder
niederwertigstes, auszutaktendede Bit)

Und Du hast recht, eine Elektroniker kennt keine Wiederstände, nur
Widerstände. (Wuste nicht, dass wir hier ein Genie in Sachen deutsche
orthographie haben - danke für die Belehrung, hab wohl wirklich 1 Bier
zu viel gehabt).

Aber ich denke Du kannst mir nicht helfen, nicht weil das ein Ding der
Unmöglichkeit wäre, sondern, weil Du nicht willst, oder nict in der
Lage bist. (Sorry für meine offenen Worte)

Ich habe mir eien Ansatz zusammengereimt, wie ich den Geber austakte:

Port 1.2 udn Port 1.3 aös Daten udn Taktleitungen (Optokoppler und
RS485-Transceiver nachgeschaltet)

Akku löschen, Clockbit setzen, Timer freigeben, nach abgelaufener Zeit
Portpin für die Daten abfragen und in Ziel schieben, Zähler um 1
dekrementieren, wenn Zähler 0, dann die Zahl von Gray in Binaer
wandeln, danach in Hexzahl wandeln, und via UART an PC senden.

Also Danke nochmals. (Und entschuldige, über eventuelle
Rechtschreibfehler die Dir im AUge wehtun ;-)

von peter dannegger (Gast)


Lesenswert?

"Aber ich denke Du kannst mir nicht helfen, nicht weil das ein Ding
der
Unmöglichkeit wäre, sondern, weil Du nicht willst, oder nict in der
Lage bist. (Sorry für meine offenen Worte)"


Da bist Du völlig auf dem Holzweg.
Das einzige Hindernis bist Du selber, der einen blöde anmacht, wenn man
ihm versucht mehr Informationen aus der Nase zu ziehen.


Google findet jedenfalls einen Treffer, ist zwar 8051-Code, aber als
Anregung bestimmt gut zu gebrauchen.
Der Autor gibt nämlich den Typ an, weil er nicht denkt, daß es nur
einen Typ gibt und jeder gleich Bescheid wissen muß.


In der Regel läßt man ungenaue Fragen einfach links liegen und ich
werde es das nächste mal besser auch so machen.


Peter

von thomas lamparter (Gast)


Lesenswert?

Danke für die Hilfe, es läuft.

werde morgen (jetzt ist es eh zu spät, mal nen Absolutgeber mit 24 Bit
anschliesen, und wenn es läuft, dann nur noch die Fehlerauswertung)

warst ne echte Hilfe, also nochmals vielen Dank....

Thomas

von Simon K. (simon) Benutzerseite


Lesenswert?

@Peter:

Ich habe ein komisches Problem:

Wenn ich meinen Zählerstand verändere mache ich das mit
1
rot_pos += tmp;

Dabei zählt er zwei weiter. Soweit so gut, hatten wir ja oben schon.
Nach deinem Lösungsvorschlag müsste das so aussehen:
1
rot_pos += tmp>>1;

Problem: Der Compiler übersetzt das (nachvollziehbarerweise) so:
1
        rot_pos += tmp>>1;
2
  c8:  86 95         lsr  r24
3
  ca:  90 91 6a 00   lds  r25, 0x006A
4
  ce:  89 0f         add  r24, r25
5
  d0:  80 93 6a 00   sts  0x006A, r24

Der Knackpunkt ist aber, dass tmp eine char (signed!) Variable ist. Das
Vorzeichen-bit geht somit flöten. Und dementsprechend gibt das Drehen in
die Eine Richtung Stuss, und in die andere Richtung garnichts.
Was hast du dir dabei gedacht? Oder habe ich einen Denkfehler?
Komischerweise übersetzt er bei signed aber
1
rot_pos += tmp/2;
exakt genauso.

Hilfe! :-)

von Simon K. (simon) Benutzerseite


Lesenswert?

Hm, kaum eine Minute geschrieben, schon habe ich die Lösung:

char ist komischerweise (Wahrscheinlich mit den vielen Parametern
hinter dem gcc.exe) ein unsigned char.

Blöderweise widern mich die Parameter an, weil das so viele sind.
Deswegen beschäftige ich mich damit nur ungern ;)

von Simon K. (simon) Benutzerseite


Lesenswert?

PS: Jetzt übersetzt er es so
1
      rot_pos += tmp>>1;
2
  c8:  85 95         asr  r24
3
  ca:  90 91 6a 00   lds  r25, 0x006A
4
  ce:  89 0f         add  r24, r25
5
  d0:  80 93 6a 00   sts  0x006A, r24

Also alles Klar!

von Simon K. (simon) Benutzerseite


Lesenswert?

Hm, zu früh gefreut. Verhält sich genau gleich der Mikrocontroller.

@Peter oder jemand anders :-): Kannst du mal kurz über meinen Code
sehen? Ich hänge dir mal die relevanten Dateien an.

von Simon K. (simon) Benutzerseite


Angehängte Dateien:

Lesenswert?

#1

von Simon K. (simon) Benutzerseite


Angehängte Dateien:

Lesenswert?

#2

von Simon K. (simon) Benutzerseite


Angehängte Dateien:

Lesenswert?

und #3

von SuperUser (Gast)


Lesenswert?

Sorry, habe mir deinen Code nicht angesehen, aber wenn dich das doppelt
zählen stört kannst du auch mal dort nachsehen:

http://www.mikrocontroller.net/forum/read-4-250095.html#new

von Simon K. (simon) Benutzerseite


Lesenswert?

Ich danke dir, das sieht ebenfalls sehr interessant aus.

von Peter D. (peda)


Lesenswert?

@simon,

nein, so kann es nicht gehen.

Wenn Du das Bit 0 nicht auswertest, darf es auch nicht gelöscht werden,
sonst funktioniert das Entprellen nicht.

Du mußt also die Auslesefunktion so ändern:
1
signed char rot_getdelta(void)
2
{
3
  signed char tmp;
4
5
  cli();
6
  tmp = rot_delta;
7
  rot_delta = tmp & 1;  // bit 0 needed for debounce !
8
  sei();
9
10
  return tmp >> 1;      // pulse / 2
11
}


Peter

von Peter D. (peda)


Lesenswert?

Hallo Simon,

Schweigen im Walde ?

Wäre schon interessant, ob es nun funktioniert.
Theoretisch müßte es.
Ich habe leider keinen solchen Drehgeber, um es zu testen.


Peter

von Simon K. (simon) Benutzerseite


Lesenswert?

Hi Peter, ich hab direkt den Code von SuperUser genommen.

Schlimm dass ich dein Codeschnipsel nicht mehr ausprobieren konnte? Das
von SuperUser klappt jedenfalls mit meinem Encoder von Pollin sehr gut.

von Thorsten F. (thorsten)


Lesenswert?

Sorry fürs ausbuddeln.

@Peter

Wollte nur mal melden, dass die Anpassung auf den Drehgeber der nur
alle 2 Schritte einrastet (Pollin-teil) funktioniert.

gruß

von Holger G. (Gast)


Lesenswert?

Hallo P E T E R  D A N N E G G E R ?

ich benutze:

- deinen Codeschnipsel mit der Differenzmethode aus "encoder.c"
- optischen Drehencoder Grayhill-62A (1 Flanke pro Rastung)
- Auswertung durch Polling per Timer-Interrupt auf MSP430

Problem:

Beim Drehen funktioniert die Auswertung tadellos. Allerdings macht mir 
der Anfangszustand der Zählvariable "enc_delta" zu schaffen. Je nach 
Position des Drehencoders wird "enc_delta" um 1 inkrementiert / 
dekrementiert wenn die Funktion das erste mal gestartet wird und zwar 
bevor ich überhaupt gedreht habe.

Wenn ich mir den Code anschaue, sehe ich, dass nach der Differenzbildung 
"i-=enc_last" eine Zahl zwischen 0 und 3 entsteht und diese im Schritt 
"if (i & 1)" auf jeden Fall ausgewertet wird (i=1, i=3), also auch wenn 
die Funktion das erste mal gestartet wird und "enc_last=1" ist.

Wie löse ich dieses Problem? Eventuell A und B schon vorher einlesen und 
dann "enc_last" auf diesen Wert und nicht auf 1 setzen? Oder gibt es 
einen anderen Weg?


Bitte, bitte helft mir!

hg

von the_absolute_trough_blicker ;-) (Gast)


Lesenswert?

Autsch Peter Danegger scheint heir einem Denkfehler auferlegen zu sein.

wenn ich nun einen Sin/cos-geber habe, wie werde ich damit glücklich.

Ich kann zwar einen Quadraturencoderchip verwenden um damit klare 
rechecksignale auzubereiten und diese damit dem µcontroller zur 
Verfügung stellen, aber das ist nur die halbe Miete. Wenn ich schon ne 
fast unendlich hohe Auflösung habe sollte ich die doch auch verwenden 
und mich nicht mit schlappen 1024 oder 2048-Inkrementen zufrieden geben, 
oder was meint Ihr dazu ? Natürlichist die Auflösung beschrenkt, durch 
die Reckenleistung des µC´s.

Also Fakt ist, dass hier nicht ein Billigheimergeber eingesetzt werden 
soll sondern ein hochwertiger, der dann bei einem Motor mit hoher 
Achslast nicht zu Microtorsion neigt udn damit bei eienm sagen wir mal 
500 Inc. Geber zum Nachregeln und aufschwingen neigt. Ja ich weis... 
jeder Regler bedarf einer Regelabweichung... aber sollte diese nicht so 
klein wie möglich sein ?

Also. P.Danekker, wie ist die Erfahrung mit Präzisionsgebern.

Einsatzgebiet. Switched Reluktanzmotor, Achlast nach Getriebe 240/12/2 
Umsetzung, udn einem Supergenialen Sin/Cos-Geber, wie er auf dem Markt 
erhältlich ist auf die Lastabgewandte Seite (also nicht auf der 
Getriebeseite und nicht nach dem Getriebe)

Den Assemblercode für den Geber (Absolutwertgeber) habe ich, die 
Grobauswertung kann ich a la den Beispielen hier super gestalten, nur 
die 65535-wertige Feinauflösung bekomme ich nicht gebacken.

Wenn jemand was weis, bitte kurz Datenblatt oder Sourcecode anhängen ..

nun gut für das erste mal, eine Super Newsgroup (was für ein grässliches 
neudeutsches Wort) und richtig schöne Beiträge hier.

von Peter D. (peda)


Lesenswert?

the_absolute_trough_blicker ;-) wrote:
> Autsch Peter Danegger scheint heir einem Denkfehler auferlegen zu sein.

> Verfügung stellen, aber das ist nur die halbe Miete. Wenn ich schon ne
> fast unendlich hohe Auflösung habe sollte ich die doch auch verwenden
> und mich nicht mit schlappen 1024 oder 2048-Inkrementen zufrieden geben,
> oder was meint Ihr dazu ? Natürlichist die Auflösung beschrenkt, durch
> die Reckenleistung des µC´s.


Der Denkfehler liegt eindeutig bei Dir

Die Rechenleistung ist völlig schnurz.

Analogsignale kann man nicht unendlich gut auflösen. Außerdem machen Dir 
Nichlineritäten, Störspannungen, Vibrationen, Rauschen usw. einen Strich 
durch die Rechnung.

Es stimmt schon, es gibt auch Drehgeber mit Analogausgang. Allerdings 
macht man dann möglichst nahe eine Umwandlung in Gray-Code, weil sich 
das viel leichter weiterleiten und verarbeiten läßt.
Wir haben sie auf eine Auflösung von 16 Teilschritten gesetzt, weil es 
darüber instabil wird.


Peter

von the_absolute_trough_blicker ;-) (Gast)


Lesenswert?

Hallo Peter Danegger,

meine etwas scharfe Provokation hat genutzt. Ich habe Deine vollste 
Aufmerksamkeit erregt.

Ja, ich gebe Dir vollkommen Recht, einen Positionsgeber auf mehr als 16 
Bit aufzulösen ist für die meisten Anwendungen mumpitz ;-)

aber die Feinauflösung (Sin/Cos-Geber welche mit Arg-Tan vermostet 
werden) ist dennoch von Berechtigung. So ist es in der Lageregelung von 
Bedeutung, dass heir eine möglich hohe Auflösung erreicht wird. In der 
Drehzahlregelung ist das eher von geringerer Bedeutung, und somit 
reichen bei der Regelung gar die Spuren A und B aus.

Anwenungsfall Aufzug hast Du vollkommen Recht
Anwendungfall µ-Positionierung bin ich im Recht.

Aber um hier zu schlichten wird denke ich kein Schlichter oder Anwalt 
benötigt ;-)

Deine Forumsbeiträge sind eien Bereicherung.

Absolutwertgeber mit Serial-Synchon-Interface oder gar BISS werden von 
mir eher wenniger eingesetzt, da die vonDir erwähnten EMV-Probleme bei 
dieser differentiellen Schnittstelle ein großes Problem darstellen.
Wir verwenden eher die für Feldbus aufbereiten Systeme (hier ist es egal 
ob  Lichtlaufzeit (linear) Barcodepositioniersysteme von Leuze oder 
Drehgeber von Stegmann für die rotatorische Auswertung zum Einsatz 
kommen.

Gray-Code o.k. hat den Vorteil, dass der Wechsel von 2 Zuständen immer 
nur 1 Bitsprung bewirkt, aber wenn das diff-Signal madig ist (zu viele 
Störungen) dann kann es zu Bitdrehern kommen und so der Positionsistwert 
frei nach dem Motto "Cat down the River" oder schwäbisch "d´Katz da Bach 
na" bedeutet. Hier habe ich inder Vergangenheit immer (für mich 
aufwendig erscheinende) Plausibilitätsprüfungen durchführen müssen. Das 
hat dann in Abhängigkeit von Geschwindigkeit zu geschehen.

grüßle und ich hab es total verschwitzt. ein gutes Neues Jahr.


(wer Rechtschreibfehler findet darf sie behalten)

von Peter D. (peda)


Lesenswert?

@nur sich selbst dafür haltenden "the_absolute_trough_blicker"


Also wir benutzen gekaufte Lineargeber mit Analogausgang und dazu 
gehörige Wandler in Gray-Code, womit wir dann Piezomotoren <=50µm 
positionieren.

Die Graycodeauswertung erfolgt mit dem obigen Programm einwandfrei.

Die Analogleitungen sind höllisch empfindlich und so kurz wie möglich zu 
halten. Mit 16 Stufen meinte ich, sie interpolieren noch weitere 4 Bits 
je Viertelwelle.

Aber 16 Bits halte ich für völlig unmöglich, da ist ja das Husten von 
Flöhen viel leichter zu zählen.


Mit Aufzügen habe ich absolut nichts zu tun.
Ich hab nur mal gesagt, daß die Aufzugsfirma in unserem Gebäude unfähig 
ist, die Ruftasten zu entprellen (Es gehen immer beide Lampen an, wenn 
man über den Teppich geht). Ich verlasse auch immer schnell die Tür, 
wenn sie sich bewegt, denn ob die Lichtschranke richtig entstört ist, 
weiß man dann ja auch nicht.


Peter

von the_absolute_trough_blicker ;-) (Gast)


Lesenswert?

@ Peter

ich kenn mich nicht mehr so ultragut mit den Aufzugssteuerungen aus, 
aber sei versichert, dass der Sicherheitskreis in europäischen Aufzügen 
funktioniert.
Ob es eine KOllmorgen oder eine LISA oder eine Schindlersteuerung oder 
eine von Liftequip... egal sie tun.

Wenn man(n) und frau bedenkt dass die LISA noch in Pascal programmiert 
wurde (igit) entweder Assembler oder ne ordentzliche Hochsprache ich 
mochte Pascal noch nie (ist denek ich was persönliches) (Ebensowennig 
Cobol) und schon weitaus mehr als 15 Jahre auf dem Buckel hat ist sie 
für den Anwender "easy 2  use".

die Feinauflösung bei den Sin/Cos-Gebern finde ich immer noch brillant, 
aber da scheiden sich unsere Geister ein wennig.

Für Analoge "Geschichten" in der Nähe von Servomotoren oder anderen 
Motoren, welche mit Umrichtern gefahren werden ist es höchst Brisant, 
wie Du schon geschrieben hast. Da ist nicht die kleinen Störspitzen der 
Verursacher sondern das irre hohe dU/dt (mehrere KV/µs werden hier bei 
sogenannten IGBT´s geschaltet - auch wenn der Zwischenkreis bei den 
Reglern sprich FU´s lediglich schlappe 680V- hat.  ooops das ist falsch, 
wenn der Motor in den Generatorischen Zustand geht und Energie 
zurückgibt ist es ein wennig mehr). Also hier helfen nur Motordrosselön 
um die Oberwellen zu fixen und dann noch um das Geberkabel Wunderkerne. 
Die sind im allgemeinen als Ferritkerne erhältlich und lassen sich auf 
das Kabel aufklipsen. Ich bin immer noch verwundert, wie die wirken. 
wenn mann bedenkt, dass solche Ferrite lediglich aus gesintertem 
gekraktem und wieder gepresstem Material besteht.

Also ich wünsch noch was, und freu mich auf weitere rege Beiträge.

liebe Grüße t_a_t_b-;-)


von Joe (Gast)


Lesenswert?

So, habe mir beide Varianten mal angesehen.

Variante 1 habe ich um einen Pulscount mit Vorteiler erweitert. Die 
Abtastrate beträgt ~ 400 Hz und die Routine funktioniert einwandfrei. 
Durch die Vorteilung ist auch noch der genannte Fehler ausgemerzt.

Variante 2 ist zwar schön kurz führt aber bei mir zu Fehlern.

enc_delta sollte ja +/- 1 liefern, zeitweise bekomme ich allerdings auch 
andere Werte zurück z.B. 3/4 etc, so als ob sich der Nullpunkt 
verschiebt. Bin mir nicht sicher ob es mein Fehler ist oder ob der 
Algorithmus einen Fehler erzeugen kann.

@ Peter, hast du ne Idee hierzu.

von Peter D. (peda)


Lesenswert?

Joe wrote:

> enc_delta sollte ja +/- 1 liefern, zeitweise bekomme ich allerdings auch
> andere Werte zurück z.B. 3/4 etc

Nö, der Wert kann -128 ... +127 betragen, je nachdem, wieviel Pulse seit 
dem letzten Lesen gezählt wurden.
Wichtig ist, daß das Lesen und Löschen atomar erfolgen muß.


Was bedeutet denn Vorteilung ?
Wenn Du die Pulse auf 2 Teiler gibst, sind sie doch nicht mehr um 90° 
phasenverschoben.

400Hz scheint mir etwas langsam.


Peter

von Joe (Gast)


Lesenswert?

Ja, 400 Hz ist zu langsam, habe nun die 2te Routine auch begriffen, hat 
ne Weile gedauert.

Danke für den Hinweis.

von D.ESWAR (Gast)


Lesenswert?

DDM427 ROTARY ENCODER DETAILS

von Dirk F. (dirk-frerichs)


Lesenswert?

hallo
ich habe ein kleines problem...

ich habe einen ATmega8 mit dem pollin Encoder
PANASONIC EVEQDBRL416B
datenblatt:
http://www.pollin.de/shop/downloads/D240313D.PDF

er hat also in den rastungen entweder 00 oder 11
01 und 10 sind nur während der drehung  dynamisch vorhanden

habe nun mittlerweile verschiedene codes getestet
einer funktioniert recht gut ..
ABER er bleibt manchmal einfach hängen
auch wenn er fast alleine läuft


kann mir jemand dabei helfen ?

das mit dem graycode ist gut , nur bn ich noch nicht SO in C bewandert 
das ich das komplett durchblick ...
oder etwas genauer erklären ...

vielen Dank
grüße
Dirk

von ich (Gast)


Lesenswert?

Dirk Frerichs

Teste mal das hier:

// ---- include Dateien ----
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>


// 
************************************************************************ 
**************
// ---- function prototypes ----

void wait_until_key_pressed(void);


// 
************************************************************************ 
**************
// ---- constant definitions ----

#define Schalter_A PIND1 // Schalter A im Drehgeber
#define Schalter_B PIND0 // Schalter B im Drehgeber
#define Taster_P   PIND2 // Taster im Drehgeber
#define Geber      PIND  // Drehgeber Port

#define Ausgabe    PORTB // Ausgabe Port zum Testen

volatile unsigned char richtung = 0;  // 0 ... 255


// 
************************************************************************ 
**************
ISR(TIMER0_OVF_vect)
{
  static unsigned char alter_status = 0,step = 0;
  unsigned char        neuer_status;

      neuer_status = Geber & (_BV(Schalter_A) | _BV(Schalter_B)); // 
Änderung einlesen
  if ((neuer_status ^ step)==(_BV(Schalter_A) | _BV(Schalter_B)))
  {
    if ((neuer_status ^ alter_status)==_BV(Schalter_A))
      richtung +=1;                  // Es war eins nach rechts
    else
      richtung -=1;                  // Es war eins nach links
    step = neuer_status;
  }
  alter_status = neuer_status;
}

von dirk-frerichs (Gast)


Lesenswert?

hi
hab dank aber ich habe es mit der ursprünglichen routine  hinbekommen
es läuft auch sehr gut...

da der regler aber entweder in 00 oder 11 rastet
habe ich den delta-wert nochmal geteilt



grüße

werd es mal heute abend reinstellen

von Philipp P. (putzer_philipp)


Lesenswert?

Hallo!!

Ich hätte eine Frage zur Routine und deren Anwendung:
Ich möchte eine Wetterfahne (Windrichtung) mit einem Drehgeber 
auswerten. Ich habe hierfür die Routine von Peter Dannegger verwendet 
und durchaus gute Ergebnisse erzielt.

Nun habe ich aber ein kleines Problem: die Messung soll längere Zeit 
unbeaufsichtigt betrieben werden, das heißt das Teil wird einmal zu 
Beginn der Messung genau nach Norden ausgerichtet. Der MC soll nun aus 
den erhalteten Pulsen über einen Umrechungsfaktor die Abweichung von 
Norden bestimmen. Also eine Pulsändereung nach rechts -> +3,6° usw. 
(Überlauf wird berücksichtigt)

Ist das oben beschriebene Vorgehen für eine Langzeitmessung sinnvoll? 
Wenn ich nun einen Puls pro Woche oder Tag, keine Ahnung, verliere (der 
Encoder gibt 100Pulse/Um) wären das ja 3,6° Fehler!!

Gibt es für solche speziellen Anwendungen eine besondere Art von 
Encodern?
Oder brauche ich mir um den Verlust von Pulsen keine Gedanken machen?


Vielen Dank und schöne Grüße

Philipp

von Peter D. (peda)


Lesenswert?

@Phillip

solange die Wetterfahne sich nicht im Zentrum eines Tornados befindet, 
dürfte die Windrichtung sich nicht so schnell ändern, daß Schritte 
verloren gehen.

50kHz Abtastrate und 100 Schritte bedeuten max 15000 Upm.



Peter

von Philipp P. (putzer_philipp)


Lesenswert?

Super, so was habe ich gehofft!!

UNd wenn es zu einem Tornado kommt, ist der Verlust von ein paar 
Schritten garantiert mein kleinstes Problem!!

Danke und schöne Grüße

Philipp

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Relative Drehgeber sind dafür nicht gut geeignet; dass aus irgend einem 
Grund (Schwingung, ruckartige Bewegung, mechanische/optische Probleme im 
Drehgeber)  alle paar Tage/Wochen mal ein Schritt verloren geht kann man 
nicht ausschließen. Ein Encoder der einen Absolutwert ausgibt wäre 
sinnvoller. Alternativ dazu könnte man den Drehgeber regelmäßig 
automatisch kalibrieren, z.B. durch eine Lichtschranke oder einen 
Mikroschalter an einer bestimmten Position.

von Peter D. (peda)


Lesenswert?

Andreas Schwarz wrote:
> Relative Drehgeber sind dafür nicht gut geeignet; dass aus irgend einem
> Grund (Schwingung, ruckartige Bewegung, mechanische/optische Probleme im
> Drehgeber)  alle paar Tage/Wochen mal ein Schritt verloren geht kann man
> nicht ausschließen.

Nein, man kann es ausschließen !

Das ist ja gerade der Witz am Graycode, daß sich immer nur ein Bit 
ändern kann.

Wenn also mal ein kurzer Störimpuls gezählt wird, ist er ja bei der 
nächsten Abtastung vorbei und wird wieder abgezogen.

Es kann also nur temporär ein Fehler von +-1 Impuls auftreten, aber nie 
akkumulierend.


Das trifft allerdings nur für entprellende Algorithmen wie dem obigen 
zu, die im Timerinterrupt abtasten.

Algorithmen mit Flankeninterrupt können dagegen Pulse verlieren, wenn 
die Störungen zu schnell kommen.
Und auch alle Algorithmen, die im Interrupt mehrmals den selben Pin 
einlesen, lassen sich durch Störungen leicht aus dem Tritt bringen.


Peter

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Andreas Schwarz wrote:
>> Relative Drehgeber sind dafür nicht gut geeignet; dass aus irgend einem
>> Grund (Schwingung, ruckartige Bewegung, mechanische/optische Probleme im
>> Drehgeber)  alle paar Tage/Wochen mal ein Schritt verloren geht kann man
>> nicht ausschließen.
>
> Nein, man kann es ausschließen !

Du würdest also guten Gewissens ein Signal von einem relativen Drehgeber 
mit 4 Zuständen über mehrere Wochen hinweg aufintegrieren? Das ist sehr 
mutig.

von Peter D. (peda)


Lesenswert?

Andreas Schwarz wrote:

> Du würdest also guten Gewissens ein Signal von einem relativen Drehgeber
> mit 4 Zuständen über mehrere Wochen hinweg aufintegrieren? Das ist sehr
> mutig.

Daran ist überhaupt nichts mutig, wenn der Drehgeber mechanisch und 
elektrisch in Ordnung ist und die Software auch in Ordnng ist.

Und ob 4 Sekunden, 4 Wochen oder 4 Jahre spielt überhaupt keine Rolle.

Relative Drehgeber werden sehr häufig eingesetzt und ich habe noch nie 
gehört, daß sie schlechter als absolute Drehgeber sein sollen.

Natürlich braucht man noch einen Referenzkontakt, um die Software nach 
einem Reset zu nullen.


Peter

von Dirk H. (arm-dran)


Lesenswert?

Also bei sowas wäre ich sehr vorsichtig.

Synchronisationsverluste jedweder Art können immer vorkommen.
Man kan jedoch einen Kompromiss eingehen.

Indem man für einen evtl. Referenzlauf an irgendeiner Stelle einen
sozusagen Nullungskontakt einbaut (optisch, mechanich etc).

Gibt diesem Rad (oder was auch immer es ist) einen Schwung um die eigene
Achse. Spätestens am Nullungkontakt baut er eine Referenzposition auf.

Zum einlernen dreht er das Rad bis es z.B. auf Norden zeigt, drückt ne 
Taste
und speichert intern die Anzahl der Steps bis zur 0 Referenz.

Es ist anzunehmen, daß dieser Kontakt aller Zeitperiode X dort mal 
vorbeikommt
und sich referenziert. Anhand der Steps von Norden bis 0 Punkt weiss er 
wo er steht.
Wenn die Elektronik mal ausfallen sollte oder ein kurzer Reset das 
System
lahm legt, erkennt er, das noch keine Nullung durch den Kontakt 
stattgefunden
hat und wartet zumindest, bis der Wind sein nötigstes getan hat.

Sollte natürlich ein Erdbeben auftreten und die Erdplatten verschieben
oder Nord und Südpol plötzlich umswappen, hat man halt Pech.


von Philipp P. (putzer_philipp)


Lesenswert?

Hallo!!

Danke erstmal für die Lösungsvorschläge!


@Dirk
Dein Vorschlag kling ziemlich gut, nur verstehe ich den im Moment nicht 
so ganz.

Ich stelle also meine Windfahne irgenwie auf. Wohin der Pfeil zeigt ist 
Wurscht? Unter der Fahne habe ich irgendwo einen Kontakt

Um die Fahne zu refenzieren drücke ich am MC eine Taste um dem MC zu 
sagen, jetzt kommt der Refernezwert

Nun drehe ich die Fahne bis auf Norden hin, lasse die Taste zb. los 
(oder drücke sie nochmals, je nach dem wie ichs programmiere)

Die bisher gezählten Schritte vom Puls des 0-Pkt's bis zum Nordpol 
speichere ich im EEp.

Liege ich bisher richtig??

Nur wie komme ich von diesem refenezwert auf meine Richtung? Das 
verstehe ich noch nicht ganz!
Kannst Du mir das vielleicht ein wenig genauer erklären?

Vielen Danke und schöne Grüße

Philipp

von Dirk H. (arm-dran)


Lesenswert?

Philipp Putzer wrote:
> Hallo!!
>
> Danke erstmal für die Lösungsvorschläge!
>
>
> @Dirk
> Dein Vorschlag kling ziemlich gut, nur verstehe ich den im Moment nicht
> so ganz.
>

@Philipp

OK.

Du hast eine Wetterfahne oder nen Wetterhahn.

Das ganze hängt an einer drehbaren Welle bzw. Stange.

Unten an der Stange ist ein Drehimpulsgeber montiert. Sagen wir mal mit
100 Schritten und damit einer Auflösung von 3.6°.

Nun gibt es mehrere Möglichkeiten:
(Drehimpulsgeber mit eingebauter Referenzspur lassen wir mal weg)
Ich erkläre es nur mal als Beispiel zum Verständniss. Du kannst es dann
auch anders lösen.

Du montierst auf die Welle, auf der auch der Drehgeber sitzt eine (z.B) 
Kunststoffscheibe oder Metallscheibe mit angemessenem Durchmesser.
Bohrst in diese Scheibe ziemlich weit aussen 1 (!!!) kleines (!!!) Loch.
Dann nimmst Du ne Gabellichtschranke und montierst Sie so, das Sie nen
Impuls abgibt, wenn Sie am Loch vorbei kommt. Der Reaktionsbereich 
sollte ziemlich eng sein.
Die Scheibe dreht sich natürlich mit der Welle.

Soweit so gut. Du kannst diese einmalige Position natürlich auch anders
detektieren.

Beim Einlernen drehst Du die Fahne oder den Hahn (;-)) mind. ein mal von 
Hand um die eigene Achse.

Die Software erkennt jetzt anhand des Impulses von der Lichtschranke
einen Referenzpunkt, der hat aber noch garnichts mit der Himmelsrichtung
zu tun.
Du musst hier auch keine Taste drücken, da der Referenzpunkt durch das
Drehen der Scheibe automatisch gefunden wurde.
Die Software setzt den internen Zählwert auf null und zählt ab jetzt
die Steps vom Drehgeber in beide Richtungen.

Jetzt nimmst Du Deine Fahne oder Deinen Wetterhahn noch mal in die Hand
und richtest Ihn nach Norden aus (nehme an mit Kompass) und drückst kurz 
eine Taste. Den Wert musst Du dann intern abspeichern.
Jetzt weiss Dein µC, wieviele Schritte es vom 0 Punkt bis Norden sind.
Aufgrund dieser Werte kann er alles andere berechnen.

Du könntest Dir zum Beispiel noch 2 LEDs hinbauen.
Die eine zeigt an, wenn das System nach dem Einschalten zum ersten mal
den Referenzpunkt gefunden hat und die andere ob der NORD-Wert 
eingelernt
wurde. Wenn beide LEDs an sind, arbeitet das System einwandfrei, es sei
denn, Du hast beim einlernen Norden mit Süden verwechselt.

Die Referenzierung findet dann immer wieder automatisch statt, weil 
anzunehmen ist, daß der Wind die Fahne oder den Hahn irgendwann mal
um die eigene Achse bewegt.

Die Software synchronisiert sich sozusagen immer neu, wenn Sie an dieser
Lichtschranke (nur Beispiel) vorbeikommt.




Und jetzt noch eine Möglichkeit, die alles obige unnötig macht.

Schau mal auf die Website von www.austriamicrosystems.com

AS5040
AS5043
AS5045
AS5140

So gehts auch.





von Werner B. (Gast)


Lesenswert?

<Offtopic>
Beim lesen bin ich auf ein anderes Problem gestoßen.

Wie wird die Windrichtung an den Polen bestimmt?

Am Nordpol herrscht immer Südwind?
Am Südpol immer Nordwind?
Von der puren Logik her stimmt das doch.
</Offtopic>

von Dirk H. (arm-dran)


Lesenswert?

Werner B. wrote:
> <Offtopic>
> Beim lesen bin ich auf ein anderes Problem gestoßen.
>
> Wie wird die Windrichtung an den Polen bestimmt?
>
> Am Nordpol herrscht immer Südwind?
> Am Südpol immer Nordwind?
> Von der puren Logik her stimmt das doch.
> </Offtopic>

Da wo die Fahne oder der Hahn hinzeigt, kommt aus der Gegenrichtung der 
Wind.
Ist ja nur eine Softwaredefinition wie man das dann auswertet.

Dirk

von Philipp P. (putzer_philipp)


Lesenswert?

Super, werde das mal testen.

Ich habe gesehen, dass mein Enecoder einen Z-Ausgang besitzt, könnte das 
so ein Refenzpunkt sein, der beretis im encoder drin eingebaut ist??

wenn ja, würde ich natürlich den nehmen



grüße

philipp

von Dirk H. (arm-dran)


Lesenswert?

Philipp Putzer wrote:
> Super, werde das mal testen.
>
> Ich habe gesehen, dass mein Enecoder einen Z-Ausgang besitzt, könnte das
> so ein Refenzpunkt sein, der beretis im encoder drin eingebaut ist??
>
> wenn ja, würde ich natürlich den nehmen
>
>
>
> grüße
>
> philipp

Z ist leider keine Referenzposition sondern nur eine UND Verknüpfung
von Signal A & B
Daher, wenn A=1 + B=1 so ist Z auch =1

Dirk

von Philipp P. (putzer_philipp)


Lesenswert?

Hi!

Habe gerade den Encoder ausgemessen, dieser liefert am Z-Ausgang an 
EINER einzigen Position einen High-Pegel.

Deshalb denke ich, der Z-Ausgang wird dann auch als refenzierungspunkt 
gedacht sein.


werde das mal in absehbarer zeit testen!

vielen dank für die Hilfe und schöne grüße

philipp

von Knut (Gast)


Lesenswert?

Als Nullimpuls oder Referenzimpuls wird ein einzelner Impuls je 
Umdrehung der Geberwelle bezeichnet. Er dient insbesondere zur exakten 
Feststellung einer Null- oder Referenzposition. Um den Nullimpuls 
drehrichtungsunabhängig exakt auswerten zu können, wird er als Standard 
mit dem High-Pegel der beiden Kanäle A und B verknüpft. Durch den 
Phasenversatz der Kanäle ist der Nullimpuls nur halb so lang wie ein 
Impuls A oder B. Die Auswerte-Elektronik muß für den Nullimpuls in der 
Lage sein, die doppelte Eingangsfrequenz zu verarbeiten. Für den Fall, 
daß dies nicht möglich ist, oder wenn aus anderen Gründen ein längerer 
Nullimpuls benötigt wird, kann er für viele Typen auch unverknüpft und 
mit nahezu beliebiger Länge geliefert werden.

Quelle:
http://www.wachendorff.de/Drehgeber/Signalverarbeitung.php

von Gast (Gast)


Lesenswert?

Hallo,

kann jemand das Beispiel von Hr. Dannegger mal in CCS Code darstellen. 
Ich kriege den Encoder einfach nicht abgefragt,bzw. den Code portiert...

Danke

von sepp (Gast)


Lesenswert?

Was ist ein CCS Code?

von Peter D. (peda)


Lesenswert?

sepp wrote:
> Was ist ein CCS Code?

Wüßte ich auch gern.

Muß jedenfalls etwas total anderes als C sein, wenn selbst 8 Zeilen 
C-Code zuviel sind :-)


Peter

von Dirk F. (dirk-frerichs)


Lesenswert?

glaube code composer studio

von Dirk H. (arm-dran)


Lesenswert?

Dirk Frerichs wrote:
> glaube code composer studio

Code Composer Studio ist eine Software und keine Programmiersprache.
Für die ARM Controller TMS470 von TI aber hauptsächlich für alle DSP 
Familien TMS320--------
24xx
28xx
5000
6000
etc.

von gast (Gast)


Lesenswert?

@ Peter Man kann genausogut einen Pin-Change-Interrupt nehmen, 
Hauptsache der
Interrupt reagiert auf alle 4 Flanken.

Hallo Peter

Wie ist das gemeint? Der gleiche Code geht auch mit PinChange Interrupt? 
Natürlich auf beide Pins (A und B) oder. Zudem muss man aber auch auf 
alle Flanken reagieren also steigende und fallende oder?.

danke

von Andi (Gast)


Lesenswert?

Ja, geht auch mit Pin-Change Interrupt.
Hatte es mit einem ATTiny26 gemacht und sicherheitshalber doch kleine 
Kondensatoren (10µF glaube ich) drangehängt.
Ob jetzt beide Pins oder nur einer für die Kanäle auf Pinchange gesetzt 
werden müssen weis ich nicht mehr genau, schon lange her. Aber im 
Prinzip wird primär erst nur ein Pin auf Veränderung abgefragt, also 
müsste einer reichen. Bei Veränderung kommt dann die weitere Auswertung.
Der Pinchange muss auf "toggle" gesetzt werden, also steigend UND 
fallend.
Aber auf was Peter eigentlich hinaus wollte ist, das man sich mit seiner 
Art der Timer-Abfrage und Auswertung die Kondensatoren sparen kann da 
gewisses "flimmer" ausgefiltert wird.
Hatte mir das für nen anderes Projekt in AVR-ASM umgesetzt und es geht 
wunderbar.
Natürlich, je schneller der Timer je weniger bzw. keine Fehler gibt es.
Der Timer sollte, denke ich, mind. 5 mal so hoch sein wie es 
Raststellungen je Umdrehung gibt um auch schnell drehen zu können.

MfG
Andi

von neuhier (Gast)


Lesenswert?

Hallo zusammen, ich bin noch recht neu hier, und versuche schon eine 
Weile den 2ten Code von Peter für die Einstellung der Uhrzeit zu 
verwenden.

Jedoch ist mir leider noch immer nicht klar geworden wie ich den 
Drehgeber richtig auswerte.
Im Moment gebe ich nur enc_delta auf einem LCD aus. Der Wert läuft auch 
wenn ich am Drehgeber Drehe von -128 bis +127.

Ich bekomm es leider nicht hin das mir nur die Änderung seit dem letzten 
Interrupt angezeigt wird.

Gruß Michael

von falscher Hase (Gast)


Lesenswert?

In ca. 2 Beiträgen oben steht die Lösung auf Dein Problem mit 
zusätzlicher Info: enc_delta bei der auswertung auf null setzen. Evtl. 
auch noch durch 2 teilen (besser um ein Bit verschieben).

von falscher Hase (Gast)


Lesenswert?

Ich habe aber auch eine Frage:

Ein Komparator macht aus den durch Drehen entstehenden 
Wechselspannungsimpulsen eines Schrittmotors ein 5-V Rechtecksignal 
(Beitrag "bürstenloser motor als quadraturencoder, störungen beheben"). Leider ist aber der 
Normalzustand 11, daher gibt es beim Drehen immer erst ein low-Impuls 
auf einer der Leitungen, bevor dann schöner Gray-Code kommt.

Ich benutze den Algorithmus von Peter in einem Pin-Change Interrupt, der 
auf beide Leitungen anspricht.
Ich hatte gehofft, dass der Algorithmus den Anfangsimpuls ignoriert, 
bekomme aber keine entsprechendes Ergebnis (enc_delta chaotisch auf 2 
oder 3).

Schöner wäre es sowieso, wenn gleich der erste Impuls (ein 
(Halb-?)Schritt des Motors) ausgewertet werden könnte, aber ich sehe 
nicht, wie das mit P.D.s Logik vereinbar ist.

Hier noch Codeausschnitte für einen tiny2313 @ 8MHz, 'Encoder' ist an 
PB1 u. PB0
1
// ENCODER
2
3
#define PHASE_A (PINB & 1<<PB0)
4
#define PHASE_B (PINB & 1<<PB1)
5
6
7
volatile int8_t enc_delta;    // -128 ... 127
1
  // pin change interrupts
2
  GIMSK =  1<<PCIE;
3
  PCMSK = 1<<PCINT0 | 1<<PCINT1;
4
5
  sei();
1
ISR(PCINT_vect)
2
{
3
4
  static int8_t enc_last = 0x01;
5
  int8_t i = 0;
6
7
  if( PHASE_A )
8
    i = 1;
9
10
  if( PHASE_B )
11
    i ^= 3;        // convert gray to binary
12
13
  i -= enc_last;      // difference new - last
14
15
  if( i & 1 ){        // bit 0 = value (1)
16
    enc_last += i;      // store new as next last
17
18
    enc_delta += (i & 2) - 1;    // bit 1 = direction (+/-)
19
  }
20
  
21
}

enc_delta lasse ich mir mit 1Hz ausgeben.

von Thomas S. (thomas55)


Angehängte Dateien:

Lesenswert?

Hallo und guten Morgen,

gestern Abend brauchte ich eine Routine für einen Rotgeber und bin dann 
bei der Suche hier gelandet. Dann habe ich auch einiges hier 
heruntergeladen um den Rotgeber zum Leben zu erwecken. Lief alles nicht 
wirklich und mit AT´s und mit C (HILFE) kenne ich mich noch ganz 
schlecht aus.
So. Es läuft. Und ich weiss auch warum. Und weil ich da vielleicht was 
anderes habe möchte ich es Euch zeigen.
Die Überlegung: A ist der Takt bei dem mich nur die steigende Flanke 
interessiert und Bist das Datum, das mir sagt ob rechts oder links 
gedreht wurde.
Damit und mit der Info aus meiner Krikelei (Anlage) ist dann die kleine 
Interruptroutine entstanden die wunderbar läuft.

Euch allen hier danke ich für die Vorarbeit. Mit Eurer Hilfe weiss ich 
jetzt wie diese kleinen Dinger funktionieren.
So, jetzt kommt das Programm. Interessant ist ja nur die 
Interruptroutine.
Hoffenlich kann es jemand gebrauchen.

#include <avr/io.h>
#include <avr/interrupt.h>
// #MCU ATmega16
#define Schalter_A PINA1 // Schalter A im Drehgeber
#define Schalter_B PINA0 // Schalter B im Drehgeber
#define Taster_P   PINA2 // Taster im Drehgeber
#define Geber      PORTA  // Drehgeber Port
#define Ausgabe    PORTC // Ausgabe Port zum Testen

volatile unsigned char richtung = 0;  // 0 ... 255
unsigned char        neuer_status;
#define PHASE_A  (PINA & 1<<PINA0)  // RotaryEncoder
#define PHASE_B (PINA & 1<<PINA1)  // RotaryEncoder
volatile uint8_t  enc_delta;      // RotaryEncoder

// 
************************************************************************ 
**************
// WICHTIG: Die Frequenz der Interrupts muss möglichst hoch sein.
// Sonst gibt es so mekwürdigkeiten dass man denken könnte die Tasten
// prellen wie doll und verrückt. Wie hoch die Frequenz hier ist
// weiss ich nicht. Wie könnte man das herausbekommen?
SIGNAL (SIG_OVERFLOW2)
{
//Interrupt, wenn T2 überläuft wird der RotaryEncoder abgefragt
// PHASE_A und PHASE_B sind die Spuren A und B
// A ist jetzt die Taktspur und B die Datenspur.
  static char A_alt;

  if (PHASE_A != A_alt) // es gab zumindest einen Flankenwechsel
    {if (PHASE_A)    // wenn das auch noch WAHR ist war die Flanke 
steigend
    {if (PHASE_B)    // wenn jetzt B HIGH ist
        enc_delta++;  // dann ist das eine Rechtsdrehung
     else      // wenn nicht,
      enc_delta--;  // dann ist es eben eine Linksdrehung
       }        // fertig
     }          // aaaaaH, fast vergessen:
  A_alt = PHASE_A;  // jetzt aber: Fertig.
}
// 
************************************************************************ 
**************
int main(void)
{
  // Drehgeber Anschluß
  DDRA  &= ~(_BV(PA1) | _BV(PA0)); // Pin's als Eingang
//  PORTA  =  (_BV(PA1) | _BV(PA0)); // PullUp's ein
  DDRC   = 0xFF;                   // Port  als Ausgang

  // Timer2 einstellen
    TCCR2 |=  (1<<CS22)| (0<<CS21)  | (1<<CS20);
    TIMSK  = 1<<TOIE2;      //enable timer2 interrupt OVERFLOW
  sei();

  for(;;)                       // Hauptschleife
  Ausgabe  = enc_delta;
}

// 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
++++++++++++++

von Falk B. (falk)


Lesenswert?

@ Thomas Salewsky (thomas55)

>Dateianhang: gekrikel.jpg (210,2 KB, 11 Downloads)

Nomen est Omen.

>Die Überlegung: A ist der Takt bei dem mich nur die steigende Flanke
>interessiert und Bist das Datum, das mir sagt ob rechts oder links
>gedreht wurde.

Die "Idee" ist nicht neu, aber leider schlecht. Siehe Drehgeber.

MFG
Falk

von Thomas S. (thomas55)


Lesenswert?

@  Falk Brunner (falk)

Hallo Falk,
Deinem Rat bin ich gefolgt und habe den Artikel Drehgeber gelesen.

In dem Artikel wird genau meine Lösung empfohlen "Absatz 
Signalauswertung".

Leider steht dort auch im ersten Absatz richtiger Unsinn über Entprellen 
und den Vorteil der Gray-Codierung. Aber der Autor wiederspricht sich ja 
dann noch bei seinem Gemecker über die Auswirkungen des Prellens.

Jedenfalls sollte meine Lösung für jeden Rastpunkt nur eie Stelle zählen 
und klein sein. Das ist keine Auswertung von Motordrehgebersignalen - 
ausser wenn Motoren Seeeehr langsam laufen (ab Drehzahl > 600 wird es 
kritisch).

Vielleicht bin ich aber auch zu sehr Anfänger.

Deine Kritik kann ich jedenfalls nicht nachvollziehen.


Gruss Thomas

von Falk B. (falk)


Lesenswert?

@  Thomas Salewsky (thomas55)

>In dem Artikel wird genau meine Lösung empfohlen "Absatz
>Signalauswertung".

???
Das Verstehen von Sachtexten müssen wir wohl noch ein wenig üben . . .

>Leider steht dort auch im ersten Absatz richtiger Unsinn über Entprellen
>und den Vorteil der Gray-Codierung. Aber der Autor wiederspricht sich ja
>dann noch bei seinem Gemecker über die Auswirkungen des Prellens.

Ach ja?

>Vielleicht bin ich aber auch zu sehr Anfänger.

Sieht wohl so aus.

>Deine Kritik kann ich jedenfalls nicht nachvollziehen.

Siehe oben.

MFG
Falk

von friedrich (Gast)


Lesenswert?

Hier kurzer Erfahrungsbericht:

Habe einen STEC12E06 :: ALPS STEC12E Drehimpulsg., 24/24, horiz., MT

an zwei pins mit internem pull-up liefert das Ding gerastet 11. Peters 
Code erkennt auch die Schritte zwischen den Rastungen einwandfrei (pin 
change interrupt).

Man muss daher aufpassen, dass man den Schrittzähler erst vierteilt, 
wenn das auch Sinn macht. Sonst wundert man sich.

von Chrislight (Gast)


Lesenswert?

Hallo Zusammen...
Ich benuzte für ein kleines Projekt den im 2ten Beitrag vorgestellten 
Code um einen Drehgeber auszulesen... Nun habe ich die Frage, wie ich 
die Zahl in enc_delta begrenzen kann? Ich will diese auf meinen PWM 
Ausgang geben. die enc_delta variable soll nur von 0 bis 1000 zählen 
können. Wenn ich das ganze mit einer if abfrage im Hauptprogramm (nicht 
in der Interrupt Routine) mache...
1
if (enc_delta >= 1000)
2
{
3
     enc_delta=1000;
4
}

funktioniert es jedoch wenn ich...
1
if (enc_delta <=0)
2
{
3
     enc_delta=0;
4
}
habe ich das Problem, dass meine Variable nie kleiner als 0 wird. Diese 
geht danach wieder auf 65536 (16Bit Zahl) weil diese Zahl grösser als 
1000 ist geht er mir in die erste if abfrage was kann ich dagegen tun? 
mittels abspeichern der Zahl in einen OLD_Value hatte ich auch keine 
erfolge, da ich ja den Timerinterrupt verwende kann es aber irgendwie 
vorkommen, dass er mir einzelne punkte überspringt... von 1 gerade auf 3 
und nicht auf 2...

Hoffe es kann mir jemand helfen... Chrislight

von Chrislight (Gast)


Lesenswert?

Das Problem für mich ist, dass die Abfrage ja im Timer Interrupt 
passiert... Somit weis ich nie wann die Abfrage durchgeführt wird...

von Michael K. (Gast)


Lesenswert?

Ich denke, dass es am besten ist wenn du diese Abfrage auch in der ISR 
machst. Dort ändert sich der Wert immer nur um +/- 1 und deswegen kannst 
du auf x==1000+1 und x==0-1 abfragen.

Wenn du die Abfrage in der main machst, kann es sein, dass du auf 1000 
stehst, um 2 erhöhst, diesen Wert (1002) für deine PWM verwendest und 
anschließend erst die Abfrage (x>1000) und ggf. Korrektur erfolgt.


Oder du lässt die Abfrage in der main, "denkst dir eine Grenze" und 
fragst auf diese ab, z.B. 65535-1000=64535; 64535/2=32267; 
32267+1000=33267.
Dann die Abfrage ob
x>1000  &&  x<33267     => 1000
und
x>=33267                => 0

Wobei: x=enc_delta

Auf die letzte Weise kann allerdings der im 2. Absatz beschriebene Fall 
eintreten.

von Boris H. (eddi)


Lesenswert?

Hallo Chrislight

Bei mir sieht das Ganze so aus:
1
ISR (TIMER0_OVF_vect)
2
{
3
  static uint8_t last_state = 0,last_cnt = 0;
4
  uint8_t new_state;
5
6
  new_state=PIND & (_BV(PIND4) | _BV(PIND3));
7
  if ((new_state^last_cnt)==(_BV(PIND4) | _BV(PIND3)) )
8
  {
9
       if ((new_state ^ last_state)==_BV(PIND4))
10
          {  
11
      if(enc_delta < 100) enc_delta++;
12
    }
13
    else
14
    {
15
      if (enc_delta > 0) enc_delta--;
16
    }
17
        last_cnt=new_state;
18
  }
19
  last_state=new_state;
20
//
21
//  PWM
22
//
23
  if (pwm_counter++ > 100) 
24
  {
25
    PORTA = 0x00;
26
    pwm_counter = 0;
27
  }
28
}

Ich zähle dabei von 0 bis 100. enc_delta ist folgendermassen deklariert:

volatile uint8_t   enc_delta=0;

Gruß
Boris

von Chrislight (Gast)


Lesenswert?

Ey Super! Die oben erwähnte Antwort von Michael K. hat mir sehr 
geholfen! So funktionietrt es Bestens und ich habe auch keine grösseren 
Probleme, da ich die Variable enc_delta immer auf den höchswert (1000) 
oder auf null setze bei der jeweiligen abfrage. Besten Dank Chrislight

von Markus B. (wolframator)


Lesenswert?

Ich habs so gelöst bei meinem optischen Drehgeber:
(PEC11 von Bourns)
1
  while (1)
2
  {
3
    if(((PINA & 0x01) == 0) && ((PINA & 0x02) == 0)) { j=1; }
4
    if(((PINA & 0x01) == 0) && ((PINA & 0x02) != 0)) { j=2; }
5
    if(((PINA & 0x01) != 0) && ((PINA & 0x02) != 0)) { j=3; }
6
    if(((PINA & 0x01) != 0) && ((PINA & 0x02) == 0)) { j=0; }
7
8
    if(j != last)
9
    {
10
      if((j+1) % 4 == last) i--;
11
      if((last+1) % 4 == j) i++;
12
      last=j;
13
    }
14
15
    if(i>=5)
16
    {
17
      i=i-5;
18
      //Drehrichtung 1
19
    }
20
    if(i<=-5)
21
    {
22
      i=i+5;
23
      //Drehrichtung 2
24
    }
25
  }


/Edit:
Bevor jemand meckert... Natürlich kann man die Pin-Abfrage auch 
kompakter gestalten, aber so denke ich sieht selbst ein Anfänger recht 
gut was passiert :)

von Nils (Gast)


Lesenswert?

Hallo,

ich scheine irgendwie auf dem Schlauch zu stehen. Ich habe den Code aus 
dem 2. Posting in die Timer0 Interrupt Routine eingefügt und verwende 
folgenden Drehencoder

http://www3.alps.com/WebObjects/catalog.woa/E/HTML/Switch/Encoder/EC11/EC11E18244AU.html

Es scheint das der Encoder nur jede 2. Rastung zählt.

Jetzt die Frage ... ich habe das so verstanden, das in der variable 
enc_delta der Wert +1 oder -1 steht richtig? Ich habe dann in meinem 
Hauptprogramm einfach die Variable die ich hoch oder runterzählen will 
mit der Variable enc_delta addiert (Y += enc_delta;). Doch leider 
funktioniert das nicht. Es wird nicht gezählt. Habe ich da was falsch 
verstanden?

Gruss
Nils

von Michael K. (Gast)


Lesenswert?

> Habe ich da was falsch verstanden?

Ja hast du. In enc_delta steht dein Wert (-128 ... 127). Du musst nichts 
mehr rechnen, sondern kannst enc_delta so verwenden.

Lass doch mal das Beispiel-Programm so laufen wie es ist. Dann wird dir 
auf Port B der aktuelle Wert ausgegeben. Und dieser sollte erniedrigt 
oder erhöht werden, je nachdem in welche Richtung du drehst.

von Nils (Gast)


Lesenswert?

Vielen Dank, das war der entscheidende Hinweis. Jetzt zählt er auf und 
ab. Das Problem ist jetzt noch das er mit jeder Rastung 2 hoch oder 
runterzählt. Gibts da auch noch einen kleinen Tipp?

von Nils (Gast)


Lesenswert?

Ach so ... ein Problem war auch noch das ich die internen Pullups 
benutzt hatte. Erst als ich extern Pullups angeschlossen hatte und die 
internen deaktiviert habe funktionierte es. Den Common habe ich auf GND 
gelegt. Funktioniert das bei euch mit den internen Pullups und dem Code 
von Peter Danegger?

von Nils (Gast)


Lesenswert?

OK, ich habe die Lösung in einem anderen Beitrag gefunden. Da wurde es 
so gelöst:

1
ISR(TIMER0_OVF_vect)
2
{
3
  static char enc_last = 0x01;
4
    char i = 0;
5
6
    if( PHASE_A )
7
      i = 1;
8
9
    if( PHASE_B )
10
      i ^= 3;                // convert gray to binary
11
12
    i -= enc_last;            // difference new - last
13
14
    if( i & 1 )            // bit 0 = value (1)
15
  {      
16
      enc_last += i;          // store new as next last
17
18
      enc_delta += (i & 2) - 1;    // bit 1 = direction (+/-)
19
20
      if (!(enc_delta % 2))     // nur jeden 2. Schritt zählen
21
    {  
22
        if ((i & 2))       // prüfen ob auf oder ab
23
      {    
24
          ms++;        // Variable die hochgezählt werden soll
25
        }
26
        else 
27
      {
28
              ms--;     // Variable die runtergezählt werden soll     
29
        }
30
      }
31
    }
32
}

Eine Frage bleibt jetzt noch ... warum brauche ich externe Pullups damit 
es läuft. Hängt es mit PORTA zusammen?

Gruss

von M. K. (kichi)


Lesenswert?

Es sollte egtl. auch mit den internen funktionieren. Wobei ich den Code 
allerdings noch nicht auf einem AVR laufen hatte.

Bei meinen derzeitigen Encodern werden 2,2k-Pullups empfohlen und damit 
klappt es. Vielleicht sind die internen zu hochohmig...

von martin (Gast)


Lesenswert?

Hallo,

die manuelle Eingabe von größeren Werten ist mit groben Encodern ja 
etwas mühselig. Hat sich da schonmal jemand Gedanken zu einer 
"Beschleunigung" gemacht? Also z.B. dass die Schrittweite proportional 
zur Zeit zwischen zwei Impulsen ist?

von M. K. (kichi)


Lesenswert?

Ich habs mal mittels dem (im Drehgeber integrierten) Taster zwischen 1, 
10 und 100 umschaltbar gemacht. Klappt ganz gut und lässt sich auch gut 
bedienen, finde ich.

von nichts (Gast)


Lesenswert?

Ich hatte das mal ganz einfach mit einer Potenzierung gemacht...das 
klappte sehr gut:
Beim langsamen Drehen konnte man die Werte genau einstellen, wenn man 
schnell drehte, kam man schnell in die richtige Region...

Das war aber vom Programmierstil her eine ziemlich unschöne Lösung.

von martin (Gast)


Lesenswert?

Sowas lässt sich bestimmt in P.D.s Code mit ein, zwei zusätzlichen 
Variablen und ein bisschen Bit-Trickserei integrieren...? ;-)

von Igor M. (bastel-wastel)


Lesenswert?

Hab da auch mal ne Frage:

enc_delta gibt mir Zahlen zwischen -128 ... 127 aus. Wenn ich mir diese 
Variable über itoa(); umwandle und am LCD ausgebe, bekomme ich Werte von 
0..127. Negative Zahlen kann die Funktion wahrscheinlich nicht - egal.
Ich bräuchte jetzt aber inkrementale Werte.

Habs zum Testen so versucht

unsigned char Zaehler;

Zaehler  = 100;

for(;;)
{
cli();
Zaehler = Zaehler + enc_delta/2;
enc_delta = 0;
sei();
Zaehler ausgeben();
}

Problem: Beim Hochzaehler wird manchmal eine Rasterung ausgelassen und 
beim Runterzaehler werden Werte um ca. 128 Werte nach unten gesprungen. 
Der Compiler kann doch mit negativen Zahlen umgehen...
Ich befürchte, dass ich einen ganz dummen Fehler eingebaut habe.
Kann mir jemand weiter helfen?

von Falk B. (falk)


Lesenswert?

@ Igor Metwet (bastel-wastel)

>Variable über itoa(); umwandle und am LCD ausgebe, bekomme ich Werte von
>0..127. Negative Zahlen kann die Funktion wahrscheinlich nicht - egal.

Doch, eigentlich schon, heisst ja I (wie Integer) to ASCII.

>for(;;)
>{
>cli();
>Zaehler = Zaehler + enc_delta/2;

Kein gute Idee, damit werden Pulse verschluckt

>enc_delta = 0;
>sei();
>Zaehler ausgeben();
>}

Besser so.

1
uint16_t; Zaehler  = 100
2
3
for(;;)
4
{
5
  cli();
6
  Zaehler = Zaehler + enc_delta;
7
  enc_delta = 0;
8
  sei();
9
  ausgeben(Zaehler/2);
10
}

>beim Runterzaehler werden Werte um ca. 128 Werte nach unten gesprungen.
>Der Compiler kann doch mit negativen Zahlen umgehen...

Ja, aber möglicherweise hast du Variablen falsch deklariert. Poste 
VOLLSTÄNDIGEN Quelltext als ANHANG.

MfG
Falk

von Gerd (Gast)


Lesenswert?

Schau dir mal den Unterschied zwischen signed char und unsigned char an!

von Igor M. (bastel-wastel)


Angehängte Dateien:

Lesenswert?

> Kein gute Idee, damit werden Pulse verschluckt
Danke! Jetzt kann ich hoch- und runterzählen ;-)


>>Variable über itoa(); umwandle und am LCD ausgebe, bekomme ich Werte von
>>0..127. Negative Zahlen kann die Funktion wahrscheinlich nicht - egal.
>
> Doch, eigentlich schon, heisst ja I (wie Integer) to ASCII.

Wenn ich runterdrehe bis auf null und dann noch einen Puls Richtung 
negative gebe, werden am Display "127" ausgegeben.
Ich habe aber allerdings die Variable "Zaehler" als char und nichts als 
int deklariert. Da wären wir schon beim nächsten Effekt: Wird "Zaehler" 
als int deklariert, dann zählt er hoch aber anstatt runter zu zählen, 
zählt er pro Schritt 127 oder 255 hoch.

von Chris W. (squid1356)


Lesenswert?

while (1){


    cli();
    encoder += enc_delta;
    enc_delta = 0;
    sei();


    uint8_t s[3];
    sprintf (s, "encoder: %3d", encoder);
    vfd_cstring(2,s);

  }

Hi!

Ich benutze auch den Drehgeber-Code von Peter Dannegger ( Code ganz 
oben, die zweite!)

wie in dem letzten Beispiel wird auch die enc_delta benutzt um den 
zähler ("uint8_t encoder = 0;") hoch bzw. runter zu zählen.

leider springt der wert aber nur zw. 0 und 255 bei linksdrehung und 
zwischen 0 und 1 bei rechtsdrehung.

ich habe mir nun schon einige beispiele hier angesehen und beiträge 
gelesen, stehe aber leider auf dem schlauch. kann mir jemand helfen bzw. 
einen tip geben?? (ps. ich benutze einen drehgeber OHNE rastung)

Danke, Christoph

von Micha (Gast)


Lesenswert?

Hast du mal versucht
1
enc_delta
direkt zu verwenden?

von Chris W. (squid1356)


Lesenswert?

Micha wrote:
> Hast du mal versucht
1
enc_delta
direkt zu verwenden?

enc_delta springt zw. 0/ 1 (rechts) bzw. 0/ -1 (links)

von T. S. (trse)


Lesenswert?

Hallo,
Wie intigriere ich das in mein Programm???
In meiner main-Funktion steht eigentlich dass ganze Programm drinne,
Wenn ich das mit der Abtastung(
1
 for(;;)        // main loop
2
    PORTB = enc_delta;
) mache, dann läuft mein Programm doch nicht mehr in der 
while(1)-Schleife???

Würde es gehen, wenn ich das
1
PORTB = enc_delta;
 in die while-Schleife packe???

von Chris W. (squid1356)


Lesenswert?

T. S. wrote:
> Würde es gehen, wenn ich das
1
PORTB = enc_delta;
 in die
> while-Schleife packe???
1
PORTB = enc_delta;
 -> das gibt nur das enc_delta auf die LED's aus (angenommen die sitzen 
hier wie beim STK500 an Port B)

enc_delta sollte eigentlich die Anzahl an schritten enthalten die der 
Interrupt vom Drehgeber eingelesen hat. (Sehe ich doch richtig?!)

Sieh doch mal weiter oben, da steht eigentlich alles was man braucht.

mein Problem besteht übrigens noch immer...
siehe Beitrag "Problem mit Drehgeber"

von Micha (Gast)


Lesenswert?

> mein Problem besteht übrigens noch immer...
> siehe Beitrag "Problem mit Drehgeber"
Richtig angeschlossen ist alles? Bleibt das Problem wenn du enc_delta 
auf einen Port ausgibst?
So verkehrt sieht das nicht aus - die Werte würden passen. Falsch ist 
halt dass es nur 1 Schritt tut...

von Chris W. (squid1356)


Lesenswert?

Micha wrote:
> Richtig angeschlossen ist alles?
Ja. siehe auch im anderen Forum, habe den Beitrag mal da rein gestellt, 
gehört ja hier eig. nicht hin!
>Bleibt das Problem wenn du enc_delta auf einen Port ausgibst?
hm, wie genau meinst du das ?
> So verkehrt sieht das nicht aus - die Werte würden passen. Falsch ist
> halt dass es nur 1 Schritt tut...
eben. denke ich bin ganz nah dran (oder meilenweit entfernt...)
habe grade nochwas interessantes festgestellt: wenn ich GANZ schnell 
drehe (so schnell wie normalerweise niemand an dem ding drehen würde) 
dann kommen auch vernünftige schritte raus. nur halt zu schnell. ist mir 
irgendwie rätselhaft...

naja, ich warte noch ne weile, vielleicht kann mir jemand den 
entscheidenden Tip geben. ansonsten besorg ich mir (leider) nen neuen 
Geber...

von Micha (Gast)


Lesenswert?

> hm, wie genau meinst du das ?
Naja du schreibst deine Werte jetzt ja auf ein Display, oder? Ich meine 
du sollst mal enc_delta direkt auf einen Port ausgeben.

Und poste wenn möglich mal deinen gesamten Source-Code.

von Chris W. (squid1356)


Lesenswert?


von Stephan S. (outsider)


Lesenswert?

Ich habe die Drehencoder Funktionen benutzt die hier beschrieben sind:

http://www.mikrocontroller.net/articles/Drehgeber

Nachdem ich ewig rumgemacht habe und nichts funktioniert hat, aber 
eigentlich funktionieren hätte sollen hab ich festgestellt dass die 
enc_delta außerhalb der ISR nicht vorhanden ist, obwohl es eine globale 
Variable ist.

Bin leider nicht sehr erfahren mit C und µC, hatte aber was von volatile 
im Hinterkopf. Nachdem ich die Variable volatil deklariert hab hat alles 
funktioniert.

Jetzt frag ich mich: Was ist beim Author anders dass es bei ihm ohne 
volatile funktioniert und bei mir nicht? So wie ich das verstanden habe 
muss man als volatile deklarieren wenn eine Variable nicht vom 
angetastet werden darf weil sie z.B. von Ports oder ISRs verändert 
werden kann, was ja bei dem Code der Fall ist.

von Michael K. (Gast)


Lesenswert?

> Jetzt frag ich mich: Was ist beim Author anders dass es bei ihm ohne
> volatile funktioniert und bei mir nicht?
Ich denke hier http://www.mikrocontroller.net/articles/Drehgeber wurde 
das volatile einfach vergessen, weil hier 
Beitrag "Re: Drehgeber auslesen" ist es ja mit drin (und 
das funktioniert auch).

von Stephan S. (outsider)


Lesenswert?

Ja verlinkt ist dieser Thread, aber hier kann ich keine Infos finden zu 
den Funktionen von dem Artikel.

Und wo ich schon dabei bin: Hat jemand eine Lösung wie man verhindern 
kann dass das erste mal Drehen nicht funktioniert? Beim 4-fach Schalter 
sollte das doch möglich sein eine eindeutige Aussage zu treffen in 
welche Richtung es geht weil man ja auch ohne bekannte Vorbedingung 
davon ausgehen kann dass die Vorbedingung so aussieht dass bei beiden 
Phasen eine Null war. Ich denke das ist vielleicht auch der Grund warum 
es solche Schalter überhaupt gibt.

von Peter D. (peda)


Lesenswert?

Stephan S. wrote:
> Jetzt frag ich mich: Was ist beim Author anders dass es bei ihm ohne
> volatile funktioniert und bei mir nicht?

Ja, das sind so die kleinen Gemeinheiten des GCC.
Er will unbedingt auch Funktionen inlinen, die nicht static sind und 
dadurch ergeben sich unschöne Seiteneffekte:

Einer Funktion, die eine Variable nur einmal benötigt, ist es egal, ob 
sie volatile ist oder nicht, sie muß sie einlesen. Volatile und der 
damit verbundene größere Code ist dann unnötig.

Wird nun allerdings diese Funktion im gleichen Modul aufgerufen, kann es 
sein, daß der Compiler sie inlined und damit optimiert er sie weg, wenn 
die Variable nicht volatile ist.
Hier im Listing sieht man schön, daß die Funktion komplett fehlt:
1
int8_t encode_read1( void )
2
{
3
  int8_t val;
4
5
  cli();
6
 118:   f8 94           cli
7
  val = enc_delta;
8
  enc_delta = 0;
9
  sei();
10
 11a:   78 94           sei


Diese unschöne Disoptimierung kann man aber abschalten mit folgender 
Compileroption:

-fno-inline-small-functions


Peter

von Stephan S. (outsider)


Lesenswert?

Wow, das ist mal echt eine gute Antwort... Wenn ich das aber nicht 
wüsste und die Variable doch als volatile deklariere, handle ich mir 
damit irgendwelche nennenswerten Nachteile ein?

Und was ist mit dem Problem dass der erste Schritt beim Drehen nicht 
richtig erkannt wird?

von Michael K. (Gast)


Lesenswert?

> Wenn ich das aber nicht wüsste und die Variable doch als volatile
> deklariere, handle ich mir damit irgendwelche nennenswerten Nachteile ein?
Würde mich auch interessieren.

> Und was ist mit dem Problem dass der erste Schritt beim Drehen nicht
> richtig erkannt wird?
Ich habe das so gelöst:
1
static char enc_last = 0;
2
3
SIGNAL (SIG_OVERFLOW0)
4
{
5
   char i = 0;
6
7
   if... (siehe oben, 2. Beitrag)
8
}
9
10
void init_rot_enc(void)
11
{
12
   if( PHASE_A )
13
      enc_last = 1;
14
15
   if( PHASE_B )
16
      enc_last ^= 3;
17
}
Während der Initialisierung einmal init_rot_enc aufrufen und es sollte 
funktionieren.

von Peter D. (peda)


Lesenswert?

Stephan S. wrote:
> Und was ist mit dem Problem dass der erste Schritt beim Drehen nicht
> richtig erkannt wird?

Michael hats ja schon erklärt.

Ich hab das Beispiel korrigiert:

http://www.mikrocontroller.net/articles/Drehgeber#Beispielcode_in_C


Peter

von Michael K. (Gast)


Lesenswert?

@ Peter
Hat es einen bestimmten Grund dass du aus
1
  if( PHASE_A )
2
    i = 1;
3
4
  if( PHASE_B )
5
    i ^= 3;
folgendes gemacht
1
  if( PHASE_A )
2
    new = 3;
3
4
  if( PHASE_B )
5
    new ^= 1;
also ...= 3; und ...= 1; getauscht hast?

von Peter D. (peda)


Lesenswert?

Michael K. wrote:
> @ Peter
> Hat es einen bestimmten Grund dass du
> ...= 3; und ...= 1; getauscht hast?

Ja, hat es.
Der AVR-GCC erzeugt äußerst umständlichen Code, wenn ein Bit abhängig 
von einem anderen gesetzt wird.
Er expandiert erstmal zu 16Bit und schiebt dann entsprechend oft bis an 
die richtige Bitposition.


Peter

von Udo S. (Firma: allround) (1udo1)


Lesenswert?

Hallo,

bin Quereinsteiger mit meinem optischen encoder GP1A038 von Sharp.

Ich beziehe mich auf den Code der unten noch einmal kurz aufgeführt ist:

An PortD,3 schließe ich Kanal A an und an PortD,4 Kanal B, oder? Ich 
verstehe nicht diese 4 ".set directiven". Sind die Werte 4,3 und 2 die 
Binärwerte, die von Kanal A und B generiert werden? uND WAS IST DER 
bUTTONß

Bitte mal jemand um eine Hilfestellung. Ich werfe sehr wahrscheinlich 
noch etwas durcheinander.

Gruß
Udo


Autor: avusgalaxy (Gast)
Datum: 02.02.2005 20:33

An PORT D,0 und PORT D, eins kommt jeweils eine Led.

Ab PORT D... 4 und 3 den Drehgeber.. Ah ja, so solls ausehen:


.include "2313def.inc"

.set DIPGPin=PinB    ;Port mit Drehimpulsgeber
.set DIPGChA=4       ;Pin mit Channel A
.set DIPGChB=3       ;Pin mit Channel B
.set DIPGBT=2        ;Pin mit Button
.def DIPGAlt=r4      ;Vorriger Zustand von Channel A
.def DIPG=r5         ;Drehimpulsgeber-Aktion. Nach Abfrage löschen
.def ButtonAlt=r6    ;Vorriger Zustand des Buttons

von Otto W. (Gast)


Lesenswert?

Hallo!
Ich möchte gerne einen Drehgeber mit einem Atmega 8 auswerten und auf 
eine LED Zeile ausgeben.
Leider kann ich  peter dannegger "C" Code nicht nachvollziehen. Gibt es 
diesen Code auch in Assembler und somit auch für mich nachvollziebar?
Danke für eure Hilfe Otto.

von Steffen H (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab die hier noch. Läuft auf einen ATtiny2313. Ergebnisse werden im 
RAM gespeichert.

Gruß
Steffen

von Peter D. (peda)


Lesenswert?

Steffen H schrieb:
> Ich hab die hier noch. Läuft auf einen ATtiny2313.

Ooch nöö, das ist ja ein Monstercode.

In Assembler kann man Register für Interrupts reservieren bzw. auch 
Variablen in Registern halten. Spart ne Menge Code.

Hier mal mein Code in Assembler (enc_delta = 16-bittig):
1
.include "tn261def.inc"
2
3
.def    save_SREG       = r14    ; for general interrupt usage
4
.def    int_i           = r15    ; for general interrupt usage
5
6
.def    int_val3        = r16    ; for encoder interrupt only
7
.def    enc_last        = r13    ; for encoder interrupt only
8
.def    count0          = r18    ; encoder value low
9
.def    count1          = r19    ; encoder valeu high
10
11
.equ    GRAY_IN         = PINA
12
.equ    PHASE_A         = PA0
13
.equ    PHASE_B         = PA1
14
15
        rjmp    init
16
17
.org    OC1Aaddr
18
        in      save_SREG, SREG
19
        clr     int_i
20
        sbic    GRAY_IN, PHASE_A        ; if( PIND & 1 )
21
        inc     int_i                   ;   i++;
22
        sbic    GRAY_IN, PHASE_B        ; if( PIND & 2 )
23
        eor     int_i, int_val3         ;   i ^= 3;
24
        sub     int_i, enc_last         ; i -= enc_last;
25
        sbrs    int_i, 0                ; if( i & 1 ){
26
        rjmp    _ioc1a1
27
        add     enc_last, int_i         ;   enc_last += i;
28
        sbrs    int_i, 1                ;   if( i & 2 )
29
        rjmp    _ioc1a2
30
        subi    count0, byte1(1)        ;     enc_delta--;
31
        sbci    count1, byte2(1)
32
        out     SREG, save_SREG
33
        reti
34
_ioc1a2:                                ;   else
35
        subi    count0, byte1(-1)       ;     enc_delta++;
36
        sbci    count1, byte2(-1)
37
_ioc1a1:                                ; }
38
        out     SREG, save_SREG
39
        reti                            ; 24 cycle
40
41
init:
42
        ldi     int_val3, 3             ; for usage in interupt
43
main:
44
; hier T1 starten und SPI-Slave bearbeiten
45
        rjmp    main


Peter

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Peter!

Ich habe mal eine Lösung für das vieldiskutierte Thema Dein 
Peda-Drehgeber-Code aus dem  Wiki ( 
http://www.mikrocontroller.net/articles/Drehgeber ) und der Pollin 
Drehencoder (Panasonic) ausgetüftelt.

Bekanntlich läuft der Pollin Encoder asymmetrisch. Nur Signal A ist bei 
jeder Raste stabil. Signal B kann in jeder zweiten Raste zwei Zustände 
einnehmen. (siehe Bild)

(1) Da bei dem Pollin "two step encoder" der Ausgabewert halbiert wird, 
muss bei der Initialisierung von enc_delta berücksichtigt werden, dass 
die instabilen Zwischenstufen bei (2*n) und (2*n+1) liegen, damit beim 
rechts shiften das letzte Bit keinen Übertrag erzeugt und das Ergebnis 
flattert.

(2) Falls mit internen Pullups gearbeitet wird, muss nach der 
Portinitialisierung und dem Einlesen der Port-Pegel in der Funktion 
encode_init() eine kleine Pause eingelegt werden, damit ggf. offene 
Leitungen auf High gezogen werden (Leitungskapazitäten)

(3) Der Pollin Encoder dreht gegenüber dem PeDa-Code falsch herum. Ich 
habe die Anschlüsse von A und B vertauscht.

Das ergibt dann folgende minimale Codeanpassung und der Pollin Drehgeber 
arbeitet absolut bullet proof.
1
void encode_init( void )
2
{
3
  int8_t new;
4
  _delay_ms(1);  //Verzögerung nach Initial. interner Pullups erforderlich
5
  new = 0;
6
  if( PHASE_A )
7
    new = 3;
8
  if( PHASE_B )
9
    new ^= 1;          // convert gray to binary
10
  last = new;          // power on state
11
12
 //enc_delta = 0;    
13
  enc_delta = (new&1?0:1);     //Pollin Encoder-Zählwerk auf stabile Startposition 0/1 setzen  
14
  
15
  TCCR0 = 1<<WGM01^1<<CS01^1<<CS00;    // CTC, XTAL / 64
16
  OCR0 = (uint8_t)(F_CPU / 64.0 * 1e-3 - 0.5);  // 1ms
17
  TIMSK |= 1<<OCIE0;
18
}
der restl. Code wie in http://www.mikrocontroller.net/articles/Drehgeber

von Klaus (Gast)


Lesenswert?

Hallo,

hat jemand von euch sein Programm bei einem Motor mit ca. 1500 U/min 
oder auch mehr zum laufen bekommen???
Habe erst Peters genommen und danach eins mit Interrupt 
Flankenauswertung geschrieben, klappen jedoch beide bei dieser Drehzahl 
nicht :-(

Ich wäre für Programmbeispiele sehr dankbar.

Gruß Klaus

von thomas55 (Gast)


Lesenswert?

Hallo Klaus,

es sind doch bei 1500 U/min nur 25 U/sec.

Da würde ich mit 250 Interrupts anfangen.

Welche Art Geber hast Du angeschlossen?
Möglich, dass es bei Gebern mit normalen Kontakten zu Schwierigkeiten 
kommt.

Willst Du damit eine Maschine positionieren?

Gruß Thomas

von Bernhard M. (boregard)


Lesenswert?

thomas55 schrieb:
> Hallo Klaus,
>
> es sind doch bei 1500 U/min nur 25 U/sec.
>
> Da würde ich mit 250 Interrupts anfangen.
>
> Welche Art Geber hast Du angeschlossen?
> Möglich, dass es bei Gebern mit normalen Kontakten zu Schwierigkeiten
> kommt.
>
> Willst Du damit eine Maschine positionieren?
>
> Gruß Thomas

??? Wirklich??

Wie viele Impulse / Schritte gibt der Geber denn pro Umdrehung? 16?
Dann sind es 4000 pro Sekunde, ein ordentliches Oversampling von 10 
eribt schon 40000 Timeraufrufe pro Sekunde oder ein Timerinterrupt alle 
25 mikrosekunden. Das ist sportlich....

von Peter D. (peda)


Lesenswert?

Bernhard M. schrieb:
> Wie viele Impulse / Schritte gibt der Geber denn pro Umdrehung? 16?
> Dann sind es 4000 pro Sekunde, ein ordentliches Oversampling von 10
> eribt schon 40000 Timeraufrufe pro Sekunde oder ein Timerinterrupt alle
> 25 mikrosekunden. Das ist sportlich....

Ob da ein mechanischer Encoder überhaupt mitmacht?

Bei hohen Impulsraten würde ich die Zählung in nen extra ATtiny oder 
CPLD machen und den per SPI oder I2C vom Master auslesen.


Peter

von Michael H. (mah)


Lesenswert?

> Wie viele Impulse / Schritte gibt der Geber denn pro Umdrehung? 16?
> Dann sind es 4000 pro Sekunde, ein ordentliches Oversampling von 10
> eribt schon 40000 Timeraufrufe pro Sekunde oder ein Timerinterrupt alle
> 25 mikrosekunden. Das ist sportlich....

ich habe das mit einem Arduino und 20usec Timerrate brauchbar 
hingekriegt, ohne Assembler, und optional mit Peter's Entprellung der 
A/B/Indexsignale ; da bleibt noch Luft für serielle I/O und einen 
einfachen Kommandointerpreter

siehe 
http://mah.priv.at/cgi-bin/viewvc.cgi/arduino-rotary/rotary-v6.pde?revision=1.1&root=CVS&sortby=date&view=markup 
- das war ein Debug-Vehikel von mir und ist daher kein als solches 
brauchbares Projekt

hatte folgendes Problem: CNC-Fräse mit EMC2; selbstgebauter Drehgeber 
mit 360 Impulsen/Umdrehung und Indexpuls auf einer Spindel mit bis zu 
5000 U/min zu erfassen und so runterzuteilen, so dass EMC2 mit einem 
Parallelport-Input "mitkommt"

habe das schlussendlich aber mit einer FPGA-basierten Lösung gemacht 
(Mesatech 5i20) und einem Heidenhain-Drehgeber mit 3600 Pulse/U; Grund 
war meine mangelhafte mechanische Präzision beim Drehgeber, und 
Störungen des Signals - manche Sachen kauft man besser und ein 
Drehstromumrichter müllt ganz schön

falls jemand dazu Anregungen braucht - der VHDL-Code und EMC2 selbst 
sind Open Source


-Michael

von Maurice K. (maurice)


Lesenswert?

Hallo zusammen,
ich habe gerade ihre Kommentare alle gelesen.Ich bion ganz neu hier.Ich 
mach gerade meine Technikerarbeit und ich soll auch einen Encoder ( 
inkremental)von der Firma Wachendorff verwenden.kann ich dafür auch den 
LS7366 Decoder nehmen? Und woher weiß ich welches Modell ich nehmen 
sollte,bezüglich der Anzahl der Impulse des Drehgebers????Ich soll 
nämlich die geschwindigkeit ermitteln eines Förderbands.Auch bei 
Geschwindigkeitänderungen. damit ich immer die perfekte position für ein 
Bauteil berechnen kann, um ein Foto mit ner Camera auszulösen.Die 
Position des Bauteils darf maximal 1mm +/- unter der Camera vom 
optimalen Punkt versetzt sein.Wisst ihr was ich meine????
Ich würde mich über eine Antwort sehr freuen.
Mfg Maurice

von Mathias O. (m-obi)


Lesenswert?

Macht da eine Lichtschranke nicht mehr Sinn?

von Maurice K. (maurice)


Lesenswert?

ein sogenannter triggersensor ist selbstverständlich vorhanden dieser 
kann aber aufgrund von baulichen gegebenheiten nicht direkt an der 
kamera positioniert werden desweiteren ist die geschwindigkeit des 
förderbandes nicht immer 100 prozent konstant.

von Mathias O. (m-obi)


Lesenswert?

Ist denn das Förderband an einer Steuerung angeschlossen, wenn ja kann 
man den Encoder mit der verbinden. Je langsamer das Band läuft desto 
mehr Impulse müssen es sein. D.h. läuft das Band mit einer sehr hohen 
Drehzahl, brauchst du ja nicht soviele Impulse. Wie schnell läuft denn 
das Band so im Minimum und Maximum?

von Dawn (Gast)


Angehängte Dateien:

Lesenswert?

heyhey,

hier mal mein Mockup, was auf der 2. Version von oben aufbaut. Ich 
verwende externe Interrupts, um die Auslastung so gering wie möglich zu 
halten. Der hohen Sensitivität was das bouncing angeht begegne ich mit 
einem kleinen Kniff: Das Bouniving ist ja im Prizp nichts anderes als 
das Hin- und Herpendeln zwischen zwei Zahlen. Wenn man jetzt nur 
weiterzählen lässt, wenn der aktuelle Schritt in die selbe Richtung 
gegangen ist, wie der vorherige, wir das Pendeln quasi ausgeblendet. Das 
ganze funktioniert, weil der erste Kontakt mit der neuen Stufe eines 
Schrittes in die selbe Richtung geht wie der letzte beim Bouncing. Die 
Richtung des vorherigen Schrittes wird durch die Variable Rtg_pos 
angegeben.

Beim Testen läufts bei mir in der Praxis sehr stabil, bin gespannt auf 
eure Meinungen.

VG, Dawn

von Falk B. (falk)


Lesenswert?

@  Dawn (Gast)

>Beim Testen läufts bei mir in der Praxis sehr stabil, bin gespannt auf
>eure Meinungen.

Wirklich? OK!

Du bist ebenso auf dem Holzweg wie Tausende vor dir. Ein funktionierndes 
Einzelexemplar ist kein Beweis. Das könnte bestenfalls ein Stresstest 
bringen. Wird er aber nicht. Warum? Siehe Artikel Drehgeber.

MfG
Falk

P S Kein "Aber . . ."

von Dawn (Gast)


Lesenswert?

...das schöne an so einem Forum ist doch, dass man abers bringen kann so 
viel wie man möchte :)
Wer bin ich denn, dass ich hier einen Beweis erbringen möchte, ich sage 
blos,dass das ganze für interupts sehr stabil  läuft. Für meine 
Anwendung, wo die Drehgeber nur selten verwendet werden ist pollen 
ziemlich überzogen. Einer Überlastung beuge ich durch Ausschalten der 
Interruots während der Routine vor. Zudem, was tun, wenn die Timer 
anderweitig gebraucht werden?

von BMJ (Gast)


Lesenswert?

Hi,

ich habe im Rahmen eines Projekts in der Uni die Aufgabe mit Hilfe eines 
Heidenhain Inkrementaldrehgebers und einem ATmega2561 den Drehwinkel 
bzw. die Winkelgeschwindigkeit eines Motors zu messen. Der Motor läuft 
mit maximal 2000 U/min und der Drehgeber hat 3000 Striche, das wäre also 
eine maximale Signalfrequenz von 100 KHz. Zu welcher Methode würdet ihr 
mir da raten? Eigentlich wollte ich das mit den externen Interrupts 
machen, aber ich habe jetzt hier öfter gelesen, dass es mit 
Timerinterrupts sicherer ist. Kommt der Mikrocontroller überhaupt mit 
dieser hohen Frequenz klar?

Vielen Dank!

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Hallo BMJ!

Du musst einfach die Eingänge schnell genug abfragen. Um mit einem AVR 
100kHz noch sicher handeln zu können sollte die entsprechende Routine 
aber in Assembler geschrieben werden und beim Aufruf aus einem Timer 
möglichst wenig auf dem Stack zwischengelagert werden.

Mit freundlichen Grüßen
Thorsten Ostermann

von Peter D. (peda)


Lesenswert?

ATmega2561 klingt so, als ob dieser Bolide noch vieles andere machen 
soll.
Daher würde ich nen extra ATtiny25 nehmen und per SPI oder I2C auslesen.

Es gibt zwar noch alte Encoder-ICs, aber die sind exorbitant teuer 
(Museumszuschlag).


Peter

von BMJ (Gast)


Lesenswert?

Hallo,

danke schon mal für die Antworten. Also ich möchte eigentlich keine 
zusätzlichen IC's benutzen. Ich habe von der Uni diesen fertigen 
Sensorknoten mit dem ATmega2561 bekommen und der muss dann auch nichts 
anderes mehr machen als die Daten aufzunehmen und auf dem PC in LabView 
darzustellen.
Wie groß müsste den die Abtastfrequenz sein, wenn ich das mit 
Timerinterrupts mache? (Die maximale Signalfrequenz sind doch "nur" 75 
kHz, da der Motor mit max 1500 U/min läuft) Der ATmega läuft mit etwas 
weniger als 8 MHz, ich habe da etwas bedenken, dass ich nicht mehr genug 
Rechenzyklen zur Verfügung habe, weil ich auch nur im Notfall auf 
Assembler zurückgreifen möchte. Der Drehgeber hat außerdem auch ein 
Referenzsignal bei jeder Umdrehung. Vielleicht würde es ausreichen, wenn 
ich bei jeder vollen Umdrehung eine Korrektur durchführe (Zähler auf 
Null setzen) und es doch mit den externen Interrupts mache. Wenn bei 
3000 Strichen bei einer Umdrehung ein Paar nicht erkannt werden, wäre 
das nicht so schlimm denke ich. Was meint ihr?

Viele Grüße!
BMJ

von Bob (Gast)


Lesenswert?

peter dannegger schrieb:
> Bei einer Änderung über einen Schritt, ergeben sich je nach
> Drehrichtung folgende Werte (in Klammern der 2-Bit Wert als
> Dezimalzahl):
>
> Vorwärts:
> 00 - 11 = 01 (1)
> 01 - 00 = 01 (1)
> 10 - 01 = 01 (1)
> 11 - 10 = 01 (1)
>
> Rückwärts:
> 00 - 01 = 11 (3)
> 01 - 10 = 11 (3)
> 10 - 11 = 11 (3)

Hallo, ich verstehe nicht, wie diese Tabelle zu Stande kommt. Kann mir 
das einer bitte erklären?

LG

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Die Tabelle ist meiner Meinung nach falsch. Encoder geben einen Graycode 
aus, d.h. es ändert sich pro Schritt immer nur eine der beiden 
Leitungen:

00 -> 01
01 -> 11
11 -> 10
10 -> 00

In Pfeilrichtung wäre dann vorwärts, gegen die Pfeilrichtung rückwärts. 
Bei den anderen 8 möglichen Zustandsänderungen hätten sich beide Signale 
geändert, was auf einen Fehler hindeutet (Zustandswechsel verpasst da 
Encoder zu schnell dreht oder Auswertung zu langsam ist).

Mit freundlichen Grüßen
Thorsten Ostermann

von Frank (Gast)


Lesenswert?

Hallo,

ich bin auch relativ neu auf diesem Gebiet und soll mithilfe eines 
magnetischen Drehgebers einen Schrittmotor regeln.

Soweit habe ich mich in das Programm von Herrn Dannegger eingelesen und 
vieles verstanden ;)

Was ich z.B. nicht verstehe ist die Diskussion um die Rastpunkte. Blöd 
gesagt was ist das?

Mein magnetischer Encoder bietet eine Auflösung von 1024 
Impulsen/Umdrehung und arbeitet eben mit den Kanälen A & B (& Z, aber 
das scheint ja egal zu sein). Das dieser in irgendeiner Einstellung 
"spürbar" einrastet kann ich nicht bestätigten....

Vielen Dank schon einmal!

Frank

von dreilira (Gast)


Lesenswert?

Hallo Frank,
die 'Rastpunkte' sind für die mechanischen Drehgeber. Die haben auch nur 
8-32 Flanken. Für magnetische Drehgeber spielt das Ganze keine Rolle. 
Und bei 1024 Pulsen wird wohl auch niemand von Hand an der Achse drehen 
:-)

Gruß
Ralf

von Frank (Gast)


Lesenswert?

Ach cool, danke Ralf für die schnelle Antwort!

Ich kann also blöd gesagt, einfach das (erste) Programm von Herrn 
Dannegger verwenden (http://www.mikrocontroller.net/articles/Drehgeber)?

Denn bei meinen bisherigen Versuch (lasse mir die Gesamtzahl an 
Schritten an einem angeschlossenen LCD anzeigen) habe ich folgende 2 
Probleme:

1. Ich brauch für die bisher manuelle Betätigung des Drehgebers (--> ca. 
2 Umdrehungen/s :D ) schon eine Auslesefrequenz von 100kHz was ja schon 
enorm ist

2.Ich denke es ist ein Variablenspeicherproblem: Sobald ich a) einen 
Overflow habe (Also bei ca. 32k Schritten) oder b) erst in die eine 
Richtung drehe (z.B. bis 11000) und dann in die andere bis es <10000 
Schritte sind, bleibt die letzte Ziffer "einfach" stehen, also z.B. 
99994 statt 9999... und ab dann springen die Schritte auf dem LCD 
absolut zufällig....


Erneut, vielen Dank schon einmal :)

Frank

von Tishima (Gast)


Lesenswert?

Hallo,

bei der Pulsfrequenz die dein Drehgeber liefert wirst Du wahrscheinlich 
nicht glücklich mit einer Software Lösung.
Kommt auf ein MC System an ob der das schafft.

Da wirst Du mit spez. IC's oder nem CPLD arbeiten müssen.
Von den spez. IC's fällt mir aber grade nicht mehr die Bezeichnung ein.

gruß,
Bjoern

von jonas biensack (Gast)


Lesenswert?

>2.Ich denke es ist ein Variablenspeicherproblem: Sobald ich a) einen
>Overflow habe (Also bei ca. 32k Schritten) oder b) erst in die eine
>Richtung drehe (z.B. bis 11000) und dann in die andere bis es <10000
>Schritte sind, bleibt die letzte Ziffer "einfach" stehen, also z.B.
>99994 statt 9999... und ab dann springen die Schritte auf dem LCD
>absolut zufällig....

Versuch mal den Datentyp zu erweitern, z.b. auf int32_t.

Gruß Jonas

von Peter D. (peda)


Lesenswert?

Frank schrieb:
> 1. Ich brauch für die bisher manuelle Betätigung des Drehgebers (--> ca.
> 2 Umdrehungen/s :D ) schon eine Auslesefrequenz von 100kHz was ja schon
> enorm ist

Bei 2 Umdrehungen/s reichen 5kHz.


Frank schrieb:
> 2.Ich denke es ist ein Variablenspeicherproblem: Sobald ich a) einen
> Overflow habe (Also bei ca. 32k Schritten) oder b) erst in die eine
> Richtung drehe (z.B. bis 11000) und dann in die andere bis es <10000
> Schritte sind, bleibt die letzte Ziffer "einfach" stehen, also z.B.
> 99994 statt 9999... und ab dann springen die Schritte auf dem LCD
> absolut zufällig....

Nö, ein Darstellungsproblem. Vermutlich erweiterst Du nicht mit 
Leerzeichen und alte Ziffern bleiben bei kürzeren Zahlen stehen.


Peter

von Frank (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Nö, ein Darstellungsproblem. Vermutlich erweiterst Du nicht mit
> Leerzeichen und alte Ziffern bleiben bei kürzeren Zahlen stehen.


Danke für die schnelle Antwort. Das stimmt, das macht Sinn :). Weiß zwar 
noch nicht ganz wie das zu bewerkstelligen ist, da ich bisher auf eine 
vorgefertigte Header Datei für das LCD zurückgreife aber wird schon 
irgendwie :).

Kommst du auf die 5 kHz über: 2 Umdrehungen/s *1024*2= 4100 Hz? Bei der 
Frequenz funktionierts aber leider nicht zuverlässig... Hab glaub auf 
rn-wissen mal gelesen dass es das 20-fache der Grundfrequenz sein 
soll...

Noch eine Verständnisfrage:
Soweit ich das Programm verstanden habe ist in enc_delta je nach 
Richtung entweder 10 oder 01 gespeichert oder? Warum ist es denn 
enc_delta += und nicht nur =? Denn angenommen ich würde es in der 
Abtastfrequenz wirklich schaffen 2 Impulse weiterzudrehen, also 01+01= 
10, dann interpretiert es doch der µC als 1 Schritt in die andere 
Richtung..

Wenn ich das richtig verstanden habe ist die Auswertung eines Drehgebers 
mit Interrupts die durch Flanken ausgelöst worden sind nur wegen den 
prellenden (mechanischen) Tastern ungeeignet/schlechter. Wäre es aber 
nicht für meinen magnetischen bzw. später optischen Drehgeber nicht 
sogar besser? Oder tritt auch hier Prellen auf?


Ich hoffe es ist ok dass ich soviele Fragen gestellt habe. Freu mich auf 
jeden Fall über eure Antworten. Danke!

Frank

von Falk B. (falk)


Lesenswert?

@  Frank (Gast)

>Frequenz funktionierts aber leider nicht zuverlässig... Hab glaub auf
>rn-wissen mal gelesen dass es das 20-fache der Grundfrequenz sein
>soll...

Ist hier falsch.

>Richtung entweder 10 oder 01 gespeichert oder? Warum ist es denn
>enc_delta += und nicht nur =?

Weil die Differenz (delta) addiert werden muss.

>Wenn ich das richtig verstanden habe ist die Auswertung eines Drehgebers
>mit Interrupts die durch Flanken ausgelöst worden sind nur wegen den
>prellenden (mechanischen) Tastern ungeeignet/schlechter.

u.a.

> Wäre es aber
>nicht für meinen magnetischen bzw. später optischen Drehgeber nicht
>sogar besser? Oder tritt auch hier Prellen auf?

Kann sein, muss nicht. Ist aber für dein Problem egal.

Dein Ansatz ist falsch. Für eine einfach Drehzahlmessung braucht man die 
echte Dekodierung nicht. Man nutzt einfach eine Spur, A oder B, und 
macht einen stinknormalen Frequenzzähler. Das macht der AVR mit links 
und gähnt dabei. Ein Timer zählt die Pulse am Eingang, ein zweiter 
generiert die Messzeit. Das passiert alles in Hardware. Die CPU muss nur 
ab und an die Zähler auslesen und daraus die Drehzahl berechnen.

MFG
Falk

von Frank (Gast)


Lesenswert?

Falk Brunner schrieb:
> für eine einfach Drehzahlmessung braucht man die
> echte Dekodierung nicht.

Hey danke Falk für deine Antwort.

Da habe ich mich wohl missverständlich ausgedrückt. Ich brauche im 
Endeffekt eigentlich keine Drehzahlmessung, sondern soll einen Schlitten 
der über einen Schrittmotor angetrieben wird regeln. Also eine 
Positionsbestimmung / -regelung. Deshalb benötige ich schon die Anzahl 
zurückgelegter Schritte. Welches Verfahren ist denn dann deiner Meinung 
nach am Sinnvollsten?


Viele Grüße

Frank


P.S: Warum Ist die Abtastfrequenz als 20-faches der Grundfrequenz 
falsch?

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Weil du hier kein sinusförmiges Signal hast, was noch rekonstruierbar 
sein soll, sondern ein einfaches Rechtecksignal.

Mit freundlichen Grüßen
Thorsten Ostermann

von Frank (Gast)


Lesenswert?

Ich bin es nochmal :)

Es wäre schön wenn mir jemand weiterhelfen würde und mir sagt, welches 
Verfahren (zur Debatte stehen ja wohl nur Timer und Flankeninterrupts, 
oder?) für die Auswertung eines optischen Drehgebers mit 350 Impulsen/U 
in Bezug auf Zuverlässigkeit und Belastung des µC geeigneter ist. Wie in 
einem vorigen Beitrag erwähnt handelt es sich bei der Auswertung um die 
Positionsbestimmung, ich muss also schon die Schritte mitzählen, 
insofern sollte es schon sehr genau sein.

Vielen Dank,

Grüße,

Frank

von Albert .. (albert-k)


Lesenswert?

Frank schrieb:
> rehgebers mit 350 Impulsen/U
Eine Umdrehung pro Minute/Sekunde/Millisekunde? Da musst du schon etwas 
genauer werden.

von Frank B. (hansdampf66)


Lesenswert?

Albert ... schrieb:
> Frank schrieb:
>> rehgebers mit 350 Impulsen/U
> Eine Umdrehung pro Minute/Sekunde/Millisekunde? Da musst du schon etwas
> genauer werden.


Stimmt da fehlt n halber Satz. Der Drehgeber gibt 350 Impulse / U aus, 
der Schrittmotor dreht mit max. 300U/min

von Peter D. (peda)


Lesenswert?

Die neueren AVRs haben ja nen Pin-Change-Interrupt. Da kann man diesen 
nehmen anstelle eines Timerinterrupts. Also für beide Eingänge den 
Pin-Change-Interrupt aktivieren.
Damit ist die max CPU-Last für hohe Drehzahlen geringer.


Peter

von MaWin (Gast)


Lesenswert?

Vielleicht habe ich ja was nicht mitbekommen,
aber in der Überschrift steht Drehgeber
und im Beitrag von Frank erwähnt er magnetische Drehgeber,
ich geh also mal davon aus, daß es um Drehgeber geht.

Und da empfiehlt ein Peter Dannegger auf die Frage
"zur Debatte stehen ja wohl nur Timer und Flankeninterrupts"
allen Ernstes die komplett untauglichen Flankeninterrupts,
auch nicht mit der vollkommen falschen Begründung
"Damit ist die max CPU-Last für hohe Drehzahlen geringer."
(es wäre natürlich umgeklehrt).

Wahnsinn, das kann ja wohl nicht sein, Drehgeber liest man NIE
mit Flankeninterrupts aus, das wäre als ob man Tastendrücke
per pin change Interrupt zählen wollte (egal ob es jetzt um
Inkrementposition, Drehzahl oder Positionsbestimmung geht)

Gerade ein Peter Dannegger sollte das nach seine Entprellroutine
für Tasteneingabe verstanden haben.

Zu Drehgebern ist eigentlich alles gesagt:
http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29

Auch magnetische Drehgeber prellen, elektrische Störungen im
Übergang können das bewirken.

Die Probleme (100kHz, falsche Ausgabe) sind ja schon versucht
worden zu erklären und beantworten, leider ohne Rückmeldung.

von Peter D. (peda)


Lesenswert?

Du hast schon richtig gelesen.
Der Pin-Change-Interrupt funktioniert sehr gut. Besonders, wenn einem 
Leute mit schnellem Drehen beweisen wollen, daß die Software sich 
verzählt.
Man muß also nicht ständig eine hohe Interruptlast erzeugen, sondern 
nur, wenn wirklich schnell gedreht wird.

Es gibt natürlich bei Positionsgebern an vibrierenden Maschinen die 
seltene Möglichkeit, daß eine hohe Impulszahl entsteht und die CPU 
verlangsamt (nur ein Main-Loop Befehl zwischen den Interrupts).
Aber dagegen kann man einfach in dem Pin-Change-Interrupt einen Zähler 
einbauen, der bei einem Maximalwert den Interrupt disabled und einen 
Fehler meldet. Ansonsten setzt ein Timerinterrupt diesen Zähler zyklisch 
zurück.

Auch eine Möglickeit wäre, der Pin-change-Interrupt disabled sich, setzt 
einen Timer-Compare-Interrupt auf 10µs und dieser enabled ihn wieder.
Man hat dann max 100kHz Abtastrate, aber nur bei Bedarf.


Peter

von Frank B. (hansdampf66)


Lesenswert?

Puh, jetzt bin ich leicht verwirrt. Ist also für (letztendlich) optische 
Drehgeber der Flankeninterrupt das sinnvollere?

Ich denke mal in Verbindung mit einem Zustandsvergleich durch eine Gray 
Code Tabelle oder?

Die Idee mit der Fehlermeldung bzw. dem switchen auf Timer-interrupt 
hört sich gut an (ich hoff ich schaff es gscheit zu implementieren), 
danke Peter!

Frank

von Frank B. (hansdampf66)


Lesenswert?

MaWin schrieb:
> Die Probleme (100kHz, falsche Ausgabe) sind ja schon versucht
> worden zu erklären und beantworten, leider ohne Rückmeldung.

Hab erst beim zweiten Mal erkannt, dass das an mich gerichtet war.

100 kHz sind bei mir "komischerweise" tasächlich noch notwendig und 
sogar da kommt es zu Fehlern wenn man sehr schnell mit der Hand dreht. 
Da ich aber letztendlich einen optischen Drehgeber mit 360 Impulsen/U 
verwenden werde statt den magnetischen mit 1000 Imp/U hoffe ich dass 
sich das Problem von "allein löst", ich melde mich ggf. nochmal :)

Die falsche Ausgabe lag tatsächlich am LCD und wurde von mir "behoben" 
indem ich die Werte per RS232 an den Computer ausgebe.

Möchte mir vllt noch jemand verraten ob denn nun Flanken oder doch Timer 
ISRs für meine Auswertung von optischen Drehgebern sinnvoll ist?

Grüße,

Frank

von Bjoern B. (per)


Lesenswert?

Hallo,

ich muß demnächst einen optischen Incrementalgeber (5000 Impulse pro 
Drehung) Auslesen und würde gerne die ENCODE.C variante wählen, nun muß 
ich um die Hardware anpassung vorzubehmen eine parametriebare 
Drehreichtungsumkehr mit einbauen, dazu kann ich ja entweder PHASE A mit 
PHASE B Vertauschen oder woanders ansetzen, nur sehe ich nicht genau wo 
ich das am besten im Code bewerkstellige, kann mit jemand da mal einen 
Denkanstoß geben, hab leider die Hardware noch nicht fertig um damit 
rumzuspielen, aber dieses Problem geistert mir die ganze Zeit durch den 
Kopf.

Was ich möchte das die Drehrichtung durch einen Port PIN umschaltbar 
ist, dies muß ich machen der der Incremantalgeber entweder von links 
oder von rechts ans Band geschraubt wird.

mfg,
Bjoern

von Bjoern B. (per)


Lesenswert?

Hallo,
nach dem x mal ansehen des codes, fällt mir grade etwas auf.

langt es einfach von der varibale i bit 1 zu invertieren um das zu 
erreichen was ich möchte ?

mfg,
Bjoern

von Alex (Gast)


Lesenswert?

Hallo an alle,

ich versuche schon seit Tagen den zweiten Code zu entschlüsseln. Für 
meinen optischen Impulsgeber brauche ich die Richtung. Also ob er Rechts 
oder Links herum dreht.
Kann mir vielleicht jemand erklären, wie sich die Variable enc_delta für 
die beiden Richtungen verhält? Damit kann ich dann schauen, welche 
Ausgänge am PortB freigeschaltet werden.
Momentan habe ich für einen Richtungssinn den Code : 1111 -> 1110 -> 
1101 -> 1100. Dieser Code müsste nacheinander dann am Ausgang PB0 und 
PB1 zu erkennen sein. Oder sehe ich hier irgendetwas falsch.


#include <io.h>
#include <interrupt.h>
#include <signal.h>


#define PHASE_A  (PINC & 1<<PINC0)  // PINC.0
#define PHASE_B (PINC & 1<<PINC1)  // PINC.1


volatile char  enc_delta;    // -128 ... 127


int main( void )
{
  TCCR0 = 1<<CS01;      //divide by 8 * 256
  TIMSK = 1<<TOIE0;      //enable timer interrupt

  DDRB = 0xFF;
  sei();
  for(;;)        // main loop
    PORTB = enc_delta;
}


SIGNAL (SIG_OVERFLOW0)
{
  static char enc_last = 0x01;
  char i = 0;

  if( PHASE_A )
    i = 1;

  if( PHASE_B )
    i ^= 3;        // convert gray to binary

  i -= enc_last;      // difference new - last

  if( i & 1 ){        // bit 0 = value (1)
    enc_last += i;      // store new as next last

    enc_delta += (i & 2) - 1;    // bit 1 = direction (+/-)
  }
}

von obbedaja (Gast)


Lesenswert?

Kann mir jemand erklären, wie ich aus der variable enc_delta eine 
Drehrichtungserkennung machen kann? Mich interessieren ja nur die ersten 
beiden Bits?, oder nicht?
Momentan zerbreche ich mir den Kopf darüber.

Weiterhin, möchte ich gerne wissen, wann der Drehgeber eine volle 
Umdrehung gemacht hat. Der Geber hat 500 Impulse.
Vielleicht kann ich das ja über die For Schleife in der mainloop 
realisieren? Aber irgendwie komme ich da nicht weiter....

von Bernhard M. (boregard)


Lesenswert?

obbedaja schrieb:
> Kann mir jemand erklären, wie ich aus der variable enc_delta eine
> Drehrichtungserkennung machen kann? Mich interessieren ja nur die ersten
> beiden Bits?, oder nicht?
> Momentan zerbreche ich mir den Kopf darüber.
>
> Weiterhin, möchte ich gerne wissen, wann der Drehgeber eine volle
> Umdrehung gemacht hat. Der Geber hat 500 Impulse.
> Vielleicht kann ich das ja über die For Schleife in der mainloop
> realisieren? Aber irgendwie komme ich da nicht weiter....

Die Drehrichtung erkennst Du daran, ob enc_delta positiv oder negativ 
ist. Für die volle Umdrehung must Du oft genug enc_delta in Deiner 
mainloop auslesen und aufaddieren, wenn die Summe 500 ist hat er eine 
volle Rechtsdrehung gemacht, bei -500 eine volle Linksdrehung (oder 
umgekehrt...)

von captnhanky (Gast)


Lesenswert?

wow das ist der längste thread den ich je gesehn hab

von obbedaja (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe es jetzt geschafft den Drehgeber und die Drehrichtung 
auszugeben. Weiterhin zählt mir ein Zähler die Inkremente und gibt pro 
voller Umdrehung ein digitales Signal aus.
Dies klappt perfekt bis zu einer bestimmten Drehzahl (ca. 500U/min), ab 
dieser werden plötzlich rechts und links Drehungen erkannt und ich kann 
damit nicht mehr weiter arbeiten.

Kann mir jemand sagen, ob dies am Inkrementalgeber liegt? Oder eher an 
der Abtastung mittels Timer. Ich lasse den Timer ohne Vorteiler laufen, 
denn mit Vorteiler kann ich auch die kleinen Drehzahlen nicht auswerten.

Ich freue mich auf eine Antwort.

von obbedaja (Gast)


Angehängte Dateien:

Lesenswert?

Der Code nochmals ein bisschen aufgeräumt.

von Werner (Gast)


Lesenswert?

obbedaja schrieb:
> Kann mir jemand sagen, ob dies am Inkrementalgeber liegt?

Das liegt wohl eher am Abtast-Theorem. Vermutlich verpaßt du Phasen des 
Gebers. Guck' dir auf 'nem Oszi mal deine Gebersignale und den 
Abtasttakt an.

von obbedaja (Gast)


Lesenswert?

Danke für die schnelle Antwort. Habe soeben die Spuren A und B mit einem 
Messrechner aufgenommmen, hatte kei Oszi zur Hand.

Im unteren Drehzahlbereich laufen die Rechtecksignale (mit leichter 
Rampenbildung) sehr genau und 90° verschoben. Erhöhe ich die Drehzahl, 
werden aus den Rechtecksignalen -> spitze Dreiecksignale und ca. jeder 
fünfte Strich wird noch als Rechteck erkannt.

Dabei hatte ich den Geber beim Drehen festgehalten und bemerkt, dass er 
eine leichte Unwucht aufweist. Ich hoffe, dass der Fehler daher kommt 
und meine Messergebnisse verfälscht.
Neuer Inkrementalgeber ist bestellt und werde sobald er da ist, neues 
berichten.

Aber eine allgemeine Frage zu dem ablaufenden Timer0 (8-bit) habe ich 
noch.
Ich benutze einen neuen Inkrementalgeber mit 1024 Impulsen. Meine 
Drehzahl ist 1333U/min.
Der Geber hat somit eine Frequenz von 22749Hz=23KHz.

Nach dem Abtasttheorem müsste ich mit 46KHz das Signal abtasten.

Wie kann ich meinen Timer einstellen, damit er dies auch so macht? D.h. 
evtl einen Vorteiler einbauen?

zur Info: Der Micrcontroller hat einen externen Quarz mit 3,6864MHz.

von obbedaja (Gast)



Lesenswert?

Anbei der Signalverlauf der mittleren und hohen Drehzahlen.

von Marcel (Gast)


Lesenswert?

Hallo,

bin echt beeindruckt von dieser Routine. Es funktioniert super. Wie 
würdet ihr den Taster des Inkrementalgebers mit einbinden? Auch in der 
ISR vom Timer? Wie würdet ihr den am besten Entprellen?
1
ISR (TIMER0_COMPA_vect)               // 1ms for manual movement
2
{
3
  int8_t neu;
4
  int8_t diff;
5
6
  neu = 0;
7
  
8
  if (!ENC_TASTER)                 // Taster des Inkrementalgebers                
9
  {
10
    enc_taster = 1;
11
  }
12
  
13
  if (ENC_CHA)
14
    neu = 3;
15
  
16
  if (ENC_CHB)
17
    neu ^= 1;                 // convert gray to binary
18
  
19
  diff = last - neu;                  // difference last - neu
20
  
21
  if (diff & 1)             // bit 0 = value (1)
22
  {                           
23
    last = neu;                      // store neu as next last
24
    enc_delta += (diff & 2) - 1;     // bit 1 = direction (+/-)
25
  }
26
}

von M. K. (kichi)


Lesenswert?

Marcel schrieb:
> Wie
> würdet ihr den Taster des Inkrementalgebers mit einbinden? Auch in der
> ISR vom Timer? Wie würdet ihr den am besten Entprellen?

Ich würde dafür Peters Entprellroutine benutzen und diese ebenfalls in 
der Timer-ISR aufrufen.

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.