Die eine Spur dieser Drehgeber ist etwas unpräzise. Wertet man die
Flanke der anderen Spur aus, funktioniert es sehr gut. Hier ein
funktionierendes Beispiel in AVR-Assembler:
http://www.mikrocontroller.net/attachment/43903/sinus.zip
MfG,
der mit den Sinüssen
sergey schrieb:
> Ja, er macht Doppelschritte. Geht einwandfrei mit dem Sprut-Beispielcode> auf PICs.>> http://sprut.de/electronic/pic/programm/rotary2/rotary2.html
Das der Doppelschritte macht, weiß ich.
das kann ja Dannegers Code auch handlen.
Das Mausrad, was ich vorher provisorisch genutzt hatte, hatte auch
Doppelschritte.
Sinusgeek schrieb:
> Die eine Spur dieser Drehgeber ist etwas unpräzise. Wertet man die> Flanke der anderen Spur aus, funktioniert es sehr gut. Hier ein> funktionierendes Beispiel in AVR-Assembler:> http://www.mikrocontroller.net/attachment/43903/sinus.zip>> MfG,> der mit den Sinüssen
Ich werds heut mal mit euren Codes probieren, danke.
Ich werd aus den Datenblatt aber auch nicht so richtig schlau.
Laut dem Timing-Diagramm, liegen die Rast-Postionen ja genau auf der
Flanke.
das ist doch dämlich
Es liegen hier beide Phasen auf der Flanke. Das ist noch dämlicher als
manche Typen von Alps, wo nur ein Signal auf der Flanke liegt. Man kann
es aber den Dingern von Alps auch vorher nicht ansehen, ob es so ist.
Ich nehme nur welche von Hopt schuler DDM 427 zB, die nerven mit sowas
nicht rum. Gibt es bei C und R,kosten aber mehr als aus der
Grabbelkiste.
Von Xilinx gibt es eine exakte Handlungsanweisung zur Auswertung eines
Drehencoders. So geht's und nicht anders.
Wer das Prinzip verstanden hat, kann damit den VHDL-Code genauso
erstellen wie C oder Assembler.
Also dass die Rastungen auf der Flanke liegen, kann ich nicht
bestätigen. Mir kommt es vor, als ob eine Spur (immer dieselbe) einen
Wackelkontakt hat, also zusätzliche Flanken erzeugt.
Wenn man dafür sorgt, dass die wacklige Spur nicht auf Flanke, sondern
nur auf Zustand geprüft wird, dann arbeitet der Drehgeber sehr sauber.
Ich habe ihn in mehreren verschiedenen Projekten eingesetzt und bin sehr
zufrieden damit.
MfG
>Von Xilinx gibt es eine exakte Handlungsanweisung zur Auswertung eines>Drehencoders.
der Xylinx-ansatz basiert ja quasi auf intertupts, die würd ich gern
vermeiden.
>So geht's und nicht anders.
Schon klar, die die es bisher anders gemacht haben, haben gezaubert.
Lothar Miller schrieb:
>> Die eine Spur dieser Drehgeber ist etwas unpräzise.> Konkret sieht das so aus:>
1
> A --------_________---------_________--------________
2
> B _--------_________---------_________--------________
3
> Raste # # # # # #
4
>
> Es sind also pro Rastung zwei Schritte.
Laut datenblatt sieht es aber anders aus
1
A ---|_________|---------|_________|-------
2
B --------|_________|---------|_________|--
3
# # #
der 1. ist auf der Flanke, der 2. leicht dahinter
Ich hab das Problem, dass er in die eine Richtung immer eins vor und
direkt wieder zurück springt und in die andere Richtung gar nichts
macht.
(verwendeter Code
http://www.mikrocontroller.net/articles/Drehgeber#Beispielcode_in_C)
> Richtig schön wäre so was:>> A --------___________---------__________--------> B ____----------_________----------_________----> Raste # # # # # # # #>
Das wärd as optimum, da könnte man die Abtastfrequenz auch ordentlich
runterschrauben, da man keine kurzen Zwischenschritte erfassen müsste.
Mir ist sowiso unklar, warum man das mit den 2 schritten macht.
>>>> Von Xilinx gibt es eine exakte Handlungsanweisung zur Auswertung eines>> Drehencoders. So geht's und nicht anders.> Doch, anders gehts auch ;-)
Vlad Tepesch schrieb:
> Laut datenblatt sieht es aber anders aus>
1
> A ---|_________|---------|_________|-------
2
> B --------|_________|---------|_________|--
3
> # # #
4
>
der 1. ist auf der Flanke, der 2. leicht dahinter
Das Datenblatt passt nicht ganz zu dem verkauften Drehgeben, alleine
schon die Anzahl an Rastpunkten ist unterschiedlich. Vermutlich handelt
es sich da um irgendwas leicht kundenspezifisches.
Das Hauptproblem an dem Drehgeber ist, dass es wirklich so aussieht wie
Lothar es gezeichnet hat: Die Phasenverschiebung zwischen den beiden
Signalen ist deutlich kleiner als 90°, daher muss die Samplerate mit der
man das ganze abtastet recht hoch sein, sonst kommt es zu obigem
Ergebnis, dass das ganze nur in einer Richtung funktioniert.
> Wertet man die Flanke der anderen Spur aus
Bitte bitte nicht so doof sein und versuchen, Flanken auszuwerten.
> verwendeter Code http://www.mikrocontroller.net/articles/Drehgeber
Der ist in Ordnung, aber recht uneffektiv geschrieben, vielleicht führst
du ihn zu langsam aus. Effektiver wäre es so:
int table[4][4]={{0,1,-1,0},{-1,0,0,1},{1,0,0,-1},{0,-1,1,0}};
int position=0; // zaehlen wir mal die absolute Position
volatile int quadrature_input; // bit 0 und bit 1 sind
Quadratureingaenge
int new_quadrature_value, last_quadrature_value=quadrature_input;
Folgenden Code ausreichend oft wiederholen (in der Programm Hauptscheife
oder einer Zeitgeber gesteuerten Interrupt Routine):
new_quadrature_value=quadrature_input;
position+=table[last_quadrature_value][new_quadrature_value];
last_quadrature_value=new_quadrature_value;
Vlad Tepesch schrieb:
>>Von Xilinx gibt es eine Anweisung zur Auswertung eines Drehencoders.> der Xylinx-ansatz basiert ja quasi auf intertupts
Nein, das ist eine State-Machine. Die hat nichts mit Interrupts zu tun.
Der Drehgeber-Code von Peter Dannegger ist auch eine State-Machine.
Die beiden Lösungen gehen also in die selbe Richtung.
> Effektiver wäre es so: ...
Das kommt darauf an, was der Compiler daraus macht. Hast du dir den
eigentlichen Timer-Interrupt aus
http://www.mikrocontroller.net/articles/Drehgeber mal angeschaut? Die
Tabellenberechungen in deinem Code dürften länger dauern als die
logischen Verknüpfungen...
Lothar Miller schrieb:
> Vlad Tepesch schrieb:>>>Von Xilinx gibt es eine Anweisung zur Auswertung eines Drehencoders.>> der Xylinx-ansatz basiert ja quasi auf intertupts> Nein, das ist eine State-Machine. Die hat nichts mit Interrupts zu tun.> Der Drehgeber-Code von Peter Dannegger ist auch eine State-Machine.>> Die beiden Lösungen gehen also in die selbe Richtung.
soweit ich das verstanden habe, soll doch die erste Flanke ein FF
triggern, das erst duch die Flanke auf dem anderen zurückgestzt werden
kann.
die umsezzung wär demzufolge auf nem µC ein Interupt.
>>> Effektiver wäre es so: ...> Das kommt darauf an, was der Compiler daraus macht. Hast du dir den> eigentlichen Timer-Interrupt aus> http://www.mikrocontroller.net/articles/Drehgeber mal angeschaut? Die> Tabellenberechungen in deinem Code dürften länger dauern als die> logischen Verknüpfungen...
Ich fand auch nciht, dass der Ineffzient geschrieben wäre.
Meine eigene Lösung vorher war zwar etwas kleiner, aber auch direkter in
meinen Code eingebettet und speiziell darauf ausgelegt nur mitzubekommen
in welche richtung gedreht wurde, ohne mitzuzählen.
Da meine Lösung mit diesem Drehgeber aber nich funktioniert hat (wie
gesagt, bei meinem Mausrad gings), hab ichs mit Peters Code ausprobiert.
wenn mein Kleiner Mittagschlaf macht, schau probier ichs erst mal mit
ner höheren Abtastrate und dann mit Sinusgeeks Code.
MaWin schrieb:
>> verwendeter Code http://www.mikrocontroller.net/articles/Drehgeber>> Der ist in Ordnung, aber recht uneffektiv geschrieben,
Das träumst Du aber.
Wenn Du "int" nimmst, wo "unsigned char" ausreicht, ist Dein Code
schonmal extrem größer.
Und für einen Feldzugriff muß der Interrupt ja erstmal ein
Pointerregister freischaufeln und laden, das ist auch teuer.
Schau mal ins Assemblerlisting, Dein Code dürfte mindestens 4-mal größer
als meiner sein.
> vielleicht führst> du ihn zu langsam aus.
Daran dürfte es liegen. Probier mal 100µs statt der 1ms.
Was natürlich pures Gift ist, wenn man an den Eingängen noch
Kondensatoren hat, die hebeln das Entprellen der Software komplett aus
und dann gehts auf keinen Fall.
Wenn die Flanken zu dicht hintereinander kommen, könnten auch die
internen Pullups zu hochohmig sein, probier mal externe 4,7k.
Peter
Ich habe ebenfalls die Pollin Drehencoder in größerer Stückzahl verbaut,
es stimmt, die machen mit vielen Codes einige Probleme. Aber PeDa's Code
funktioniert einwandfrei (wobei ich auch mit dem erst einige Probleme
hatte)
Wie folgt setze ich ihn erfolgreich ein, aufgerufen jede ms:
1
/* rotary encoder on PB 0 1 2 6 low nibble */
2
KEY_PORT=0xFF;/* KEY PORT is always input; enable pullups */
3
SW_PORT=0x00;
4
5
6
uint8_tnew_state;
7
uint8_tindex_full;
8
9
for(temp=0;temp<=3;temp++)// 4 "ports"
10
{
11
12
SW_DDR=(1<<(temp));/* SW_PORT is always zero; make one output */
13
14
for(temp2=0;temp2<=3;temp2++)
15
{
16
index_full=4*temp;
17
index_full+=temp2;
18
temp3=((1<<(2*temp2))|(1<<(2*temp2+1)));
19
new_state=KEY_PIN&temp3;
20
if((new_state^last_cnt[index_full])==temp3)/* difference in bits */
Der Code ist eigentlich noch nicht so alt aber nicht wirklich durchdacht
(viel zu langer Interrupt). Das Prinzip funktioniert allerdings, man
kann mit der Hand so schnell drehen wie man möchte (Hab das ausprobiert
indem ich den Encoder so schnell wie's geht etwa 180° rumgerissen hab,
dabei ist kein Schritt verloren gegangen). Kann auch sein, dass der Code
jetzt ne leichte Abwandlung von PeDa's ist, aber den hab ich so in etwa
auch irgendwo hier ausm Board.
Matthias
Die Encoder-Routine von peda aus
http://www.mikrocontroller.net/articles/Drehgeber ist hocheffizient,
wenn man mittels Drehencoder lediglich den Encoderwert (Drehwinkel)
bestimmen möchte. Ein Fehler bspw. durch Drehung um erst eine halbe
Rastung vorwärts und anschließend wieder rückwärts, wird sofort
korrigiert durch die Addition und anschließende Subraktion des
Inkrementalwertes.
Der TS möchte jedoch auch die Zählflanken auswerten, sprich, ob sich der
Encoderwert erhöht oder vermindert hat. Genau hier ist die Routine von
peda nicht geeignet, da der verwendete Encoder mehr Zustandswechsel als
Rastungen hat. Dann müssen nämlich drei Pin-Status berücksichtigt
werden, peda wertet nur den aktuellen und den vorherigen aus.
Beispiel:
Eine Drehung am Encoder nur bis kurz vor Einrasten der nächsten Stellung
und Zurückdrehen in die Ausgangsrastung würde zunächst zu einem
positiven Zählimpuls und anschließend zu einem negativen Zählimpuls
führen, da ja auch die Encodervariable inkrementiert und anschließend
dekrementiert wurde.
Tatsächlich wurde aber überhaupt keine gültige Weiterrastung ausgeführt,
da ja bereits vor Einrasten des Drehgebers zurückgedreht wurde. Es darf
also weder der Encoderwert verändert werden noch dürfen Zählimpulse
generiert werden. Und dazu bedarf es der Berücksichtigung von drei
Encoderzuständen.
MFG
screwdriver
Häh, wo hast du denn das rausgelesen?
Ich möchte nur wissen, ob seit der letzten Abfrage nach rechts oder
links gedreht wurde, wie weit ist Bonus, den ich nicht unbedingt
bräuchte.
was in solchen extremfällen passiert, wie kurz vor rastung drehen und
dann zurückfallen lassen, ist mir egal.
Ich hab aber grad ein anderes Problem, weswegen ich es doch noch nicht
testen konnte.
vlad_tepesch schrieb:
>Häh, wo hast du denn das rausgelesen?
Weibliche Intuition! - Außerdem hast du weiter oben gepostet:
>Meine eigene Lösung vorher war zwar etwas kleiner, aber auch direkter in>meinen Code eingebettet und speiziell darauf ausgelegt nur mitzubekommen>in welche richtung gedreht wurde, ohne mitzuzählen.
Die Aussagen...
screwdriver schrieb:
>Der TS möchte jedoch auch die Zählflanken auswerten, sprich, ob sich der>Encoderwert erhöht oder vermindert hat.
...und ...
vlad_tepesch schrieb:
>Ich möchte nur wissen, ob seit der letzten Abfrage nach rechts oder>links gedreht wurde, wie weit ist Bonus, den ich nicht unbedingt>bräuchte.
...hören sich für mich einigermaßen gleich an.
vald_tepesch schrieb:
>was in solchen extremfällen passiert, wie kurz vor rastung drehen und>dann zurückfallen lassen, ist mir egal.
Gerade bei einem Drehencoder, der mechanisch unsymmetrisch ist, ist das
alles andere als ein Extremfall sondern Alltag und meiner Meinung auch
eine Ursache deiner Schwierigkeit den Encoder vernünftig auszuwerten.
screwdriver
screwdriver schrieb:
> Genau hier ist die Routine von> peda nicht geeignet, da der verwendete Encoder mehr Zustandswechsel als> Rastungen hat.
Nö, das klappt schon.
Deshalb gibt es ja 3 Ausgaberoutinen, je nachdem, ob der Encoder ohne
Rastung oder mit Rastung alle 2 Schritte oder alle 4 Schritte ist.
Ich hab es auch mit allen 3 Typen getestet.
Den Interrupt interessiert das aber nicht, der ist immer gleich.
Peter
@peda
Ich programmiere meine Hobbyanwendungen in einer Programmmiersprache,
deren Namen ich in diesem Forum lieber nicht aussprechen möchte.
Deshalb habe ich anderenorts meine Lösung, speziell zu dem o.g.
Drehencoder von Pollin, vorgestellt:
http://www.roboternetz.de/phpBB2/viewtopic.php?t=48413&start=0
Desweiteren habe ich mir inzwischen die im Anhang befindlichen Dateien
im Netz zusammengeklaubt und mir aus deiner Encoderroutine das
Testprogramm encoder.c zusammengezimmert und auf meine Hardware
programmiert.
Beide Versionen laufen sehr gut. Der Unterschied zwischen meiner und
deiner Version ist jedoch wie ich bereits sagte, das bei dir
Zwischenschritte beim Drehen bis vor eine Rastung und wieder zurück
mitgezählt werden und bei mir nicht. Ob das eine Rolle spielt, ist wohl
von der Anwendung abhängig. Da ich jedoch die Zählimpulse zur
Menusteuerung verwende, dürfen halbe Schritte nicht registriert werden.
MFG
screwdriver
Verzeihung, aber im letzten Anhang war eine unbrauchbare encoder.c. Hier
ist eine Version, die sich auch kompilieren lässt und mit der ich meinen
im Roboternetz dargestellten Code verglichen habe.
Ich möchte noch was zu dem Vergleich sagen:
Den Encoder-Pins habe ich jeweils so angeschlossen, weil nur noch mein
TWI-Port frei ist.
Vcc
|
-
10K | |
- 100R
| __
PC0 --------|__|-- Ph_A
bzw. PC1 bzw. Ph_B
Ich habe eben noch mal mit dem C-Code von peda an dem o.g.
Billigst-Encoder von Pollin rumgespielt. Selbst dieser "schwierige"
Encoder läuft absolut fehlerfrei. Ich muß mich schon sehr, sehr
anstrengen um Schrittverluste zu erzielen.
Fazit:
An diesem Code kommt kein C-Programmierer vorbei. Alles Rumgebastle
macht den Code nur kaputt. Wenn eure Encoderauswertung nicht läuft,
sucht woanders nach Fehlern oder Verbesserungsmöglichkeiten, aber lasst
diesen Code in Ruhe - er ist perfekt!
screwdriver schrieb:
> aber lasst diesen Code in Ruhe - er ist perfekt!
Nö, da ist keine dynamische Beschleunigung drin.
Wenn die noch drin wäre, dann wäre er perfekt...
lol,
noch besser wär, wenn er auf gedanken reagieren würde.
back to topic:
ich hab jetzt die Abtastfrequenz erhöht und noch mal außerhalb meines
Boards auf dem Steckbrett getestet. Dort funktionierts.
folgender Plot ergibt sich (anhang).
Die Flanken sind sehr nah beieinander (die zeiten sind millisek).
Abtastrate 0,5-1ms sollte aber trotzdem noch reichen.
Ein recorden in meiner Schaltung hat ergeben, dass eine Phase immer auf
GND steht. da scheint der Encoder defekt zu sein. - hmpff
hab ihn ausgelötet und getauscht, um sicher zu gehen, dass es nicht an
der Verkabelung liegt und siehe da, jetzt gehts.
> internen Pullups zu hochohmig sein, probier mal externe 4,7k.
genau dises problem hatte ich mit den encodern von POLLIN.
immer gerätzelt warum sich die Pullups nicht aktivierten. rrrrr
mit 3k3, gings dann. ;-)))