Forum: Compiler & IDEs Drehgeber mit viertelter Auflösung


von Stefanie (Gast)


Lesenswert?

Hallo,

wie muss ich das Array aus dem Artikel 
http://www.mikrocontroller.net/articles/Drehgeber anpassen, wenn bei mir 
die Dekodertabelle für die halbe Auflösung immer noch doppelt zu schnell 
geht?
Also bei mir zeigt es bei jedem Schritt einen Sprung von 2 an.

// Dekodertabelle für wackeligen Rastpunkt
// halbe Auflösung
int8_t table[16] PROGMEM = {0,0,-1,0,0,0,0,1,1,0,0,0,0,-1,0,0};

D.h. ich bräuchte obiges Array für viertelte Auflösung.

Danke!

von Klaus W. (mfgkw)


Lesenswert?

Was meinst du mit "jedem Schritt"?
Einen Rastpunkt eines Drehknopfs?

Das was du vermutlich willlst, geht nicht mehr mit einer Änderung der 
Tabelle (zumindest nicht ohne deutliche Verlängerung der Tabelle und 
Änderung des Codes).
Warum halbierst du nicht einfach die tatsächlich zum Weiterrechnen 
benutzte Position?
Du bräuchtest also zwei Positionen: die bisherige genauere, aus der mit 
obiger Tabelle jeweils ein neuer Wert gebildet wird, und eine weitere, 
die dann immer als die genaue/2 berechnet wird. Mit letzterer arbeitest 
du im Programm, sie hat die halbe Auflösung.

von jørg (Gast)


Lesenswert?

Teil einfach enc_delta durch 2

von Yalu X. (yalu) (Moderator)


Lesenswert?

Z.B. so:
1
int8_t table[16] PROGMEM = {0,0,0,0,0,0,0,1,0,0,0,0,0,-1,0,0};

jørg schrieb:
> Teil einfach enc_delta durch 2

Gefährlich. Was passiert, wenn encode_read so oft aufgerufen wird, dass
enc_delta bei jeder Abfrage 0 oder 1 ist?

Edit:

Da die Tabelle nur noch zwei von 0 verschiedene Werte enthält, bringt
sie keine Geschwindigkeitsvorteile mehr, im Gegenteil. Folgender Code
ist schneller und spart einschließlich der nun nicht mehr benötigten
Tabelle 30 Bytes an Flash-Speicher ein.
1
ISR( TIMER0_COMP_vect )             // 1ms fuer manuelle Eingabe
2
{
3
    static int8_t last=0;           // alten Wert speichern
4
    int8_t last1;
5
 
6
    last1 = (last << 2)  & 0x0F;
7
    if (PHASE_A) last1 |= 0x02;
8
    if (PHASE_B) last1 |= 0x01;
9
    if(last1 == 0x07)
10
      enc_delta++;
11
    else if(last1 == 0x0d)
12
      enc_delta--;
13
    last = last1;
14
}

Vorsicht: Dieser Code ist nicht getestet :)

von Falk B. (falk)


Lesenswert?

@jørg (Gast)

>Teil einfach enc_delta durch 2

Nein, das geht schief. Er muss den aus enc_delta abgeleiteten Wert 
normal speichern und daraus den Wert / 2 teilen.
1
 while(1){
2
    val += encode_read();
3
    val_2 = val / 2;      
4
    LEDS = val_2;
5
  }

MFG
Falk

von Simon K. (simon) Benutzerseite


Lesenswert?

Hä? In der von dir verlinkten Seite sind doch extra Funktionen dafür 
angelegt worden:

int8_t encode_read2( void )
int8_t encode_read4( void )

usw.

Da ists vorgemacht, wie man das am besten (=ohne extra Variable) löst.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Yalu X. schrieb:
> Z.B. so:
> int8_t table[16] PROGMEM = {0,0,0,0,0,0,0,1,0,0,0,0,0,-1,0,0};

Ich habe eine Anfrage erhalten, wie man denn auf diese Tabelle käme.
Hier ist eine kurze Erklärung:

Die Signale A und B können zusammen vier Zustände annehmen: 00, 01, 10
und 11. Bei jedem Timer-Interrupt geht der Zustand (A,B) in einen Zu-
stand (A',B') über. Dafür gibt es 4·4=16 Möglichkeiten. In folgender
Tabelle sind auf der linken Seite alle 16 möglichen Zustandsübergänge
und auf der rechten Seite der Wert für die Inkrementierung des Zählers
(-1, 0 oder +1) aufgelistet. man betrachte sich dazu die Signaldiagramme
am Anfang des Artikels [Drehgeber].

Ist die Interruptfrequenz hoch genug, d.h. zwischen zwei Zustandsüber-
gänge fällt mindestens ein Interrupt, ändert sich bei jedem Interrupt
der Pegel von höchstens einem der Signale A und B. Ändern sich beide
Signale zusammen, wurde der Knopf zu schnell gedreht, so dass mindestens
ein Zustandsübergang nicht registriert wurde. Diese Fälle sind in der
Tabelle mit einem 'F' gekennzeichnet.

Ja nachdem, welche Signalflanken bzw. Zustandsübergänge man für die In-
krementierung des Zählers nutzt, erhält man unterschiedliche Auflösun-
gen:

I4 (volle Auflösung):   Alle Flanken (4 pro Periode)
I2 (halbe Auslösung):   Nur Flanken von A (2 pro Periode)
I1 (Viertelsauflösung): Nur Flanken von A, während B=1 (1 pro Periode)
1
-----------+--------------
2
  Zustands-|  Inkrement
3
  übergang |  (F=Fehler)
4
-----+-----+----+----+----
5
 A B | A'B'| I4 | I2 | I1
6
-----+-----+----+----+----
7
 0 0 | 0 0 |  0 |  0 |  0
8
 0 0 | 0 1 | +1 |  0 |  0
9
 0 0 | 1 0 | -1 | -1 |  0
10
 0 0 | 1 1 |  F |  F |  F
11
 0 1 | 0 0 | -1 |  0 |  0
12
 0 1 | 0 1 |  0 |  0 |  0
13
 0 1 | 1 0 |  F |  F |  F
14
 0 1 | 1 1 | +1 | +1 | +1
15
 1 0 | 0 0 | +1 | +1 |  0
16
 1 0 | 0 1 |  F |  F |  F
17
 1 0 | 1 0 |  0 |  0 |  0
18
 1 0 | 1 1 | -1 |  0 |  0
19
 1 1 | 0 0 |  F |  F |  F
20
 1 1 | 0 1 | -1 | -1 | -1
21
 1 1 | 1 0 | +1 |  0 |  0
22
 1 1 | 1 1 |  0 |  0 |  0
23
-----+-----+----+----+----

Der Beispielcode in

  http://www.mikrocontroller.net/articles/Drehgeber#Dekoder_f.C3.BCr_Drehgeber_mit_wackeligen_Rastpunkten

fasst nun die vier Bits A, B, A' und B' eines Zustandsübergangs zu einer
Integerzahl last (0..15) zusammen und nutzt diese als Index für die
Tabelle der Inkremente. Der Tabellenwert wird dann zur Zählervariablen
enc_delta hinzuaddiert.

In dem von mir geposteten Codefragment für die Viertelsauflösung wird
genau das Gleiche getan, nur ohne Tabelle. Da die Tabelle nur zwei von 0
verschiedene Werte enthält, werden die entsprechenden Indizes (7 und
13) stattdessen mittels zweier if-Abfragen direkt ausgewertet.

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.