Ich nutze einen handbetriebenen Drehgeber von ALPS an einem Atmel328p,
kann aber für das Lesen keinen Timer einsetzen. Also musste ein anderer
Weg für das entprellte Erkennen beider Drehrichtungen her.
Ich kam nach einigen Versuchen und dem Lesen des Datenblattes vom
Drehgebers (macht das Leben so viel leichter) zu folgendem Verfahren.
Schauen wir uns exemplarisch die Schalterstellung als Bitfolge an (A
schaltet hier vor B mit Prellen beider Schalter, Ausgangslage ist 00):
1 | BA BA BA BA BA BA BA BA BA BA BA BA BA BA BA BA BA BA
|
2 | 00 01 00 01 00 01 01 01 01 11 01 11 01 11 01 11 11 11
|
A schaltet ab Schritt 2 und ist ab Schritt 6 stabil. Laut Datenblatt
meines Drehgebers fängt B erst an zu Schalten, wenn A umgeschaltet hat
(wichtig, geprüft per Oszilloskop). Im Beispiel schaltet B ab Schritt 10
und ist ab Schritt 16 stabil.
Ansatz: es reicht zu erkennen, dass A geschaltet hat und stabil ist, und
darauf zu warten, das B anfängt zu prellen. Und natürlich anders herum
bei geänderter Drehrichtung. Das reicht als Indikator.
Vorgehen: die Schalterstellung als 2-Bit-Folge bei Änderungen in eine
8-Bit-Queue schieben und die Queue für die Drehrichtungserkennung
nutzen.
Wenn ich das obige Beispiel nehme, enthält die Queue als Ergebnis die
Bitfolge xx000111 (Shift von Rechts, die beiden hohen Bits sind nicht
von Belang). Wenn wir mit 11 starten und in die gleiche Richtung weiter
drehen, enthält die Queue xx111000. Dieses Pattern zeigt mir eine
Drehrichtung an. Wenn in die andere Richtung gedreht wird, sehen die
Pattern so aus: xx001011 bzw. xx110100. Also reicht es, die Queue
fortlaufend gegen die Änderungs-Pattern zu vergleichen und den Match als
Drehrichtungserkennung zu werten.
Vereinfacht wird das Ganze, da die Pattern einer Drehrichtung genau
gegenteilig sind. man schaut einfach auf Bit 6 und invertiert das Muster
wenn das Bit auf 1 steht. Dann bedeutet Pattern xx000111 eine
Drehrichtung und xx001011 die andere Drehrichtung.
Das Ganze läuft ohne Timer bei mir in meinem ziemlich proppevollen Code
problemfrei. Die Variable ticks (siehe Code Beispiel) beinhaltet die
Anzahl der Drehschritte und muss möglichst schnell ausgewertet werden.
In meinem Projekt geschieht das ungefähr alle 80-120ms, das ist für die
händische Nutzung bei mir völlig ausreichend.
Beispiel-Code:
1 | // Defines
|
2 | #define CW 0b00001011 // identification pattern clockwise
|
3 | #define CCW 0b00000111 // identification pattern counter clockwise
|
4 | #define QUEUE 0b00111111 // relevant bits of the queue (0-5)
|
5 | #define REVERT 0b00100000 // inverting detector pattern
|
6 |
|
7 | // function returns encoder switches A and B as lowest two bits (000000BA)
|
8 | // Hier: A an D12, B an D11 (Arduino Nomenklatur)
|
9 | uint8_t getEncoderStatus() {
|
10 | return ( ((~PINB & (1 << 4)) >> 4) // A shift to the most right
|
11 | |((~PINB & (1 << 3)) >> 2));// B shift to the right before A
|
12 | }
|
13 |
|
14 |
|
15 | int main(void) {
|
16 | int8_t ticks; // resulting number of turn ticks (must be signed)
|
17 | uint8_t encoder_queue; // encoder queue (relevant bits xx111111)
|
18 | uint8_t encoder_status; // actual encoder status (relevant bits xxxxxx11)
|
19 |
|
20 | encoder_queue = GetEncoderStatus(); // initialize encode queue
|
21 | ticks = 0; // initialize ticks
|
22 |
|
23 | while (1) {
|
24 |
|
25 | encoder_status = getEncoderStatus(); // get actual encoder status
|
26 | // if actual bits differ from lowest two bits...
|
27 | if ((encoder_queue ^ encoder_status) & 3) {
|
28 | // ... push them into queue from the right
|
29 | encoder_queue = encoder_queue << 2 | encoder_status;
|
30 |
|
31 | encoder_temp = encoder_queue; // queue bits into a temporary variable
|
32 |
|
33 | if (encoder_temp & REVERT) { // if reverse bit (bit 6) is true...
|
34 | encoder_temp = ~encoder_temp; // ...reverse the temporary variable
|
35 | }
|
36 |
|
37 | encoder_temp &= QUEUE; // select relevant queued bits
|
38 |
|
39 | if (encoder_temp == CCW) { // if counter clockwise pattern fits ...
|
40 | ticks--; // ... decrease the ticks
|
41 | }
|
42 | if (encoder_temp == CW) { // if clockwise pattern fits ...
|
43 | ticks++; // ... increment the ticks
|
44 | }
|
45 | }
|
46 | }
|
47 | }
|