Hallo,
ich versuche den Drehregler ans Laufen zu kriegen. Anfänger Level!
Benutzt wird ein STM32F103 Mikrocontroller. Ich habe mir bereits den
Code von Peter D. angeguckt leider konnte ich ihn nicht nachvollziehen.
Es ist verwirrend, wo die Funktionen reingeschrieben worden.
Ich habe es erst selber versucht den Drehregler ans Laufen zu kriegen
mit 2 Timer und 2 Interrupts aber das ganze funktioniert nicht perfekt
manchmal werden Impulse Doppelt und manchmal gar nicht erkannt.
Vielleicht hat jemand mit STM Erfahrung gehabt.
AA schrieb:> STM32F103
Soweit mir bekannt, hat der STM32F103 (Alle STM32F103 ?) einen (oder
mehrere?) Timer(Hardwaredecoder), welcher direkt mit einem solchen
Drehencoder umgehen kann.
Den Code von Peter wirst du also gar nicht brauchen.
Arduino Fanboy D. schrieb:> Den Code von Peter wirst du also gar nicht brauchen.
Wobei man sagen muss, das der evtl. vorhandene Quadraturdekoder (so
heisst das Ding) nicht ganz einfach zu initialisieren ist. Ich habe
jedenfalls dann doch PeDas Code implementiert, der ja lediglich einen
1ms Timerinterrupt voraussetzt.
AA schrieb:> Benutzt wird ein STM32F103 Mikrocontroller. Ich habe mir bereits den> Code von Peter D. angeguckt leider konnte ich ihn nicht nachvollziehen.
Eigentlich ist es nicht so schlimm:
1. Timer auf 1ms mit Interrupt initialisieren. Das ist beim STM32 mit
Prescaler und Periodendauer nicht so schwer hinzukriegen, obwohl man
evtl. gleich uin32_t statt uint8_t für die Zwischen- und
Ergebnisvariablen verwenden könnte.
2. In der Hauptschleife nur eine der drei Ergebnisabfragen verwenden,
also nur 'encode_read1' oder nur 'encode_read2','encode_read4' etc.
verwenden. Welche am günstigsten ist, hängt vom Drehgeber ab.
Beim STM32 ist es günstig, mit den Bitmustervorgaben der Libraries zu
arbeiten. Also z.B.
1
#define PHASE_A GPIO_Pin_12
2
#define PHASE_B GPIO_Pin_13
3
4
#define ENCODER_GPIO_PORT GPIOD
da ja beim STM32 Bitposition und Portpin nicht 1:1 liegen.
Ja ich denke mir ist nicht klar, wo ich den Code reinschreiben soll.
Ich habe jetzt TIM1 auf 1 ms eingestellt
Prescaler auf 7200 somit habe ich 10kHz und Period auf 65525. Jetzt
zählt er nur 10 Schritte = 1mS
Jetzt habe ich in der Interrupt Service Routines folgendes einen
Interrupt und ein Timer. Ich müsste dann jetzt seine "void t0_interrupt"
Funktion in EXTI1 und "gray_width get_gray_delta" Funktion in TIM1
schreiben richtig?
Aber dennoch ich sehe nicht das Gesamtbild, habe den Code von Peter
nicht zu 100% verstanden.
AA schrieb:> ich versuche den Drehregler ans Laufen zu kriegen.
Gib es nur einen Typ davon? Wie regelt er die Drehung?
Das sollte doch zuerst geklärt werden.
AA schrieb:> Aber dennoch ich sehe nicht das Gesamtbild, habe den Code von Peter> nicht zu 100% verstanden.
Wenn du so einen einfachen Drehgeber nicht zu verstehen in der Lage
bist, warum wagst du dich dann an so ein Projekt? Versuche zu allererst,
die Funktion dieser Dinger zu verstehen, dann ergibt sich alles Weitere
wie von selbst!
Die allermeisten heutigen Drehgeber funktionieren so, daß sie 2 Kontakte
besitzen, die mit einem Winkel-Versatz öffnen und schließen.
Also etwa so:
1. k1 geht auf
2. k2 geht auf
3. k1 geht zu
4. k2 geht zu
dann wiederholt sich das Spiel 1..4 in der gleichen Reihenfolge. Wenn
man anders herum dreht, dann geht es ganz genau so, bloß in umgekehrter
Reihenfolge.
Bei den meisten Drehgebern gibt es auch eine Raststellung, die ganz
häufig mit einem oder mit zweien der Ereignis-Punkte 1 bis 4
zusammenfällt.
Also etwa so:
1. k1 geht auf und Rastpunkt A
2. k2 geht auf
3. k1 geht zu und Rastpunkt B
4. k2 geht zu
Wenn du also einen rastenden DG hast, dann mußt du das Ereignis
herausfinden, wo k2 auf oder zu geht und zu diesem Zeitpunkt
feststellen, welchen Zustand k1 gerade hat. Aus dem Ereignis "k2 hat
sich geändert" folgt das controllerinterne Ereignis, daß jemand dran
gedreht hat. Aus dem Zustand von k1 hingegen erkennst du, ob der
vorwärts oder rückwärts gedreht hat.
Ist doch EASY, sowas!
Nun kannst du dir überlegen, ob du den ganzen Mist pollen willst, oder
ob du das durch einen Interrupt auf beide Flanken von k2 erfassen
willst.
Der Interrupt ist die weitaus elegantere Variante, setzt aber voraus,
daß du das Signal zuvor analog entprellst. Dafür braucht's nen 22nF
Kondensator und fertig. Obendrein ist diese Variante weniger
ressourcenfressend.
Hier gibt's jedoch eine Riege militanter Verfechter des Pollings. Kann
man auch machen, aber dann muß man eben softwaremäßig entprellen, was
den Programm-Overhead erhöht. Den beiden Kontakten nen Kondensator zu
spendieren ist wesentlich einfacher.
W.S.
AA schrieb:> void EXTI1_IRQHandler(void)
Den EXTI Handler brauchst du, wenn du die von W.S. beschriebene Methode
benutzt, bei dem der Drehgeber selber einen IRQ auslöst.
Bei der PeDa Methode wird er nicht benötigt. Hier ist
AA schrieb:> void TIM1_UP_IRQHandler(void)
die richtige ISR.
AA schrieb:> seine "void t0_interrupt"> Funktion in EXTI1 und "gray_width get_gray_delta" Funktion in TIM1> schreiben richtig?
Ich bin mir nicht klar, von welchen Routinen du redest. Ich beziehe mich
immer auf die 'Solide Lösung' von hier:
https://www.mikrocontroller.net/articles/Drehgeber#Solide_L.C3.B6sung:_Beispielcode_in_C
Ausserdem nicht vergessen, den NVIC auf die Interrupts zu programmieren,
sonst passiert nix.
W.S. schrieb:> Hier gibt's jedoch eine Riege militanter Verfechter des Pollings. Kann> man auch machen, aber dann muß man eben softwaremäßig entprellen, was
Nicht ganz richtig. Beim Polling muß man gar nicht Entprellen, weil das
Prellen eben durchs Zeitraster fällt. Hab ich jedenfalls nie gebraucht.
batman schrieb:> Nicht ganz richtig. Beim Polling muß man gar nicht Entprellen, weil das> Prellen eben durchs Zeitraster fällt. Hab ich jedenfalls nie gebraucht.
Bei einer Abtastrate von ~1kHz korrigiert sich das von selbst, weil eine
Schalterstellung immer mehrfach abgefragt wird, bevor zur nächsten
geschaltet wird. Dank des Gray-Codes springt das beim Prellen nur
zwischen einem Schritt hin und her (+/-).
Falls beim schnellen kurbeln mal ein Schritt verlorengeht, merkt das
eh keiner. Der Einsatz von Pin-Change-INTs ist völlig unnötig und bringt
nur zusätzliche Probleme.
[Nachtrag]
Bzw. bei Einsatz von INTs ist dann wirklich eine aktive Entprellung
notwendig. Was heißt den INT sperren bis das Prellen vorbei ist....
Matthias S. schrieb:> Eigentlich ist es nicht so schlimm:> 1. Timer auf 1ms mit Interrupt initialisieren. Das ist beim STM32 mit> Prescaler und Periodendauer nicht so schwer hinzukriegen, obwohl man> evtl. gleich uin32_t statt uint8_t für die Zwischen- und> Ergebnisvariablen verwenden könnte.
Oder noch simpler den viel einfacher zu konfigurierenden Systick nutzen.
Vermutlich wird der eh schon für andere Zwecke gebraucht.
Hat den weiteren Vorteil, dass die Routine dann auch auf allen Cortex-M
Controllern läuft.
Doctor Snuggles schrieb:> Oder noch simpler den viel einfacher zu konfigurierenden Systick nutzen.
Klar, geht natürlich auch.
Ob man Polling oder IRQ Methode benutzt, sei jedem selber überlassen.
Ich habe mit Polling auch bei übelsten Drehgebern gute Erfahrungen
gemacht und habe sowieso immer irgendwelche Timer über bei den STM32.
Auf AVR nutze ich den Timer dann sowohl für den Encoder als auch für
etwaige Tasterroutinen, Multiplexing oder Uhrenkram gleichzeitig.
batman schrieb:> Beim Polling muß man gar nicht Entprellen, weil das> Prellen eben durchs Zeitraster fällt.
Wenn das nicht so unsäglich falsch wäre, könnte man sich vor Lachen ..
ROTFL
Nein, beim Polling muß man auch entprellen, entweder wieder mal analog
mit nem simplen C oder durch mehrfaches Abfragen und
"Mehrheits-Entscheidung".
Obendrein muß man beim Polling das per Software nachbilden, was die
Hardware - nämlich das Erkennen des Flanken-Wechsel Ereignisses - einem
sonst an Arbeit abnimmt.
W.S.
batman schrieb:> Beim Polling muß man gar nicht Entprellen, weil das> Prellen eben durchs Zeitraster fällt.
Zumindest PeDas Routine kann man unter 'ich frage zweimal und dann ist
es wahr' zusammenfassen. Beim ersten Durchlauf mit geänderten
Phasenzuständen wird erstmal ein Bit gekippt. Ist beim nächsten
Durchlauf die Zustand immer noch so, wird das übernommen und als gültig
erklärt.
Es kann also schon mal prellen, rutscht aber beim nächsten Durchlauf
durch den Test.
W.S. schrieb:> batman schrieb:>> Beim Polling muß man gar nicht Entprellen, weil das>> Prellen eben durchs Zeitraster fällt.>> Wenn das nicht so unsäglich falsch wäre,
Das ist bei einem Drehgeber etwas anders, als bei einem Taster mit nur
einem Kontakt -> Gray-Code.
Das entprellt sich da wirklich von selbst, da du dir den alten Zustand
ja eh merken musst und wesentlich schneller pollst. Das muss man halt
bei einem Taster extra zum Endprellen programmieren.
In SW Endprellen heißt doch nur 'Oh da war doch was, sehen wir etwas
später noch mal nach, ob da wirklich was is....'
Bei solch immensen Aufwand, könnte man schon auf die Idee kommen, daß
das zeitgesteuerte Abfragen bereits das komplette entprellen darstellt.
:)
Wo hat das was mit einer "Mehrheits-Entscheidung" zu tun? Die (pollende)
EA-Methode, die ich kenne, übernimmt den ersten gültigen
Zustandswechsel. Nagut, mag es auch andere Varianten geben.
batman schrieb:> Wo hat das was mit einer "Mehrheits-Entscheidung" zu tun? Die (pollende)> EA-Methode, die ich kenne, übernimmt den ersten gültigen> Zustandswechsel.
Tust du doch automatisch!
Oder wertest du die Drehgeber Ereignisse so schnell aus wie sie
auftreten können (1kHz -> 500Hz bei 28âTurn -> ~1000RPM!), bzw. änderst
du Einstellungen im Programm?
Du Oversampelst den Drehgeber sowieso und dank des Gray-Codes summieren
sich die Fehler durchs Prellen nicht auf.
Teo D. schrieb:> Oder wertest du die Drehgeber Ereignisse so schnell aus wie sie> auftreten können
Ja wieso nicht, worauf willst du denn warten. Man muß jeden
Zustandswechsel doch nur einmal erkennen. Nichtsdestowenigertrotz kann
der schon im nächsten Intervall wieder rückgängig gemacht werden, ob
durch Kippeln (auf dem Rastpunkt), Prellen oder schlicht Zurückdrehen
ist ja im Prinzip gleich.
Teo D. schrieb:> Das entprellt sich da wirklich von selbst,..
eben nicht. Du hast ja Recht mit der Annahme, daß sich das nach einigem
Prellen von selbst auf den richtigen Zustand einspielt (vorausgesetzt,
dein Polling ist schnell genug, um alle Prell-Zustände korrekt zu
erfassen), aber bedenke mal, was quasi hintendran losgeht.
Nimm mal an, dein DG prellt dreimal, also dabei stellst du fest:
vor-rück-vor-rück-vor-rück-vor und jetzt stabil.
Willst du jetzt z.B. im angezeigten Menü auf dem kompliziert und langsam
anzusteuernden grafischen Display insgesamt 7 mal binnen einiger zehn
Millisekunden sämtlichen Schmonzes neu zeichnen?
Wohl eher nicht. Also mußt du entweder zuvor analog entprellen um nur 1
Ereignis "vor" zu kriegen - oder du mußt nach all dem gepollten
vor-zurück-vor Krempel das Ganze softwaremäßig entprellen, um dir die 7
Zustandswechsel zu ersparen.
Ist das jetzt ein bissel klarer geworden?
W.S.
W.S. schrieb:> Willst du jetzt z.B. im angezeigten Menü auf dem kompliziert und langsam> anzusteuernden grafischen Display insgesamt 7 mal binnen einiger zehn> Millisekunden sämtlichen Schmonzes neu zeichnen?Teo D. schrieb:> Oder wertest du die Drehgeber Ereignisse so schnell aus wie sie> auftreten
Das meinte ich damit.
In der IRQ wird ein Var aufsummiert und alle xx-ms dieser Wert im
Programm aktualisiert und die Var auf 0 gesetzt. So Prellt nichts und
verloren geht auch nichts.
Wie meist bei dem Thema, reden wir nur ein wenig aneinander vorbei...
ich konnte nur feststellen der Peter D Code war einfach zu nutzen, ich
musste nur die 3 möglichen Subroutinen durchprobieren bis es passte!
int8_t encode_read1( void ) // read single step encoders
int8_t encode_read2( void ) // read two step encoders
int8_t encode_read4( void ) // read four step encoders
bei meinem Drehecoder war es encode_read4( void )!
ISR mit 1ms
W.S. schrieb:> Teo D. schrieb:>> Das entprellt sich da wirklich von selbst,..>> eben nicht. Du hast ja Recht mit der Annahme, daß sich das nach einigem> Prellen von selbst auf den richtigen Zustand einspielt (vorausgesetzt,> dein Polling ist schnell genug, um alle Prell-Zustände korrekt zu> erfassen), aber bedenke mal, was quasi hintendran losgeht.>
Falsch, man braucht eben nicht jeden Prell-Zustand erfassen. Dafür
reichen die üblichen Tastraten auch nicht => kann irgendwie schon nicht
sein. Der Trick ist hier grob, daß verpaßte Wechsel zu ungültigen Folgen
führen, die nicht gezählt werden.
> Nimm mal an, dein DG prellt dreimal, also dabei stellst du fest:> vor-rück-vor-rück-vor-rück-vor und jetzt stabil.>> Willst du jetzt z.B. im angezeigten Menü auf dem kompliziert und langsam> anzusteuernden grafischen Display insgesamt 7 mal binnen einiger zehn> Millisekunden sämtlichen Schmonzes neu zeichnen?>> Wohl eher nicht. Also mußt du entweder zuvor analog entprellen um nur 1> Ereignis "vor" zu kriegen - oder du mußt nach all dem gepollten> vor-zurück-vor Krempel das Ganze softwaremäßig entprellen, um dir die 7> Zustandswechsel zu ersparen.>
Falsch, dafür gibts die 2-4 Phasen Abstand zwischen den Rastpunkten.
Erst wenn der Phasenzyklus korrekt durchgelaufen ist, triggert man eine
Reaktion im Hauptprogramm. Prellen bleibt i.d.R. in Phase 1 hängen, weil
nur 1 Bit sich ändert.
Ohje, die Grundlagen..
Ich hatte mir den Peter-D-Code ausgedruckt und durchgearbeitet, als
meine Frau mit ihren Freundinnen im Wald Pilze suchte.
Alles sehr logisch und nachvollziehbar, ohne das hard-/soft-Entprellen,
ohne Polling, ohne INT vom DG ausgelöst???, das Prinzip muss man
verstehen...
Ich habe das dann (ohne Abzugucken) auf mein PIC in ASM umgesetzt, läuft
sehr gut - muss ja. Man muss es verstehen! initialisieren, ISR,
Verwendung im HP, beim Lesen der Variablen im HP die ISRs sperren. Ich
habe dann gleich noch die Drehgeschwindigkeit dynamisiert.
mfG fE_wob
batman schrieb:> dafür gibts die 2-4 Phasen Abstand zwischen den Rastpunkten.> Erst wenn der Phasenzyklus korrekt durchgelaufen ist, triggert man eine> Reaktion im Hauptprogramm. Prellen bleibt i.d.R. in Phase 1 hängen, weil> nur 1 Bit sich ändert.
so isses.
W.S. schrieb:> Annahme, daß sich das nach einigem> Prellen von selbst auf den richtigen Zustand einspielt (vorausgesetzt,> dein Polling ist schnell genug, um alle Prell-Zustände korrekt zu> erfassen), aber bedenke mal, was quasi hintendran losgeht.>> Nimm mal an, dein DG prellt dreimal, also dabei stellst du fest:> vor-rück-vor-rück-vor-rück-vor und jetzt stabil.>> Willst du jetzt z.B. im angezeigten Menü auf dem kompliziert und langsam> anzusteuernden grafischen Display insgesamt 7 mal binnen einiger zehn> Millisekunden sämtlichen Schmonzes neu zeichnen?
Selbstverständlich nicht.
Betrachte bitte die tatsächliche mechanisch erreichbare Auflösung (aka
Drehwinkel) mal als Zyklus im Greycode. Und erst nach einem Zyklus wird
die Richtung erkannt+auegewertet, und erst dann als Winkeländerung
weitergereicht. (von mir aus nenne das "halbe Auflösung" aka "gröbere
Winkel" und nenne deine bisherige Methode "oversampling").
Da(nn) prellt lange nix mehr; an dem Punkt (in dem Winkel) ist ja sogar
schon der nächste Kontakt geschaltet (und der kann prellen wie er will)
und damit die Position erkannt.
HTH
P.S.
W.S. schrieb:> Hier gibt's jedoch eine Riege militanter Verfechter des Pollings
LOL der war gut. Yodaspeech: Ertappt du mich hast :D