Hallo Leute,
habe ein kleines Problem:
Ich habe hier einen Encoder, der über einen STM32 angesprochen wird. Der
uC beschreibt automatisch ein Counter Register, je nach Zählrichtung.
Das Register habe ich auf 20000 Werte begrenzt. Eine Umdrehung des
Encoders bedeutet ebenfalls 20000 Counts. Ich möchte nun die absolute
Anzahl der Counts anzeigen, dafür benötige ich eine Überlauferkennung.
Wenn ich das so nach dem Motto mache...
...benötige ich aber eine Schwelle. Ich bin mir nicht im klaren, wie
groß diese sein sollte. Wähle ich sie zu groß, erkennt sie keine
Überläufe, zu klein werden welche dazugedichtet...
Der Encoder wird mit max 50u/s angetrieben, ein Timer, der das
Counterregister ausließt hat eine Periodendauer von 6ms. Das bedeutet
pro Timerintervall können max 6000 Counts entstanden sein.
Angenommen meine Werte befinden sich bei 10000 und 6ms später bei 16000
Counts, dann ist alles gut, die Differenz beträgt 6000.
Kurz darauf kommt der Überlauf: 1. Wert bei 15k, der 2. 6ms später bei
1k. Die Differenz beträgt jetzt |-4000|=4000. Wähle ich also 6000 als
untere Grenze (darunter ist ein Überlauf), würde es hinkommen.
Dreht der Encoder aber langsamer, so werden natürlich auch die Counts
zwischen zwei Abtastpunkten (6ms) weniger. Z.B. nur noch 1000 steps bei
500rpm. Also wäre alles ein Überlauf :D
Das blöde: Es sollen sowohl positive als auch negative Überläufe erkannt
werden.
Versteht ihr mein Problem? Wenn ja, wie löst man so etwas?
Danke & schöne Grüße!
stm32 schrieb:> Aber wie geht es ohne Interrupt?
Du kennst die 'Richtung' in die sich der Zählerstand entwickeln müsste?
(zb wegen bekannter Drehrichtung eines Motor an dem der Encoder hängt)
Wenn der Counter eigentlich größer werden müsste.
Wenn der neue Wert kleiner als der vorhergehende ist, gab es
einen Überlauf. 19998 + 4 -> 2
vorher: 19998
jetzt: 2
-> Überlauf, indem 4 Ticks aufgelaufen sind
Wenn der Counter eigentlich kleiner werden müsste
Wenn der neue Wert größer als der vorhergehende ist, gab es
einen Unterlauf.
2 - 4 -> 19998
vorher: 2
jetzt: 19998
-> Unterlauf, indem 4 Ticks in der anderen Richtung aufgelaufen
sind
Du kennst die Drehrichtung nicht:
zb. du weisst nur dass sich der Wert von 15k auf 1k verändert hat.
dazu gibt es 2 Möglichkeiten
entweder der Counter ist immer größer geworden und hat
irgendwann mit einem Überlauf die 1k erreicht
oder der Counter ist in der anderen Richtung sukzessive
kleiner geworden, hat also tatsächlich
15000, 14999, 14998, ..., 1002, 1001, 1000
gezählt.
Welche ist die richtige Lösung?
Ist der Counter größer (+Überlauf) geworden, dann hat er
1k - 15k (und weil das Ergebnis negtiv ist: + 20k): 6k Ticks
zurückgelegt. -> Ergebnis A
Ist der Counter regulär kleiner geworden, dann hat er
15k - 1k: 14k Ticks zurückgelegt -> Ergebnis B
Da du aber weißt, das von einer Abfrage zur nächsten, der Counter
sich maximal um 6k Einheiten verändern kann, KANN daher Ergebnis B
nicht richtig sein. Der Counter kann sich physikalisch im
betrachteten Zeitraum nicht um 14k Ticks verändert haben.
Ergebnis A hingegen liegt mit 6k im Bereich des Möglichen.
-> Strategie: rechne dir die Werte für beide Möglichkeiten aus
und mach einen Plausibilitätscheck um zu entscheiden welcher
von beiden der richtige ist.
Note: Da Ergebnis A + Ergebnis B in Summe wieder die 20k ergeben
müssen, und die 6k Schwelle kleiner als die Hälfte davon (10k) ist,
ist es immer eindeutig welcher Fall vorliegt und man braucht auch
nur einen der beiden Fälle durchrechnen. Ist der durchgerechnete
Fall nicht möglich, kann es nur der andere sein.
stm32 schrieb:
>Kurz darauf kommt der Überlauf: 1. Wert bei 15k, der 2. 6ms später bei>1k. Die Differenz beträgt jetzt |-4000|=4000
Das ist ja wohl komplett falsch gerechnet.
Auch ist der Überlauf nicht durch einen Wert kleiner als irgendwas
gekennzeichnet, sondern größer als irgendwas.
Danke für deine Antwort!
Karl Heinz Buchegger schrieb:> Du kennst die 'Richtung' in die sich der Zählerstand entwickeln müsste?> (zb wegen bekannter Drehrichtung eines Motor an dem der Encoder hängt)
Leider nein, da schnelle Änderungen, fällt somit raus.
Es gibt zwar ein direction Bit, aber ich habe Angst das zu benutzen,
weil der Encoder sehr hochauflösend ist und die Richtungsänderung
ziemlich schnell sein kann.
Karl Heinz Buchegger schrieb:> Du kennst die Drehrichtung nicht:> zb. du weisst nur dass sich der Wert von 15k auf 1k verändert hat.
Das schon eher (wenn man z.B. von 3000rpm ausgeht)
Karl Heinz Buchegger schrieb:> -> Strategie: rechne dir die Werte für beide Möglichkeiten aus> und mach einen Plausibilitätscheck.
So in der Richtung wollte ich das ja ausprobieren, kam aber auf keinen
grünen Ast ;)
Dein Beispiel klingt aber logisch. Ich muss das nur noch in Befehle
verpacken, werde ich morgen machen.
Dankeschön =)
chick schrieb:> Das ist ja wohl komplett falsch gerechnet.>>> Auch ist der Überlauf nicht durch einen Wert kleiner als irgendwas> gekennzeichnet, sondern größer als irgendwas.
Aber das is das, was ich oben stehen hatte ;) Schlicht und ergreifend
die Differenz. Dass die nicht stimmt ist ja mehr oder weniger das
Problem ;)
stm32 schrieb:> Dein Beispiel klingt aber logisch.
Sowas (Überlauf/Unterlauf) kann man sich oft ganz leicht mit einer Uhr
und einem Sekundenzeiger klar machen.
erste Zeit: Sekundenzeiger auf 56
zweite Zeit: Sekundenzeiger auf 2
Du weisst nicht, ob es sich um eine normale Uhr oder um eine
rückwärtslaufende Eieruhr handelt.
Aber du weißt, dass der Vorgang (Gewicht, das vom Dach fällt) nicht
länger als 10 Sekunden gedauert haben kann.
Also wird es wohl eine normale Uhr gewesen sein, bei der der Zeiger über
60 drüber gelaufen ist.
Denn im anderen Fall hätte der Sekundenzeiger 54 Sekunden gebraucht um
von der 56 auf die 2 zu kommen. Und das widerspricht dem Grundwissen,
dass der Vorgang spätestens nach 10 Sekunden vorbei ist.
Dein Glück ist diese Aussage
> Der Encoder wird mit max 50u/s angetrieben, ein Timer, der> das Counterregister ausließt hat eine Periodendauer von 6ms.> Das bedeutet pro Timerintervall können max 6000 Counts entstanden> sein.
Die ist der Schlüssel zur Lösung des Gordischen Knotens.
stm32 schrieb:> chick schrieb:>> Das ist ja wohl komplett falsch gerechnet.>>>>>> Auch ist der Überlauf nicht durch einen Wert kleiner als irgendwas>> gekennzeichnet, sondern größer als irgendwas.>> Aber das is das, was ich oben stehen hatte ;) Schlicht und ergreifend> die Differenz. Dass die nicht stimmt ist ja mehr oder weniger das> Problem ;)
Das Problem ist, dass du dich von den Zahlenwerten hast täuschen lassen.
Eine Differenz errechnet sich immer aus Ende minus Anfang. Immer!
1k - 15k
und da kommt ganz sicher nicht -4k raus. Schon eher -14k. UNd weil es
sich um unsigned Arithmetik handelt, kann das nicht negativ sein,
sondern muss mit +20k beaufchlagt werden um wieder im erlaubten Bereich
0 bis 20k zu sein.
Wieder: einfach mal mit einer Uhr und einem Sekundenzeiger klarmachen.
Oder auch mit Winkeln am Winkelmesser. 20° minus 40° ergeben -20°. Um in
den erlaubten Bereich 0 bis 360 zu kommen, müssen da noch 360 dazu. -20
plus 360 macht 340. Also: 20° minus 40° ergeben 340°. Und natürlich auch
umgekehrt: 340° plus 40° ergeben 20°
Ein Absolutwert hingegen hat da nichts verloren.
Ist mir vollkommen klar, habe mir den Sachverhalt hier per
Sägezahnfunktion dargestellt. Das Problem war es bisher das in
Anweisungen zu verpacken :-(
Trotzdem natürlich danke für die weitere Ausführung!
Mir kommt gerade noch eine Frage hoch: Ist es überhaupt sinnvoll, den
absoluten Winkel benutzen zu wollen? Unter Umständen braucht es dafür
große Variablen, die auch überlaufen können. Mit einem int32 z.B. kann
ich ca 30 Min auf voller Drehzahl den Winkel loggen (pos + neg).
Ich möchte eigentlich eine Positionsregelung machen. Ist es da
möglicherweise sinniger, die Anzahl der Überläufe zu zählen und dann per
modulo Operation den Winkel herauszufinden? Kam mir gerade nur so in den
Kopf ;)
Und dann noch was zur Laufzeit:
Eine Flag im Interrupt setzen geht schnell denke ich mal. Eine
verschachtelte If-Konstruktion ist bestimmt länger.
Aber ein Interrupt "stört" auch gleichzeitig die anderen Abläufe. Ich
habe z.B. einen wichtigen Timer, der das Counter register abtastet.
Diesen habe ich natürlich hoch priorisiert. Dann sollte das kein Problem
sein oder?
Die selbe Frage bezüglich der Modulo Operation: Wie viel langsamer ist
die im Vergleich zum einfachen addieren der Winkel?
Danke euch!
Oh, da kam schon wieder was neues..
Karl Heinz Buchegger schrieb:> Dein Glück ist diese Aussage>> Der Encoder wird mit max 50u/s angetrieben, ein Timer, der>> das Counterregister ausließt hat eine Periodendauer von 6ms.>> Das bedeutet pro Timerintervall können max 6000 Counts entstanden>> sein.> Die ist der Schlüssel zur Lösung des Gordischen Knotens.
Das hab' ich so festgelegt, sonst käme mir auch der Herr Shannon in die
Quere ;)
Karl Heinz Buchegger schrieb:> Das Problem ist, dass du dich von den Zahlenwerten hast täuschen lassen.> Eine Differenz errechnet sich immer aus Ende minus Anfang. Immer!>> 1k - 15k>> und da kommt ganz sicher nicht -4k raus. Schon eher -14k. UNd weil es> sich um unsigned Arithmetik handelt, kann das nicht negativ sein,> sondern muss mit +20k beaufchlagt werden um wieder im erlaubten Bereich> 0 bis 20k zu sein.
Oh man. Damit muss ich meine Aussage von oben revidieren, hatte noch
nicht klick gemacht beim Sägezahn ;) Habe in der Tat die falschen Werte
verwendet. Statt 15k nämlich 5k, was die Differenz von 15k zu 20k ist.
Dankeschön
stm32 schrieb:> verschachtelte If-Konstruktion ist bestimmt länger.
Programmiers aus. Das hört sich jetzt nur kompliziert an. Im Code ist
das dann viel einfacher.
So, heute nochmal drüber geguckt.
Fand' die Interrupt Lösung eigentlich cool, aber habe dann festgestellt,
dass sich mei einem Ripple in 0° das übliche Problem ergibt.
Daher also 6000 als Schwelle verwendet und läuft. Hab' ich übrigens
vorher auch schon ausprobiert; Es lief nur nicht, weil ich Idiot den
falschen Header für die abs() Funktion includiert habe.
Jetzt läufts, besten Dank!
> Ich möchte nun die absolute Anzahl der Counts anzeigen, dafür> benötige ich eine Überlauferkennung.
Wenn ich mich jetzt gedanklich nicht zu sehr verfranst habe, dann ist
das hier ....
1
....
2
3
diff=naechsterWert-vorigerWert;
4
if(diff<0)
5
diff+=20000;
6
7
if(diff<10000)
8
total+=diff
9
else
10
total-=20000-diff;
11
12
vorigerWert=naechsterWert;
13
14
....
.... die komplette Aufsummierung der Tick Counts auf eine laufende
Summe.
Komplett ohne Interrupts oder auch nur die Anzahl der Overflows kennen
zu müssen. Ich sagte doch: Es erklärt sich nur schlecht, der Code selbst
ist ganz simpel.
Fall 1: Drehrichtung positiv, ohne Überlauf
vorigerWert sei 8000
naechsterWert sei 12000
-> also sollten 4000 Ticks addiert werden. Schaun ma mal
*** Passt ***
Fall 2: Drehrichtung positiv, mit Überlauf
vorigerWert sei 18000
naechsterWert sei 2000
-> also sollten 4000 Ticks addiert werden. Schaun ma mal
*** Passt ***
Fall 3: Drehrichtung negativ, ohne Unterlauf
vorigerWert sei 12000
naechsterWert sei 8000
-> also sollten 4000 Ticks subtrahiert werden. Schaun ma mal
total -= 20000 - diff; 4000 subtrahieren (20 - 16)
*** Passt ***
Fall 4: Drehrichtung negativ, mit Unterlauf
vorigerWert sei 2000
naechsterWert sei 18000
-> also sollten 4000 Ticks subtrahiert werden. Schaun ma mal
pwm schrieb:> Habe ich da Möglichkeiten nicht mit abgedeckt?
Probiers aus.
Es gibt 4 Fälle, spiel sie durch
(Oder schreib dir schnell am PC ein Programm, welches das für dich tut)