Forum: Mikrocontroller und Digitale Elektronik STM32 Encoder als +/- Wert auswerten


von Timo (Gast)


Lesenswert?

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_t myEncVal = 0;
2
void StartEncoderTask(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
extern uint32_t myEncVal;
2
void HomeView::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

von c-hater (Gast)


Lesenswert?

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

von Timo (Gast)


Lesenswert?

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.

von Walter Tarpan (Gast)


Lesenswert?

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.

von Uwe K. (ukhl)


Lesenswert?

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… 🙈

von Gerald M. (gerald_m17)


Lesenswert?

1
uint32_t myEncVal = 0;
2
uint32_t myEncValold = 0;
3
void StartEncoderTask(void *argument)
4
{
5
  /* USER CODE BEGIN StartEncoderTask */
6
  HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
7
  /* Infinite loop */
8
  
9
  for(;;)
10
  {
11
    myEncValold = myEncVal
12
    myEncVal=  TIM3->CNT;
13
    osDelay(1);
14
  }
15
  /* USER CODE END StartEncoderTask */
16
}

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.

von Jobst M. (jobstens-de)


Lesenswert?

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

von Mobst J. (Gast)


Lesenswert?

@Jobst M.
Total an der Frage vorbei geantwortet. Aber sowas von.

von Timo (Gast)


Lesenswert?

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"

von Jobst M. (jobstens-de)


Lesenswert?

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

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.