Forum: Mikrocontroller und Digitale Elektronik Drehregler Peter D Code


von AA (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

: Bearbeitet durch User
von AA (Gast)


Lesenswert?

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

1
static void MX_TIM1_Init(void)
2
{
3
  TIM_ClockConfigTypeDef sClockSourceConfig;
4
  TIM_MasterConfigTypeDef sMasterConfig;
5
 
6
  htim1.Instance = TIM1;
7
  htim1.Init.Prescaler = 7200;
8
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
9
  htim1.Init.Period = 65525;
10
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
11
  htim1.Init.RepetitionCounter = 0;
12
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
13
}

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.
1
void EXTI1_IRQHandler(void)
2
{
3
4
}
und
1
void TIM1_UP_IRQHandler(void)
2
{
3
4
}

von m.n. (Gast)


Lesenswert?

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.

von Experte (Gast)


Lesenswert?

AA schrieb:
> ich versuche den Drehregler

WELCHEN?

von AA (Gast)


Lesenswert?


von W.S. (Gast)


Lesenswert?

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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

: Bearbeitet durch User
von batman (Gast)


Lesenswert?

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.

von Teo D. (teoderix)


Lesenswert?

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....

: Bearbeitet durch User
von Doctor Snuggles (Gast)


Lesenswert?

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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Teo D. (teoderix)


Lesenswert?

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. 
:)

von batman (Gast)


Lesenswert?

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.

von Teo D. (teoderix)


Lesenswert?

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.

von batman (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Teo D. (teoderix)


Lesenswert?

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...

von Joachim B. (jar)


Lesenswert?

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

: Bearbeitet durch User
von batman (Gast)


Lesenswert?

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..

von phil (Gast)


Lesenswert?

irgendwie wird hier "Prellen" und "kippeln zwischen 2 gültigen 
Zuständen" vermischt.

von Frank E. (ffje)


Lesenswert?

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

von 2 Cent (Gast)


Lesenswert?

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

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.