Forum: Mikrocontroller und Digitale Elektronik Inkrement auslesen, Auflösung verringern


von Dezimator (Gast)


Lesenswert?

Guten Tag,

ich lese einen inkrementellen Drehgeber mit 16 Bit aus, wobei ich 
allerdings die Auflösung um zwei Bit verringern will. Das Ergebnis 
benötige ich als Inkrement. Wichtig ist mir, dass der Fehler durch die 
Auflösungsverringerung nicht anwächst.

Würde ich einfach die Differenz zweier aufeinander Dekoderstände durch 
den Dezimierungsfaktor teilen, wüchse der Fehler schnell an. Also mache 
ich eine Division mit Restglied:
1
/* Inkrement aus Hardware-Decoder gewinnen bei verrringerter Aufloesung */
2
int getIncrement(void)
3
{
4
    const int8_t decimation = 4; // Zweierpotenz
5
6
    static uint16_t enc_n = 0;
7
    static int16_t rest = 0;
8
    
9
    uint16_t enc = (uint16_t) TIM_GetCounter(TIM3);
10
    int16_t denc = (int16_t) (enc - enc_n); // Vorzeichenrichtige Differenz
11
    enc_n = enc;
12
    
13
    int16_t dx = (denc+rest)/decimation;
14
    rest = (denc+rest)%decimation;
15
16
    return dx;
17
}

Das funktioniert wie erwartet.

Allerdings: Ist der Aufwand wirklich nötig, oder bin ich einem 
Denkfehler aufgesessen und es geht viel einfacher?

von Dezimator (Gast)


Lesenswert?

Ich sehe gerade: Es geht. ich brauche den Divisionsrest ja nur von enc_n 
abziehen, und spare mir die zweite statische Variable.

von Falk B. (falk)


Lesenswert?

Alles viel zu kompliziert.

https://www.mikrocontroller.net/articles/Drehgeber#Solide_L.C3.B6sung:_Beispielcode_in_C
1
int8_t encode_read4( void )         // read four step encoders
2
{
3
  int8_t val;
4
5
  cli();
6
  val = enc_delta;
7
  enc_delta = val & 3;
8
  sei();
9
  return val >> 2;
10
}

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Dezimator schrieb:

> Allerdings: Ist der Aufwand wirklich nötig, oder bin ich einem
> Denkfehler aufgesessen

Letzteres. Der Fehler wird sich immer im Bereich der weggeschnibbelten 
Bits bewegen, also im konkreten Fall eine Größe zwischen 0 und 3 
annehmen. Du muss dazu nur die zwei wegzuschnibbelnden Bits ÜBERALL 
ignorieren, das ist schon alles.

Am einfachsten machst du das, indem du einfach schon den Eingangswert 
durch den Dezimierungsfaktor teilst und in der Folge bloß noch mit den 
dezimierten Werten hantierst.

von Falk B. (falk)


Lesenswert?

@c-hater (Gast)

>Letzteres. Der Fehler wird sich immer im Bereich der weggeschnibbelten
>Bits bewegen, also im konkreten Fall eine Größe zwischen 0 und 3
>annehmen. Du muss dazu nur die zwei wegzuschnibbelnden Bits ÜBERALL
>ignorieren, das ist schon alles.

Tja, und eben weil das eher unpraktisch ist, packt man das in eine 
Funktion.

>Am einfachsten machst du das, indem du einfach schon den Eingangswert
>durch den Dezimierungsfaktor teilst und in der Folge bloß noch mit den
>dezimierten Werten hantierst.

Er muss aber intern mit dem Rest weiter zählen, sonst kommt Mist raus.

von c-hater (Gast)


Lesenswert?

Falk B. schrieb:

> Tja, und eben weil das eher unpraktisch ist, packt man das in eine
> Funktion.

Na klar, das war doch auch garnicht die Frage. Natürlich würde man das 
in eine Funktion packen. Überall schließt natürlich diese Funktion 
ein.

>>Am einfachsten machst du das, indem du einfach schon den Eingangswert
>>durch den Dezimierungsfaktor teilst und in der Folge bloß noch mit den
>>dezimierten Werten hantierst.
>

> Er muss aber intern mit dem Rest weiter zählen, sonst kommt Mist raus.

OMG, ich glaub' es nicht: Derselbe Denkfehler wie beim TO. Und das mit 
der angeblich SOOO GROOSSEN Programiererfahrung..

Nein, wenn man wie beschrieben vorgeht, also gleich an der Quelle die 
Bits wegschnibbelt und in der Folge nur noch mit der reduzierten 
Darstellung arbeiten (inbesondere auch beim Halter des letzten 
Zustands), kann man den Rest in den weggeschnibbelten Bits tatsächlich 
komplett ignorieren, der Fehler wird trotzdem niemals über den genannten 
Bereich anwachsen, weil er automagisch korrigiert wird, sobald er einen 
Wert von 4 (bzw. Vielfache davon) erreicht, dann gibt es nämlich in der 
reduzierten Interpretation einfach eine um 1 größere Änderung als 
nominell anstehen würde.

Das gilt übrigens für sogar für jeden Reduktionsfaktor, nicht nur für 
Zweierpotenzen. Man kann dann bloß nicht mehr so einfach die ignorierten 
Bits bennennen. Das interessiert aber auch niemanden wirklich...

von m.n. (Gast)


Lesenswert?

Dezimator schrieb:
> Wichtig ist mir, dass der Fehler durch die
> Auflösungsverringerung nicht anwächst.

Willst Du Kernspeicher sparen?
Verringere die Auflösung erst ganz zum Schluß, nachdem alle Berechnungen 
(ggf. Skalierung) mit dem ursprünglichen Wert durchgeführt wurden.

von Dezimator (Gast)


Lesenswert?

c-hater schrieb:
> Am einfachsten machst du das, indem du einfach schon den Eingangswert
> durch den Dezimierungsfaktor teilst und in der Folge bloß noch mit den
> dezimierten Werten hantierst.

Das wird nicht klappen. Dann stimmt der Überlauf der unsigned-Variablen 
nicht mehr.


Falks Lösung dürfte klappen, wenn man val static macht und statt & 3 
&(~3) macht.

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.