Hallo Zusammen,
Für ein kleines Projekt möchte ich einen Encoder auswerten. Hierbei
handelt es sich nicht um einen von einem Motor sondern um einen dieser
Handbedienten die Aussehen wie ein Potentiometer.
Ich habe nun in CubeIDE den Encoder bereits zum laufen gebracht, hierzu
benutze ich Timer3 auf einem STM32 Nucleo und die passenden Pins, den
Wert des Encoders rufe ich wie folgt ab:
1
uint32_tmyEncVal=0;
2
voidStartEncoderTask(void*argument)
3
{
4
/* USER CODE BEGIN StartEncoderTask */
5
HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL);
6
/* Infinite loop */
7
for(;;)
8
{
9
myEncVal=TIM3->CNT;
10
osDelay(1);
11
}
12
/* USER CODE END StartEncoderTask */
13
}
später wird der Wert dann wie folgt verwendet:
1
externuint32_tmyEncVal;
2
voidHomeView::handleTickEvent(){
3
Anzeige1.setValue(myEncVal);
4
}
Das Funktioniert ohne Probleme wenn ich die Variable myEncVal beobachte
wird vom Variablen Wert 0 "nach rechts" gedreht zählt es hoch, und wird
vom Variablen Wert 0 "nach links" gedreht springt der Wert auf 1023 und
von dort abwärts.
Mein Problem ist nun aber, das ich gerne aus die Auswertung als letzte
Änderung erhalten möchte.
Aktuell is es jetz beispielsweise so das wenn ich den Encoder abfrage
erhalte ich die Zahl "500" ich weiss aber nicht wie der Encoder dies
erreicht hat.
Was ich mir wünschen würde, ist das der Wert "myEncVal" jeweils nur die
differenz zu letzen Mal abfragen beinhaltet. Also wenn der Encoder seit
der letzen Abfrage 4 mal nach rechts gedreht wurde sollte der Wert 4
sein, bei 4 mal nach links sollte der Wert -4 sein. Dreht man Ihn
zwischen den Abfragen 4 mal nach links und einmal nach rechts, wäre der
Wert -3. Das aber nur als hypothetische Angabe da man das kaum schafft.
Könnte mir jemand einen Tipp geben wie ich sowas lösen kann?
Viele Grüss
Timo
Timo schrieb:> Das Funktioniert ohne Probleme wenn ich die Variable myEncVal beobachte> wird vom Variablen Wert 0 "nach rechts" gedreht zählt es hoch, und wird> vom Variablen Wert 0 "nach links" gedreht springt der Wert auf 1023 und> von dort abwärts.
Aha. Also hat der Zähler wohl 10Bit. Blöd, paßt nicht zu irgendeinem
existierenden C-Datentyp. Da muß man richtig denken und wirklich wissen,
was man tut...
> Was ich mir wünschen würde, ist das der Wert "myEncVal" jeweils nur die> differenz zu letzen Mal abfragen beinhaltet.
Behandele die Zahl korrekt im zyklischen Bereich eines 10 Bit-Integer.
Ja, das geht auch in C. Sogar recht einfach, da der
Standard-Integer-Datentyp mindestens 16 Bit hat, man sich also nicht mit
Über-/Unterläufen des Typen selber rumschlagen muss, sondern alles
Wichtige noch in der Zahl selber erkennbar ist.
Also absolut trivial. Man muss bloß was über die binäre Darstellung von
Zahlen lernen und das dann sinnvoll anwenden. Passendes Google-Suchwort
wäre wohl "signed extension".
Ich bin mir nicht ganz sicher ob du verstanden hast was das Problem ist.
Mein Problem ist, das dieser Encoder die "Position" speichert, so wie
z.b. ein Encoder das bei einem Motor tun müsste, um zu wissen an welcher
Position steht, ich benötige aber jeweils nur den Unterschied zwischen
der letzten Abfrage.
So ein Handbetriebener Encoder ist ja quasi ein Ersatz für zwei Taster.
Der Wert 1023 kommt übrigends aus dem Beispiel, aber in CubeMX lässt
sich dieser einstellen zwischen 0...65535, das bringt aber keine
Veränderung, die Position bzw. Wert wird weiterhin gespeichert.
Timo schrieb:> ich benötige aber jeweils nur den Unterschied zwischen der letzten> Abfrage.
Ich fürchte, er weiss genau was Du meinst und hat angenommen, dass Du
selbst darauf gekommen bist, dass Du die vorzeichenrichtige Differenz
suchst.
Wie auch immer, das ist nicht komplett trivial, mit sign extension wurde
ja schon das Stichwort genannt.
Wenn dein Drehgeber-Programm dir die Differenz nicht zur Verfügung
stellt, dann musst Du es ausrechnen.
Einfach den alten Wert speichern und vom neuen Abziehen.
Neu - Alt = Differenz
Wenn Du den Unterschied zwischen uint32_t und int32_t nicht kennst,
suche dir ein neues Hobby. Ein int8_t sollte für die Differenz genügen.
… echt jetzt… 🙈
Deine Differenz ist dann einfach der neue minus der alte Wert.
Ansonsten kannst du auch nach jedem Durchlauf den Encoderwert auf null
setzen. Dann verlierst du natürlich auch den Absolutwert.
Bei der Dekodierung von Grayencodern fällt als erstes sogar nur die
Differenz ab, welche dann zu dem Dir zur Verfügung gestellten Wert
hinzuaddiert wird.
Du kannst dies nun also durch die Differenz zum vorherigen Wert
zurückrechnen oder Dir die Lib nehmen und die Akkumulierung dort
entfernen.
Oder natürlich auch selbst eine Routine schreiben.
Oder hier hineinschauen ...
Beitrag "Drehgeber auslesen"
Gruß
Jobst
Ich habe das Problem nun gelöst mit euren Tipps und noch ein bisschen im
Internet suchen,
Ich habe den Wert des Counters nun auf 65535 gestellt und den Datentyp
int16 gesetzt, dazu habe ich es nun mit googlen hinbekommen, den Zähler
direkt aus dem Display zurückzusetzen. Nach jedem auslesen des Werts
setzte ich den zähler auf 0, wird dann nach rechts gedreht zäht es ins
Minus und nach links ins Plus.
Die "Absolutposition" ist für mich sowieso irrelevant, da der Encoder
ein Menü auf dem Display steuert, quasi wie mit einem Button für "nach
link" "nach rechts"
Mobst J. schrieb:> @Jobst M.> Total an der Frage vorbei geantwortet. Aber sowas von.
Ich gebe zu, ein wichtiges Detail übersehen zu haben.
Als gänzliche Verfehlung würde ich es aber nicht werten.
Denn an einer Stelle in der Routine wird eben 1 hinzu gezählt oder 1
abgezogen. Und dann muss man schauen, wie einem dieser akkumulierte Wert
übergeben wird.
Bekommt man nur eine Kopie oder bekommt man direkt den Akkumulator
zurück? Im zweiten Fall würde es nämlich ausreichen diesen auszulesen
und anschließend einfach zu löschen.
Ich drehe 4 vor, lese 4, lösche.
Ich drehe 3 zurück, lese -3, lösche.
Ich drehe 2 zurück und 4 vor, lese 2, lösche.
Anstelle des löschens kannst Du auch den gelesenen Wert abziehen. Dies
hat den Charme, falls die Abfrage in einem IRQ passiert und zwischen
lesen und löschen stattfindet, Dir weitere Impulse nicht abhanden
kommen.
Gruß
Jobst