Hi,
in einem meiner Projekte verwende ich einen Drehencoder.
Der Encoder hat ne Rastung, pro Rasteinheit liefert er zwei Inkremente
ab.
Prinzipell funktioniert die Auswertung. Angeschlossen ist der Drehgeber
an zwei externe INTs (PinChange an AVR ATmega88).
Im Programm gibt es nun Probleme, weil das Ding prellt. Ne "normale"
Entprellung kommt nicht in Frage, weil man ja keine Pulse verpassen
will.
Das Problem ist, daß Linksdrehen (-) nicht die Umkehrung von
Rechtsdrehen (+) ist, d.h. im Programm wird die Folge +-+ anders
interpretiert als ++- anders als + etc.
Hat jemand ne Idee wie man das lösen könnte? Hier mal die
C-Implementierung:
1 | #ifndef _DREHGEBER_H_
|
2 | #define _DREHGEBER_H_
|
3 |
|
4 | #define DREH_INVALID -128
|
5 |
|
6 | static inline char drehgeber_step(void);
|
7 | static inline char drehgeber_job(void);
|
8 |
|
9 | #if defined (__GNUC__) && defined (__AVR__)
|
10 | # include <avr/pgmspace.h>
|
11 | #else
|
12 | # define PROGMEM
|
13 | # define pgm_read_byte(x) (*(x))
|
14 | #endif // avr-gcc
|
15 |
|
16 | // Aufrufen, wenn eine Flanke an einem der Ports festgestellt wurde,
|
17 | // zB aus einer ISR heraus.
|
18 | char drehgeber_step ()
|
19 | {
|
20 | static const char drehgeber_transitions[] PROGMEM =
|
21 | {
|
22 | 0, 1, -1, DREH_INVALID,
|
23 | -1, 0, DREH_INVALID, 1,
|
24 | 1, DREH_INVALID, 0, -1,
|
25 | DREH_INVALID, -1, 1, 0
|
26 | };
|
27 |
|
28 | static uint8_t a_alt;
|
29 | uint8_t a = a_alt;
|
30 |
|
31 | if (IS_SET (PORT_DREH_A)) a |= (1 << 2);
|
32 | if (IS_SET (PORT_DREH_B)) a |= (1 << 3);
|
33 |
|
34 | a_alt = a >> 2;
|
35 |
|
36 | return (char) pgm_read_byte (& drehgeber_transitions[a]);
|
37 | }
|
38 |
|
39 | // Mein Drehgeber hat eine Rasterung und bei jeden Raster erzeugt er *zwei*
|
40 | // Flanken. Man muss also die Anzahl der Schritte etwas mühsam durch 2 teilen.
|
41 | char drehgeber_job(void)
|
42 | {
|
43 | char step = drehgeber_step();
|
44 | char s = 0;
|
45 |
|
46 | if (DREH_INVALID != step)
|
47 | {
|
48 | static char tick;
|
49 | char t = step + tick;
|
50 |
|
51 | if (t >= 2) s = 1;
|
52 | if (t <= -2) s = -1;
|
53 |
|
54 | t -= s;
|
55 | t -= s;
|
56 |
|
57 | tick = t;
|
58 | }
|
59 |
|
60 | return s;
|
61 | }
|
62 | #endif // _DREHGEBER_H_
|
Was das Makro IS_SET macht sollte klar sein, aufgerufen wird
drehgeber_job() in der PinChange ISR:
1 | #include <inttypes.h>
|
2 | #include <avr/interrupt.h>
|
3 |
|
4 | #include "drehgeber.h"
|
5 |
|
6 | static int8_t volatile steps; // vom Drehgeber
|
7 |
|
8 | ...
|
9 |
|
10 | SIGNAL (SIG_PIN_CHANGE0)
|
11 | {
|
12 | steps += drehgeber_job();
|
13 | }
|
14 |
|
15 | int main()
|
16 | {
|
17 | ...
|
18 | // Leeraufruf zum Initialisieren
|
19 | drehgeber_step();
|
20 | ...
|
21 | }
|