Forum: Mikrocontroller und Digitale Elektronik Rotary Encoder macht immer 4 Schritte


von Alexander S. (alexander_s674)


Lesenswert?

Hallo zusammen.

Ich habe mich vor ein paar Tagen nach langer Arduino pause mal 
hingesetzt und das ein oder andere Projekt gestartet.

Ganz neu bin ich auf dem Gebiet der Encoder.

Encoder einlesen und wert ausgeben hat nach anfänglichen problem auch 
super geklappt.
Leider ist es so, das wenn ich den Encoder eine Raste weiter drehe, sich 
der wert gleich um 4 erhöht. Und zwar immer genau um 4.

Schaltung: Ich nutze einen Arduino Mega 2560. Der Encoder hängt mit Pin1 
auf D2 und mit Pin2 auf D22. Der Encoder ist mehr oder weniger direkt 
verbunden. Habe testweise von pin1 und pin2 des Encoders jeweils einen 
100nF elko zur Masse gesetzt, hat leider nicht geholfen. Deßwegen 
momentan wieder direkt angeschlossen.

Code: long hdg_pos  = 0;

void loop() {
  long hdg_new = hdg.read();
  if (hdg_new != hdg_pos) {
    hdg_pos = hdg_new;}
    if (hdg_pos > 360){
      hdg.write(1);
    }
    if (hdg_pos < 1){
      hdg.write(360);
    }
}

Ich habe schon probiert hdg.read() / 4;
Das hilft auch danach sind dann einer Schritte möglich, allerdings macht 
der "Wertebereich" dann Probleme denn wenn ich hdg.write(360) sage und 
danach direkt hdg.read() / 4 gibt er mir natürlich 90 aus, soll aber 360 
ausgeben.
(Ja, das ganze soll mal auf einen Autopiloten hinaus laufen)

Könnt ihr mir hier evt. weiterhelfen?

Lieber Gruß,
- Alex

: Verschoben durch User
von Volker S. (vloki)


Lesenswert?

Alexander S. schrieb:
> Leider ist es so, das wenn ich den Encoder eine Raste weiter drehe, sich
> der wert gleich um 4 erhöht. Und zwar immer genau um 4.

Das ist vermutlich ganz normal. Der Encoder erzeugt zwischen den 
Rastpunkten zwei versetzte Pulse. Das gibt vier Zustandswechsel.

von Alexander S. (alexander_s674)


Lesenswert?

Also habe ich hier einen Encoder mit 20 Rastungen und 80 Impulsen?

Wusste garnicht das es sowas gibt.....

Gibts denn eine Möglichkeit das Problem irgendwie im Code zu lösen ohne 
gleich neue encoder kaufen zu müssen?

lg.

von Volker S. (vloki)


Lesenswert?

Alexander S. schrieb:
> Also habe ich hier einen Encoder mit 20 Rastungen und 80 Impulsen?

Nein, das sind bestimmt 20 Rasten und auch 20 Impulse pro Spur. Durch 
die versetzten Signale der beiden Kanäle gibt das 80 Signalwechsel.
Bei Encoder ohne Rasten (auf Motorwellen ...) bekäme man so 80 
Positionen pro Umdrehung. Bei den Fingern mit Rasten, die man mit der 
Hand dreht bringt das aber nichts. Da gibt es eben nur so viele 
sinnvolle Positionen wie Rasten.

Alexander S. schrieb:
> Gibts denn eine Möglichkeit das Problem irgendwie im Code zu lösen
Klar, schreib den Code um...

: Bearbeitet durch User
von EGS (Gast)


Lesenswert?

Hallo Alexander,

du hast sicherlich einen Encoder wie jeden anderen auch. Die meisten 
haben 24 Rastungen pro Umdrehung.

Auch gehe ich in der Annahme, dass du dir eine fertige Libary gesucht 
hast für deinen Code. Ich gebe zu, habe ich für meinen ersten Encoder 
auch gemacht. Hier wurden auch je Rastung der Zähler um 4 
inkrementiert/dekrementiert.

Du kannst dein Problem genau durch verstehen der verwendeten Libary und 
anpassen selbiger an der richigen Stelle "lösen".

Kannst ja mal deinen vollständigen Code posten, der Schnipsel aus deinem 
Eingangspost ist ja nur ein Bruchteil eines Arduinosketches...

Gruß EGS

von Alexander S. (alexander_s674)


Lesenswert?

Alles klar.
Also so wie ich rotary encoder kenne machen die pro Raste genau einen 
Wechsel. Anders macht die Raste m.M.n. auch keinen Sinn.



Volker S. schrieb:
> Alexander S. schrieb:
>> Gibts denn eine Möglichkeit das Problem irgendwie im Code zu lösen
> Klar, schreib den Code um...

PS: Wenn man keine Lust hat anderen zu helfen kann man sich besser 
gleich aus sämtlichen Internet Foren verziehen, denn auf solche 
Kommentare kann ich und auch alle anderen die Hilfe suchen dankend 
verzichten.
Schönen Abend noch.

von Dieter F. (Gast)


Lesenswert?


von Alexander S. (alexander_s674)


Lesenswert?

EGS schrieb:
> Hallo Alexander,
>
> du hast sicherlich einen Encoder wie jeden anderen auch. Die meisten
> haben 24 Rastungen pro Umdrehung.
>
> Auch gehe ich in der Annahme, dass du dir eine fertige Libary gesucht
> hast für deinen Code. Ich gebe zu, habe ich für meinen ersten Encoder
> auch gemacht. Hier wurden auch je Rastung der Zähler um 4
> inkrementiert/dekrementiert.
>
> Du kannst dein Problem genau durch verstehen der verwendeten Libary und
> anpassen selbiger an der richigen Stelle "lösen".
>
> Kannst ja mal deinen vollständigen Code posten, der Schnipsel aus deinem
> Eingangspost ist ja nur ein Bruchteil eines Arduinosketches...
>
> Gruß EGS

Hi.

Ja, ich arbeite mit Libary´s. Das häst es für mich schön einfach.
Ich habe nur den Schnipsel rausgerückt weil das der einzige Teil ist in 
dem der encoder behandelt wird (exklusive inkludieren der libary und 
zuweisen der pins). Im Rest des Codes werden nur einige Sachen ans LCD 
Display ausgegeben. (Auch noch nicht schön)

Trotzdem hier der ganze code:
1
 
2
#include <LiquidCrystal.h>
3
#include <Encoder.h>
4
5
LiquidCrystal lcd(11, 12, 13, 10, 9, 8, 7, 6, 5, 4, 3);
6
Encoder hdg(2, 22);
7
void setup() {
8
9
}
10
long hdg_pos  = 0;
11
12
void loop() {
13
  long hdg_new = hdg.read();
14
  if (hdg_new != hdg_pos) {
15
    hdg_pos = hdg_new;}
16
    if (hdg_pos > 360){
17
      hdg.write(1);
18
    }
19
    if (hdg_pos < 1){
20
      hdg.write(360);
21
    }
22
23
  lcd.begin(20, 4);
24
  lcd.setCursor(0, 0);
25
  lcd.print("Autopilot");
26
  lcd.setCursor(0, 2);
27
  lcd.print("HDG");
28
  lcd.setCursor(0, 3);
29
  lcd.print(hdg_pos);
30
  lcd.setCursor(7, 2);
31
  lcd.print("SPD");
32
  lcd.setCursor(7, 3);
33
  lcd.print("999");
34
  lcd.setCursor(15, 2);
35
  lcd.print("ALT");
36
  lcd.setCursor(14, 3);
37
  lcd.print("99999");
38
  
39
}

Lieber Gruß,
- Alex

: Bearbeitet durch User
von Volker S. (vloki)


Lesenswert?

Alexander S. schrieb:
> Volker S. schrieb:
>> Alexander S. schrieb:
>>> Gibts denn eine Möglichkeit das Problem irgendwie im Code zu lösen
>> Klar, schreib den Code um...
>
> PS: Wenn man keine Lust hat anderen zu helfen kann man sich besser
> gleich aus sämtlichen Internet Foren verziehen, denn auf solche
> Kommentare kann ich und auch alle anderen die Hilfe suchen dankend
> verzichten. Schönen Abend noch.

Den Code posten und um weitere Hinweise bitten wäre meiner persönlichen 
Meinung nach cleverer gewesen ;-)

von Dieter F. (Gast)


Lesenswert?

Das wäre eine einfache Lösung ...
(Aber es gibt hier wirklich gutes Coding zur Encoder-Auswertung :-) )
1
...
2
void loop() {
3
  long hdg_new = hdg.read();
4
  if (hdg_new != hdg_pos) {
5
    hdg_pos = hdg_new;}
6
    if (hdg_pos > 1440){
7
      hdg.write(4);
8
    }
9
    if (hdg_pos < 4){
10
      hdg.write(1440);
11
    }
12
   
13
14
    
15
    // set up the LCD's number of columns and rows:
16
  lcd.begin(20, 4);
17
  lcd.setCursor(0, 0);
18
  lcd.print("Autopilot");
19
  lcd.setCursor(0, 2);
20
  lcd.print("HDG");
21
  lcd.setCursor(0, 3);
22
  lcd.print(hdg_pos/4);
23
...

von Joachim B. (jar)


Lesenswert?

ich finde den Code genial, lief wie immer von peda auf Anhieb!
https://www.mikrocontroller.net/articles/Drehgeber
ich habe auch einen 4er muss halt nur benutzt werden

int8_t encode_read4( void )         // read four step encoders

von Volker S. (vloki)


Lesenswert?

Volker S. schrieb:
> Den Code posten

Ich mein natürlich den Lib-Code. Hat ja nicht jeder schon genau damit 
gearbeitet aber viele verstehen C-Code trotzdem, egal für was der 
geschrieben wurde.

von Volker S. (vloki)


Lesenswert?

Alexander S. schrieb:
> Alles klar.
> Also so wie ich rotary encoder kenne machen die pro Raste genau einen
> Wechsel. Anders macht die Raste m.M.n. auch keinen Sinn.

Da kennst Du wohl nicht viele ;-)

von EGS (Gast)


Lesenswert?

> Ja, ich arbeite mit Libary´s. Das häst es für mich schön einfach.
> Ich habe nur den Schnipsel rausgerückt weil das der einzige Teil ist in
> dem der encoder behandelt wird (exklusive inkludieren der libary und
> zuweisen der pins). Im Rest des Codes werden nur einige Sachen ans LCD
> Display ausgegeben. (Auch noch nicht schön)
>
> Trotzdem hier der ganze code:
> #include <LiquidCrystal.h>
> #include <Encoder.h>

So jetzt schau mal was du hier in der einen Zeile machst...du hast es ja 
bereits bschrieben. Die Libs sind dafür da das du anstelle jedesmal die 
kompletten Befehle zu schreiben mit Funktionsaufrufen arbeiten kannst.

Daher wird dein Encoder nicht nur in deinem im Eingangspost gegebenen 
Code bearbeitet, sondern durch das #include <encoder.h>.

Hier wird der Encoder denke mal im Interupt verarbeitet und als Funktion 
bereitgestellt was das Ergebniss ist (eine Variable die 
hoch/runterzählt) von der Impulsauswertung.

Wenn du die "enoder.h" mit notepad oder der Arduino IDE öffnest dann 
siehst du da den entsprechenden Code.

Und hier sind wir wieder bei:

"Du kannst dein Problem genau durch verstehen der verwendeten Libary und
anpassen selbiger an der richigen Stelle "lösen"."

Gruß EGS

von Volker S. (vloki)


Lesenswert?

EGS schrieb:
> Und hier sind wir wieder bei:
>
> "Du kannst dein Problem genau durch verstehen der verwendeten Libary und
> anpassen selbiger an der richigen Stelle "lösen"."

Pass auf,sonst bekommst du auch noch negative Bewertungen ;-)

von EGS (Gast)


Lesenswert?

Volker S. schrieb:
> Pass auf,sonst bekommst du auch noch negative Bewertungen ;-)

Hihi als Gast :P

Ich bin bloßzu vergesslich bei meinem mc-Forum PW (Selbstschutz vor 
negativen Bewertungen) ;)

duckundwech

von Volker S. (vloki)


Lesenswert?

EGS schrieb:
> Volker S. schrieb:
>> Pass auf,sonst bekommst du auch noch negative Bewertungen ;-)
>
> Hihi als Gast :P....
Hätte ich wohl besser geschrieben "dein Beitrag" ;-)

von EGS (Gast)


Lesenswert?

Verdammt...

Volker S. schrieb:
> EGS schrieb:
>> Volker S. schrieb:
>>> Pass auf,sonst bekommst du auch noch negative Bewertungen ;-)
>>
>> Hihi als Gast :P....
> Hätte ich wohl besser geschrieben "dein Beitrag" ;-)

nassmachvorangst hihihihuhihuch...

von Alexander S. (alexander_s674)


Lesenswert?

So, ich habe mir gestern und heute morgen mal die Libary angeschaut.

Meine Programmierkenntnisse sind allerdings nicht auf dem Stand um das 
alles auf Anhieb zu verstehen.

Ich poste euch hier mal die Libary rein, vielleicht ist jemand von euch 
so nett und schaut mal drüber und kann mir dann vielleicht sagen welche 
part ich mir mal genauer anschauen könnte.....
1
/* Encoder Library, for measuring quadrature encoded signals
2
 * http://www.pjrc.com/teensy/td_libs_Encoder.html
3
 * Copyright (c) 2011,2013 PJRC.COM, LLC - Paul Stoffregen <paul@pjrc.com>
4
 *
5
 * Version 1.2 - fix -2 bug in C-only code
6
 * Version 1.1 - expand to support boards with up to 60 interrupts
7
 * Version 1.0 - initial release
8
 * 
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 * 
16
 * The above copyright notice and this permission notice shall be included in
17
 * all copies or substantial portions of the Software.
18
 * 
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 * THE SOFTWARE.
26
 */
27
28
29
#ifndef Encoder_h_
30
#define Encoder_h_
31
32
#if defined(ARDUINO) && ARDUINO >= 100
33
#include "Arduino.h"
34
#elif defined(WIRING)
35
#include "Wiring.h"
36
#else
37
#include "WProgram.h"
38
#include "pins_arduino.h"
39
#endif
40
41
#include "utility/direct_pin_read.h"
42
43
#if defined(ENCODER_USE_INTERRUPTS) || !defined(ENCODER_DO_NOT_USE_INTERRUPTS)
44
#define ENCODER_USE_INTERRUPTS
45
#define ENCODER_ARGLIST_SIZE CORE_NUM_INTERRUPT
46
#include "utility/interrupt_pins.h"
47
#ifdef ENCODER_OPTIMIZE_INTERRUPTS
48
#include "utility/interrupt_config.h"
49
#endif
50
#else
51
#define ENCODER_ARGLIST_SIZE 0
52
#endif
53
54
55
56
// All the data needed by interrupts is consolidated into this ugly struct
57
// to facilitate assembly language optimizing of the speed critical update.
58
// The assembly code uses auto-incrementing addressing modes, so the struct
59
// must remain in exactly this order.
60
typedef struct {
61
  volatile IO_REG_TYPE * pin1_register;
62
  volatile IO_REG_TYPE * pin2_register;
63
  IO_REG_TYPE            pin1_bitmask;
64
  IO_REG_TYPE            pin2_bitmask;
65
  uint8_t                state;
66
  int32_t                position;
67
} Encoder_internal_state_t;
68
69
class Encoder
70
{
71
public:
72
  Encoder(uint8_t pin1, uint8_t pin2) {
73
    #ifdef INPUT_PULLUP
74
    pinMode(pin1, INPUT_PULLUP);
75
    pinMode(pin2, INPUT_PULLUP);
76
    #else
77
    pinMode(pin1, INPUT);
78
    digitalWrite(pin1, HIGH);
79
    pinMode(pin2, INPUT);
80
    digitalWrite(pin2, HIGH);
81
    #endif
82
    encoder.pin1_register = PIN_TO_BASEREG(pin1);
83
    encoder.pin1_bitmask = PIN_TO_BITMASK(pin1);
84
    encoder.pin2_register = PIN_TO_BASEREG(pin2);
85
    encoder.pin2_bitmask = PIN_TO_BITMASK(pin2);
86
    encoder.position = 0;
87
    // allow time for a passive R-C filter to charge
88
    // through the pullup resistors, before reading
89
    // the initial state
90
    delayMicroseconds(2000);
91
    uint8_t s = 0;
92
    if (DIRECT_PIN_READ(encoder.pin1_register, encoder.pin1_bitmask)) s |= 1;
93
    if (DIRECT_PIN_READ(encoder.pin2_register, encoder.pin2_bitmask)) s |= 2;
94
    encoder.state = s;
95
#ifdef ENCODER_USE_INTERRUPTS
96
    interrupts_in_use = attach_interrupt(pin1, &encoder);
97
    interrupts_in_use += attach_interrupt(pin2, &encoder);
98
#endif
99
    //update_finishup();  // to force linker to include the code (does not work)
100
  }
101
102
103
#ifdef ENCODER_USE_INTERRUPTS
104
  inline int32_t read() {
105
    if (interrupts_in_use < 2) {
106
      noInterrupts();
107
      update(&encoder);
108
    } else {
109
      noInterrupts();
110
    }
111
    int32_t ret = encoder.position;
112
    interrupts();
113
    return ret;
114
  }
115
  inline void write(int32_t p) {
116
    noInterrupts();
117
    encoder.position = p;
118
    interrupts();
119
  }
120
#else
121
  inline int32_t read() {
122
    update(&encoder);
123
    return encoder.position;
124
  }
125
  inline void write(int32_t p) {
126
    encoder.position = p;
127
  }
128
#endif
129
private:
130
  Encoder_internal_state_t encoder;
131
#ifdef ENCODER_USE_INTERRUPTS
132
  uint8_t interrupts_in_use;
133
#endif
134
public:
135
  static Encoder_internal_state_t * interruptArgs[ENCODER_ARGLIST_SIZE];
136
137
//                           _______         _______       
138
//               Pin1 ______|       |_______|       |______ Pin1
139
// negative <---         _______         _______         __      --> positive
140
//               Pin2 __|       |_______|       |_______|   Pin2
141
142
    //  new  new  old  old
143
    //  pin2  pin1  pin2  pin1  Result
144
    //  ----  ----  ----  ----  ------
145
    //  0  0  0  0  no movement
146
    //  0  0  0  1  +1
147
    //  0  0  1  0  -1
148
    //  0  0  1  1  +2  (assume pin1 edges only)
149
    //  0  1  0  0  -1
150
    //  0  1  0  1  no movement
151
    //  0  1  1  0  -2  (assume pin1 edges only)
152
    //  0  1  1  1  +1
153
    //  1  0  0  0  +1
154
    //  1  0  0  1  -2  (assume pin1 edges only)
155
    //  1  0  1  0  no movement
156
    //  1  0  1  1  -1
157
    //  1  1  0  0  +2  (assume pin1 edges only)
158
    //  1  1  0  1  -1
159
    //  1  1  1  0  +1
160
    //  1  1  1  1  no movement
161
/*
162
  // Simple, easy-to-read "documentation" version :-)
163
  //
164
  void update(void) {
165
    uint8_t s = state & 3;
166
    if (digitalRead(pin1)) s |= 4;
167
    if (digitalRead(pin2)) s |= 8;
168
    switch (s) {
169
      case 0: case 5: case 10: case 15:
170
        break;
171
      case 1: case 7: case 8: case 14:
172
        position++; break;
173
      case 2: case 4: case 11: case 13:
174
        position--; break;
175
      case 3: case 12:
176
        position += 2; break;
177
      default:
178
        position -= 2; break;
179
    }
180
    state = (s >> 2);
181
  }
182
*/
183
184
public:
185
  // update() is not meant to be called from outside Encoder,
186
  // but it is public to allow static interrupt routines.
187
  // DO NOT call update() directly from sketches.
188
  static void update(Encoder_internal_state_t *arg) {
189
#if defined(__AVR__)
190
    // The compiler believes this is just 1 line of code, so
191
    // it will inline this function into each interrupt
192
    // handler.  That's a tiny bit faster, but grows the code.
193
    // Especially when used with ENCODER_OPTIMIZE_INTERRUPTS,
194
    // the inline nature allows the ISR prologue and epilogue
195
    // to only save/restore necessary registers, for very nice
196
    // speed increase.
197
    asm volatile (
198
      "ld  r30, X+"    "\n\t"
199
      "ld  r31, X+"    "\n\t"
200
      "ld  r24, Z"      "\n\t"  // r24 = pin1 input
201
      "ld  r30, X+"    "\n\t"
202
      "ld  r31, X+"    "\n\t"
203
      "ld  r25, Z"      "\n\t"  // r25 = pin2 input
204
      "ld  r30, X+"    "\n\t"  // r30 = pin1 mask
205
      "ld  r31, X+"    "\n\t"  // r31 = pin2 mask
206
      "ld  r22, X"      "\n\t"  // r22 = state
207
      "andi  r22, 3"      "\n\t"
208
      "and  r24, r30"    "\n\t"
209
      "breq  L%=1"      "\n\t"  // if (pin1)
210
      "ori  r22, 4"      "\n\t"  //  state |= 4
211
    "L%=1:"  "and  r25, r31"    "\n\t"
212
      "breq  L%=2"      "\n\t"  // if (pin2)
213
      "ori  r22, 8"      "\n\t"  //  state |= 8
214
    "L%=2:" "ldi  r30, lo8(pm(L%=table))"  "\n\t"
215
      "ldi  r31, hi8(pm(L%=table))"  "\n\t"
216
      "add  r30, r22"    "\n\t"
217
      "adc  r31, __zero_reg__"  "\n\t"
218
      "asr  r22"      "\n\t"
219
      "asr  r22"      "\n\t"
220
      "st  X+, r22"    "\n\t"  // store new state
221
      "ld  r22, X+"    "\n\t"
222
      "ld  r23, X+"    "\n\t"
223
      "ld  r24, X+"    "\n\t"
224
      "ld  r25, X+"    "\n\t"
225
      "ijmp"        "\n\t"  // jumps to update_finishup()
226
      // TODO move this table to another static function,
227
      // so it doesn't get needlessly duplicated.  Easier
228
      // said than done, due to linker issues and inlining
229
    "L%=table:"        "\n\t"
230
      "rjmp  L%=end"      "\n\t"  // 0
231
      "rjmp  L%=plus1"    "\n\t"  // 1
232
      "rjmp  L%=minus1"    "\n\t"  // 2
233
      "rjmp  L%=plus2"    "\n\t"  // 3
234
      "rjmp  L%=minus1"    "\n\t"  // 4
235
      "rjmp  L%=end"      "\n\t"  // 5
236
      "rjmp  L%=minus2"    "\n\t"  // 6
237
      "rjmp  L%=plus1"    "\n\t"  // 7
238
      "rjmp  L%=plus1"    "\n\t"  // 8
239
      "rjmp  L%=minus2"    "\n\t"  // 9
240
      "rjmp  L%=end"      "\n\t"  // 10
241
      "rjmp  L%=minus1"    "\n\t"  // 11
242
      "rjmp  L%=plus2"    "\n\t"  // 12
243
      "rjmp  L%=minus1"    "\n\t"  // 13
244
      "rjmp  L%=plus1"    "\n\t"  // 14
245
      "rjmp  L%=end"      "\n\t"  // 15
246
    "L%=minus2:"        "\n\t"
247
      "subi  r22, 2"      "\n\t"
248
      "sbci  r23, 0"      "\n\t"
249
      "sbci  r24, 0"      "\n\t"
250
      "sbci  r25, 0"      "\n\t"
251
      "rjmp  L%=store"    "\n\t"
252
    "L%=minus1:"        "\n\t"
253
      "subi  r22, 1"      "\n\t"
254
      "sbci  r23, 0"      "\n\t"
255
      "sbci  r24, 0"      "\n\t"
256
      "sbci  r25, 0"      "\n\t"
257
      "rjmp  L%=store"    "\n\t"
258
    "L%=plus2:"        "\n\t"
259
      "subi  r22, 254"    "\n\t"
260
      "rjmp  L%=z"      "\n\t"
261
    "L%=plus1:"        "\n\t"
262
      "subi  r22, 255"    "\n\t"
263
    "L%=z:"  "sbci  r23, 255"    "\n\t"
264
      "sbci  r24, 255"    "\n\t"
265
      "sbci  r25, 255"    "\n\t"
266
    "L%=store:"        "\n\t"
267
      "st  -X, r25"    "\n\t"
268
      "st  -X, r24"    "\n\t"
269
      "st  -X, r23"    "\n\t"
270
      "st  -X, r22"    "\n\t"
271
    "L%=end:"        "\n"
272
    : : "x" (arg) : "r22", "r23", "r24", "r25", "r30", "r31");
273
#else
274
    uint8_t p1val = DIRECT_PIN_READ(arg->pin1_register, arg->pin1_bitmask);
275
    uint8_t p2val = DIRECT_PIN_READ(arg->pin2_register, arg->pin2_bitmask);
276
    uint8_t state = arg->state & 3;
277
    if (p1val) state |= 4;
278
    if (p2val) state |= 8;
279
    arg->state = (state >> 2);
280
    switch (state) {
281
      case 1: case 7: case 8: case 14:
282
        arg->position++;
283
        return;
284
      case 2: case 4: case 11: case 13:
285
        arg->position--;
286
        return;
287
      case 3: case 12:
288
        arg->position += 2;
289
        return;
290
      case 6: case 9:
291
        arg->position -= 2;
292
        return;
293
    }
294
#endif
295
  }
296
private:
297
/*
298
#if defined(__AVR__)
299
  // TODO: this must be a no inline function
300
  // even noinline does not seem to solve difficult
301
  // problems with this.  Oh well, it was only meant
302
  // to shrink code size - there's no performance
303
  // improvement in this, only code size reduction.
304
  __attribute__((noinline)) void update_finishup(void) {
305
    asm volatile (
306
      "ldi  r30, lo8(pm(Ltable))"  "\n\t"
307
      "ldi  r31, hi8(pm(Ltable))"  "\n\t"
308
    "Ltable:"        "\n\t"
309
      "rjmp  L%=end"      "\n\t"  // 0
310
      "rjmp  L%=plus1"    "\n\t"  // 1
311
      "rjmp  L%=minus1"    "\n\t"  // 2
312
      "rjmp  L%=plus2"    "\n\t"  // 3
313
      "rjmp  L%=minus1"    "\n\t"  // 4
314
      "rjmp  L%=end"      "\n\t"  // 5
315
      "rjmp  L%=minus2"    "\n\t"  // 6
316
      "rjmp  L%=plus1"    "\n\t"  // 7
317
      "rjmp  L%=plus1"    "\n\t"  // 8
318
      "rjmp  L%=minus2"    "\n\t"  // 9
319
      "rjmp  L%=end"      "\n\t"  // 10
320
      "rjmp  L%=minus1"    "\n\t"  // 11
321
      "rjmp  L%=plus2"    "\n\t"  // 12
322
      "rjmp  L%=minus1"    "\n\t"  // 13
323
      "rjmp  L%=plus1"    "\n\t"  // 14
324
      "rjmp  L%=end"      "\n\t"  // 15
325
    "L%=minus2:"        "\n\t"
326
      "subi  r22, 2"      "\n\t"
327
      "sbci  r23, 0"      "\n\t"
328
      "sbci  r24, 0"      "\n\t"
329
      "sbci  r25, 0"      "\n\t"
330
      "rjmp  L%=store"    "\n\t"
331
    "L%=minus1:"        "\n\t"
332
      "subi  r22, 1"      "\n\t"
333
      "sbci  r23, 0"      "\n\t"
334
      "sbci  r24, 0"      "\n\t"
335
      "sbci  r25, 0"      "\n\t"
336
      "rjmp  L%=store"    "\n\t"
337
    "L%=plus2:"        "\n\t"
338
      "subi  r22, 254"    "\n\t"
339
      "rjmp  L%=z"      "\n\t"
340
    "L%=plus1:"        "\n\t"
341
      "subi  r22, 255"    "\n\t"
342
    "L%=z:"  "sbci  r23, 255"    "\n\t"
343
      "sbci  r24, 255"    "\n\t"
344
      "sbci  r25, 255"    "\n\t"
345
    "L%=store:"        "\n\t"
346
      "st  -X, r25"    "\n\t"
347
      "st  -X, r24"    "\n\t"
348
      "st  -X, r23"    "\n\t"
349
      "st  -X, r22"    "\n\t"
350
    "L%=end:"        "\n"
351
    : : : "r22", "r23", "r24", "r25", "r30", "r31");
352
  }
353
#endif
354
*/
355
356
357
#ifdef ENCODER_USE_INTERRUPTS
358
  // this giant function is an unfortunate consequence of Arduino's
359
  // attachInterrupt function not supporting any way to pass a pointer
360
  // or other context to the attached function.
361
  static uint8_t attach_interrupt(uint8_t pin, Encoder_internal_state_t *state) {
362
    switch (pin) {
363
    #ifdef CORE_INT0_PIN
364
      case CORE_INT0_PIN:
365
        interruptArgs[0] = state;
366
        attachInterrupt(0, isr0, CHANGE);
367
        break;
368
    #endif
369
    #ifdef CORE_INT1_PIN
370
      case CORE_INT1_PIN:
371
        interruptArgs[1] = state;
372
        attachInterrupt(1, isr1, CHANGE);
373
        break;
374
    #endif
375
    #ifdef CORE_INT2_PIN
376
      case CORE_INT2_PIN:
377
        interruptArgs[2] = state;
378
        attachInterrupt(2, isr2, CHANGE);
379
        break;
380
    #endif
381
    #ifdef CORE_INT3_PIN
382
      case CORE_INT3_PIN:
383
        interruptArgs[3] = state;
384
        attachInterrupt(3, isr3, CHANGE);
385
        break;
386
    #endif
387
    #ifdef CORE_INT4_PIN
388
      case CORE_INT4_PIN:
389
        interruptArgs[4] = state;
390
        attachInterrupt(4, isr4, CHANGE);
391
        break;
392
    #endif
393
    #ifdef CORE_INT5_PIN
394
      case CORE_INT5_PIN:
395
        interruptArgs[5] = state;
396
        attachInterrupt(5, isr5, CHANGE);
397
        break;
398
    #endif
399
    #ifdef CORE_INT6_PIN
400
      case CORE_INT6_PIN:
401
        interruptArgs[6] = state;
402
        attachInterrupt(6, isr6, CHANGE);
403
        break;
404
    #endif
405
    #ifdef CORE_INT7_PIN
406
      case CORE_INT7_PIN:
407
        interruptArgs[7] = state;
408
        attachInterrupt(7, isr7, CHANGE);
409
        break;
410
    #endif
411
    #ifdef CORE_INT8_PIN
412
      case CORE_INT8_PIN:
413
        interruptArgs[8] = state;
414
        attachInterrupt(8, isr8, CHANGE);
415
        break;
416
    #endif
417
    #ifdef CORE_INT9_PIN
418
      case CORE_INT9_PIN:
419
        interruptArgs[9] = state;
420
        attachInterrupt(9, isr9, CHANGE);
421
        break;
422
    #endif
423
    #ifdef CORE_INT10_PIN
424
      case CORE_INT10_PIN:
425
        interruptArgs[10] = state;
426
        attachInterrupt(10, isr10, CHANGE);
427
        break;
428
    #endif
429
    #ifdef CORE_INT11_PIN
430
      case CORE_INT11_PIN:
431
        interruptArgs[11] = state;
432
        attachInterrupt(11, isr11, CHANGE);
433
        break;
434
    #endif
435
    #ifdef CORE_INT12_PIN
436
      case CORE_INT12_PIN:
437
        interruptArgs[12] = state;
438
        attachInterrupt(12, isr12, CHANGE);
439
        break;
440
    #endif
441
    #ifdef CORE_INT13_PIN
442
      case CORE_INT13_PIN:
443
        interruptArgs[13] = state;
444
        attachInterrupt(13, isr13, CHANGE);
445
        break;
446
    #endif
447
    #ifdef CORE_INT14_PIN
448
      case CORE_INT14_PIN:
449
        interruptArgs[14] = state;
450
        attachInterrupt(14, isr14, CHANGE);
451
        break;
452
    #endif
453
    #ifdef CORE_INT15_PIN
454
      case CORE_INT15_PIN:
455
        interruptArgs[15] = state;
456
        attachInterrupt(15, isr15, CHANGE);
457
        break;
458
    #endif
459
    #ifdef CORE_INT16_PIN
460
      case CORE_INT16_PIN:
461
        interruptArgs[16] = state;
462
        attachInterrupt(16, isr16, CHANGE);
463
        break;
464
    #endif
465
    #ifdef CORE_INT17_PIN
466
      case CORE_INT17_PIN:
467
        interruptArgs[17] = state;
468
        attachInterrupt(17, isr17, CHANGE);
469
        break;
470
    #endif
471
    #ifdef CORE_INT18_PIN
472
      case CORE_INT18_PIN:
473
        interruptArgs[18] = state;
474
        attachInterrupt(18, isr18, CHANGE);
475
        break;
476
    #endif
477
    #ifdef CORE_INT19_PIN
478
      case CORE_INT19_PIN:
479
        interruptArgs[19] = state;
480
        attachInterrupt(19, isr19, CHANGE);
481
        break;
482
    #endif
483
    #ifdef CORE_INT20_PIN
484
      case CORE_INT20_PIN:
485
        interruptArgs[20] = state;
486
        attachInterrupt(20, isr20, CHANGE);
487
        break;
488
    #endif
489
    #ifdef CORE_INT21_PIN
490
      case CORE_INT21_PIN:
491
        interruptArgs[21] = state;
492
        attachInterrupt(21, isr21, CHANGE);
493
        break;
494
    #endif
495
    #ifdef CORE_INT22_PIN
496
      case CORE_INT22_PIN:
497
        interruptArgs[22] = state;
498
        attachInterrupt(22, isr22, CHANGE);
499
        break;
500
    #endif
501
    #ifdef CORE_INT23_PIN
502
      case CORE_INT23_PIN:
503
        interruptArgs[23] = state;
504
        attachInterrupt(23, isr23, CHANGE);
505
        break;
506
    #endif
507
    #ifdef CORE_INT24_PIN
508
      case CORE_INT24_PIN:
509
        interruptArgs[24] = state;
510
        attachInterrupt(24, isr24, CHANGE);
511
        break;
512
    #endif
513
    #ifdef CORE_INT25_PIN
514
      case CORE_INT25_PIN:
515
        interruptArgs[25] = state;
516
        attachInterrupt(25, isr25, CHANGE);
517
        break;
518
    #endif
519
    #ifdef CORE_INT26_PIN
520
      case CORE_INT26_PIN:
521
        interruptArgs[26] = state;
522
        attachInterrupt(26, isr26, CHANGE);
523
        break;
524
    #endif
525
    #ifdef CORE_INT27_PIN
526
      case CORE_INT27_PIN:
527
        interruptArgs[27] = state;
528
        attachInterrupt(27, isr27, CHANGE);
529
        break;
530
    #endif
531
    #ifdef CORE_INT28_PIN
532
      case CORE_INT28_PIN:
533
        interruptArgs[28] = state;
534
        attachInterrupt(28, isr28, CHANGE);
535
        break;
536
    #endif
537
    #ifdef CORE_INT29_PIN
538
      case CORE_INT29_PIN:
539
        interruptArgs[29] = state;
540
        attachInterrupt(29, isr29, CHANGE);
541
        break;
542
    #endif
543
544
    #ifdef CORE_INT30_PIN
545
      case CORE_INT30_PIN:
546
        interruptArgs[30] = state;
547
        attachInterrupt(30, isr30, CHANGE);
548
        break;
549
    #endif
550
    #ifdef CORE_INT31_PIN
551
      case CORE_INT31_PIN:
552
        interruptArgs[31] = state;
553
        attachInterrupt(31, isr31, CHANGE);
554
        break;
555
    #endif
556
    #ifdef CORE_INT32_PIN
557
      case CORE_INT32_PIN:
558
        interruptArgs[32] = state;
559
        attachInterrupt(32, isr32, CHANGE);
560
        break;
561
    #endif
562
    #ifdef CORE_INT33_PIN
563
      case CORE_INT33_PIN:
564
        interruptArgs[33] = state;
565
        attachInterrupt(33, isr33, CHANGE);
566
        break;
567
    #endif
568
    #ifdef CORE_INT34_PIN
569
      case CORE_INT34_PIN:
570
        interruptArgs[34] = state;
571
        attachInterrupt(34, isr34, CHANGE);
572
        break;
573
    #endif
574
    #ifdef CORE_INT35_PIN
575
      case CORE_INT35_PIN:
576
        interruptArgs[35] = state;
577
        attachInterrupt(35, isr35, CHANGE);
578
        break;
579
    #endif
580
    #ifdef CORE_INT36_PIN
581
      case CORE_INT36_PIN:
582
        interruptArgs[36] = state;
583
        attachInterrupt(36, isr36, CHANGE);
584
        break;
585
    #endif
586
    #ifdef CORE_INT37_PIN
587
      case CORE_INT37_PIN:
588
        interruptArgs[37] = state;
589
        attachInterrupt(37, isr37, CHANGE);
590
        break;
591
    #endif
592
    #ifdef CORE_INT38_PIN
593
      case CORE_INT38_PIN:
594
        interruptArgs[38] = state;
595
        attachInterrupt(38, isr38, CHANGE);
596
        break;
597
    #endif
598
    #ifdef CORE_INT39_PIN
599
      case CORE_INT39_PIN:
600
        interruptArgs[39] = state;
601
        attachInterrupt(39, isr39, CHANGE);
602
        break;
603
    #endif
604
    #ifdef CORE_INT40_PIN
605
      case CORE_INT40_PIN:
606
        interruptArgs[40] = state;
607
        attachInterrupt(40, isr40, CHANGE);
608
        break;
609
    #endif
610
    #ifdef CORE_INT41_PIN
611
      case CORE_INT41_PIN:
612
        interruptArgs[41] = state;
613
        attachInterrupt(41, isr41, CHANGE);
614
        break;
615
    #endif
616
    #ifdef CORE_INT42_PIN
617
      case CORE_INT42_PIN:
618
        interruptArgs[42] = state;
619
        attachInterrupt(42, isr42, CHANGE);
620
        break;
621
    #endif
622
    #ifdef CORE_INT43_PIN
623
      case CORE_INT43_PIN:
624
        interruptArgs[43] = state;
625
        attachInterrupt(43, isr43, CHANGE);
626
        break;
627
    #endif
628
    #ifdef CORE_INT44_PIN
629
      case CORE_INT44_PIN:
630
        interruptArgs[44] = state;
631
        attachInterrupt(44, isr44, CHANGE);
632
        break;
633
    #endif
634
    #ifdef CORE_INT45_PIN
635
      case CORE_INT45_PIN:
636
        interruptArgs[45] = state;
637
        attachInterrupt(45, isr45, CHANGE);
638
        break;
639
    #endif
640
    #ifdef CORE_INT46_PIN
641
      case CORE_INT46_PIN:
642
        interruptArgs[46] = state;
643
        attachInterrupt(46, isr46, CHANGE);
644
        break;
645
    #endif
646
    #ifdef CORE_INT47_PIN
647
      case CORE_INT47_PIN:
648
        interruptArgs[47] = state;
649
        attachInterrupt(47, isr47, CHANGE);
650
        break;
651
    #endif
652
    #ifdef CORE_INT48_PIN
653
      case CORE_INT48_PIN:
654
        interruptArgs[48] = state;
655
        attachInterrupt(48, isr48, CHANGE);
656
        break;
657
    #endif
658
    #ifdef CORE_INT49_PIN
659
      case CORE_INT49_PIN:
660
        interruptArgs[49] = state;
661
        attachInterrupt(49, isr49, CHANGE);
662
        break;
663
    #endif
664
    #ifdef CORE_INT50_PIN
665
      case CORE_INT50_PIN:
666
        interruptArgs[50] = state;
667
        attachInterrupt(50, isr50, CHANGE);
668
        break;
669
    #endif
670
    #ifdef CORE_INT51_PIN
671
      case CORE_INT51_PIN:
672
        interruptArgs[51] = state;
673
        attachInterrupt(51, isr51, CHANGE);
674
        break;
675
    #endif
676
    #ifdef CORE_INT52_PIN
677
      case CORE_INT52_PIN:
678
        interruptArgs[52] = state;
679
        attachInterrupt(52, isr52, CHANGE);
680
        break;
681
    #endif
682
    #ifdef CORE_INT53_PIN
683
      case CORE_INT53_PIN:
684
        interruptArgs[53] = state;
685
        attachInterrupt(53, isr53, CHANGE);
686
        break;
687
    #endif
688
    #ifdef CORE_INT54_PIN
689
      case CORE_INT54_PIN:
690
        interruptArgs[54] = state;
691
        attachInterrupt(54, isr54, CHANGE);
692
        break;
693
    #endif
694
    #ifdef CORE_INT55_PIN
695
      case CORE_INT55_PIN:
696
        interruptArgs[55] = state;
697
        attachInterrupt(55, isr55, CHANGE);
698
        break;
699
    #endif
700
    #ifdef CORE_INT56_PIN
701
      case CORE_INT56_PIN:
702
        interruptArgs[56] = state;
703
        attachInterrupt(56, isr56, CHANGE);
704
        break;
705
    #endif
706
    #ifdef CORE_INT57_PIN
707
      case CORE_INT57_PIN:
708
        interruptArgs[57] = state;
709
        attachInterrupt(57, isr57, CHANGE);
710
        break;
711
    #endif
712
    #ifdef CORE_INT58_PIN
713
      case CORE_INT58_PIN:
714
        interruptArgs[58] = state;
715
        attachInterrupt(58, isr58, CHANGE);
716
        break;
717
    #endif
718
    #ifdef CORE_INT59_PIN
719
      case CORE_INT59_PIN:
720
        interruptArgs[59] = state;
721
        attachInterrupt(59, isr59, CHANGE);
722
        break;
723
    #endif
724
      default:
725
        return 0;
726
    }
727
    return 1;
728
  }
729
#endif // ENCODER_USE_INTERRUPTS
730
731
732
#if defined(ENCODER_USE_INTERRUPTS) && !defined(ENCODER_OPTIMIZE_INTERRUPTS)
733
  #ifdef CORE_INT0_PIN
734
  static void isr0(void) { update(interruptArgs[0]); }
735
  #endif
736
  #ifdef CORE_INT1_PIN
737
  static void isr1(void) { update(interruptArgs[1]); }
738
  #endif
739
  #ifdef CORE_INT2_PIN
740
  static void isr2(void) { update(interruptArgs[2]); }
741
  #endif
742
  #ifdef CORE_INT3_PIN
743
  static void isr3(void) { update(interruptArgs[3]); }
744
  #endif
745
  #ifdef CORE_INT4_PIN
746
  static void isr4(void) { update(interruptArgs[4]); }
747
  #endif
748
  #ifdef CORE_INT5_PIN
749
  static void isr5(void) { update(interruptArgs[5]); }
750
  #endif
751
  #ifdef CORE_INT6_PIN
752
  static void isr6(void) { update(interruptArgs[6]); }
753
  #endif
754
  #ifdef CORE_INT7_PIN
755
  static void isr7(void) { update(interruptArgs[7]); }
756
  #endif
757
  #ifdef CORE_INT8_PIN
758
  static void isr8(void) { update(interruptArgs[8]); }
759
  #endif
760
  #ifdef CORE_INT9_PIN
761
  static void isr9(void) { update(interruptArgs[9]); }
762
  #endif
763
  #ifdef CORE_INT10_PIN
764
  static void isr10(void) { update(interruptArgs[10]); }
765
  #endif
766
  #ifdef CORE_INT11_PIN
767
  static void isr11(void) { update(interruptArgs[11]); }
768
  #endif
769
  #ifdef CORE_INT12_PIN
770
  static void isr12(void) { update(interruptArgs[12]); }
771
  #endif
772
  #ifdef CORE_INT13_PIN
773
  static void isr13(void) { update(interruptArgs[13]); }
774
  #endif
775
  #ifdef CORE_INT14_PIN
776
  static void isr14(void) { update(interruptArgs[14]); }
777
  #endif
778
  #ifdef CORE_INT15_PIN
779
  static void isr15(void) { update(interruptArgs[15]); }
780
  #endif
781
  #ifdef CORE_INT16_PIN
782
  static void isr16(void) { update(interruptArgs[16]); }
783
  #endif
784
  #ifdef CORE_INT17_PIN
785
  static void isr17(void) { update(interruptArgs[17]); }
786
  #endif
787
  #ifdef CORE_INT18_PIN
788
  static void isr18(void) { update(interruptArgs[18]); }
789
  #endif
790
  #ifdef CORE_INT19_PIN
791
  static void isr19(void) { update(interruptArgs[19]); }
792
  #endif
793
  #ifdef CORE_INT20_PIN
794
  static void isr20(void) { update(interruptArgs[20]); }
795
  #endif
796
  #ifdef CORE_INT21_PIN
797
  static void isr21(void) { update(interruptArgs[21]); }
798
  #endif
799
  #ifdef CORE_INT22_PIN
800
  static void isr22(void) { update(interruptArgs[22]); }
801
  #endif
802
  #ifdef CORE_INT23_PIN
803
  static void isr23(void) { update(interruptArgs[23]); }
804
  #endif
805
  #ifdef CORE_INT24_PIN
806
  static void isr24(void) { update(interruptArgs[24]); }
807
  #endif
808
  #ifdef CORE_INT25_PIN
809
  static void isr25(void) { update(interruptArgs[25]); }
810
  #endif
811
  #ifdef CORE_INT26_PIN
812
  static void isr26(void) { update(interruptArgs[26]); }
813
  #endif
814
  #ifdef CORE_INT27_PIN
815
  static void isr27(void) { update(interruptArgs[27]); }
816
  #endif
817
  #ifdef CORE_INT28_PIN
818
  static void isr28(void) { update(interruptArgs[28]); }
819
  #endif
820
  #ifdef CORE_INT29_PIN
821
  static void isr29(void) { update(interruptArgs[29]); }
822
  #endif
823
  #ifdef CORE_INT30_PIN
824
  static void isr30(void) { update(interruptArgs[30]); }
825
  #endif
826
  #ifdef CORE_INT31_PIN
827
  static void isr31(void) { update(interruptArgs[31]); }
828
  #endif
829
  #ifdef CORE_INT32_PIN
830
  static void isr32(void) { update(interruptArgs[32]); }
831
  #endif
832
  #ifdef CORE_INT33_PIN
833
  static void isr33(void) { update(interruptArgs[33]); }
834
  #endif
835
  #ifdef CORE_INT34_PIN
836
  static void isr34(void) { update(interruptArgs[34]); }
837
  #endif
838
  #ifdef CORE_INT35_PIN
839
  static void isr35(void) { update(interruptArgs[35]); }
840
  #endif
841
  #ifdef CORE_INT36_PIN
842
  static void isr36(void) { update(interruptArgs[36]); }
843
  #endif
844
  #ifdef CORE_INT37_PIN
845
  static void isr37(void) { update(interruptArgs[37]); }
846
  #endif
847
  #ifdef CORE_INT38_PIN
848
  static void isr38(void) { update(interruptArgs[38]); }
849
  #endif
850
  #ifdef CORE_INT39_PIN
851
  static void isr39(void) { update(interruptArgs[39]); }
852
  #endif
853
  #ifdef CORE_INT40_PIN
854
  static void isr40(void) { update(interruptArgs[40]); }
855
  #endif
856
  #ifdef CORE_INT41_PIN
857
  static void isr41(void) { update(interruptArgs[41]); }
858
  #endif
859
  #ifdef CORE_INT42_PIN
860
  static void isr42(void) { update(interruptArgs[42]); }
861
  #endif
862
  #ifdef CORE_INT43_PIN
863
  static void isr43(void) { update(interruptArgs[43]); }
864
  #endif
865
  #ifdef CORE_INT44_PIN
866
  static void isr44(void) { update(interruptArgs[44]); }
867
  #endif
868
  #ifdef CORE_INT45_PIN
869
  static void isr45(void) { update(interruptArgs[45]); }
870
  #endif
871
  #ifdef CORE_INT46_PIN
872
  static void isr46(void) { update(interruptArgs[46]); }
873
  #endif
874
  #ifdef CORE_INT47_PIN
875
  static void isr47(void) { update(interruptArgs[47]); }
876
  #endif
877
  #ifdef CORE_INT48_PIN
878
  static void isr48(void) { update(interruptArgs[48]); }
879
  #endif
880
  #ifdef CORE_INT49_PIN
881
  static void isr49(void) { update(interruptArgs[49]); }
882
  #endif
883
  #ifdef CORE_INT50_PIN
884
  static void isr50(void) { update(interruptArgs[50]); }
885
  #endif
886
  #ifdef CORE_INT51_PIN
887
  static void isr51(void) { update(interruptArgs[51]); }
888
  #endif
889
  #ifdef CORE_INT52_PIN
890
  static void isr52(void) { update(interruptArgs[52]); }
891
  #endif
892
  #ifdef CORE_INT53_PIN
893
  static void isr53(void) { update(interruptArgs[53]); }
894
  #endif
895
  #ifdef CORE_INT54_PIN
896
  static void isr54(void) { update(interruptArgs[54]); }
897
  #endif
898
  #ifdef CORE_INT55_PIN
899
  static void isr55(void) { update(interruptArgs[55]); }
900
  #endif
901
  #ifdef CORE_INT56_PIN
902
  static void isr56(void) { update(interruptArgs[56]); }
903
  #endif
904
  #ifdef CORE_INT57_PIN
905
  static void isr57(void) { update(interruptArgs[57]); }
906
  #endif
907
  #ifdef CORE_INT58_PIN
908
  static void isr58(void) { update(interruptArgs[58]); }
909
  #endif
910
  #ifdef CORE_INT59_PIN
911
  static void isr59(void) { update(interruptArgs[59]); }
912
  #endif
913
#endif
914
};
915
916
#if defined(ENCODER_USE_INTERRUPTS) && defined(ENCODER_OPTIMIZE_INTERRUPTS)
917
#if defined(__AVR__)
918
#if defined(INT0_vect) && CORE_NUM_INTERRUPT > 0
919
ISR(INT0_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(0)]); }
920
#endif
921
#if defined(INT1_vect) && CORE_NUM_INTERRUPT > 1
922
ISR(INT1_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(1)]); }
923
#endif
924
#if defined(INT2_vect) && CORE_NUM_INTERRUPT > 2
925
ISR(INT2_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(2)]); }
926
#endif
927
#if defined(INT3_vect) && CORE_NUM_INTERRUPT > 3
928
ISR(INT3_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(3)]); }
929
#endif
930
#if defined(INT4_vect) && CORE_NUM_INTERRUPT > 4
931
ISR(INT4_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(4)]); }
932
#endif
933
#if defined(INT5_vect) && CORE_NUM_INTERRUPT > 5
934
ISR(INT5_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(5)]); }
935
#endif
936
#if defined(INT6_vect) && CORE_NUM_INTERRUPT > 6
937
ISR(INT6_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(6)]); }
938
#endif
939
#if defined(INT7_vect) && CORE_NUM_INTERRUPT > 7
940
ISR(INT7_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(7)]); }
941
#endif
942
#endif // AVR
943
#if defined(attachInterrupt)
944
// Don't intefere with other libraries or sketch use of attachInterrupt()
945
// https://github.com/PaulStoffregen/Encoder/issues/8
946
#undef attachInterrupt
947
#endif
948
#endif // ENCODER_OPTIMIZE_INTERRUPTS
949
950
951
#endif

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Ich poste euch hier mal die Libary rein

Welchen Teil von

Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

hast Du jetzt nicht verstanden?

von Volker S. (vloki)


Lesenswert?

Alexander S. schrieb:
> Ich poste euch hier mal die Libary rein, vielleicht ist jemand von euch
> so nett und schaut mal drüber und kann mir dann vielleicht sagen welche
> part ich mir mal genauer anschauen könnte.....

Oh je, das sieht nicht gut aus falls der Assembler Teil aktiv sein 
sollte. Könnte man natürlich einfach entsprechend umdefinieren ;-)

Also konkret ist die Auswertung unter der "Zeichnung" für die beiden 
Signale A und B die das Ganze erklären soll. Diese Auswertung ist nicht 
so geeignet für die Teile mit Rasten, welche man mit der Hand dreht, 
weil wie schon weiter oben erwähnt da mehrere Wechsel (bei deinem Geber 
4) pro Raste stattfinden.

Jetzt müsste man die State-mashine entsprechend anpassen oder eine 
andere Bibliothek suchen. Vor einiger Zeit habe ich mal versucht eine 
Auswertung zu schreiben die nicht unbedingt absolut elegant und effektiv 
ist, aber dafür hoffentlich einigermaßen verständlich.
1
typedef enum {
2
    ENC_d4      = -4,   // ENC_DOWN for 1-pulse/1-detent (puls)
3
    ENC_d3      = -3,
4
    ENC_DOWN    = -2,   // ENC_DOWN for 1-pulse/2-detent (toggle)
5
    ENC_d1      = -1,   // ENC_DOWN for quadratur encoder
6
    ENC_IDLE    =  0,
7
    ENC_u1      =  1,   // ENC_UP for quadratur encoder
8
    ENC_UP      =  2,   // ENC_UP for 1-pulse/2-detent (toggle)
9
    ENC_u3      =  3,
10
    ENC_u4      =  4    // ENC_UP for 1-pulse/1-detent (puls)
11
} ENC_STATE;
12
ENC_STATE encState;
13
14
unsigned char encNew, encLast;
15
--------------------------------------------------------------------------
16
    if(INP_POLL_IR){                            // timer IR (i.e. 1000Hz)
17
        if (flags.firstLoop){
18
            encLast = 2 * ENC_A + ENC_B;
19
            encState = ENC_IDLE;
20
            flags.firstLoop = 0;
21
        } else{
22
            encNew = (ENC_A << 1) + ENC_B;
23
            if (encNew != encLast){             // signals changed
24
                if((encNew ^ encLast) == 0b11){ // both signals changed -> ERROR
25
                    flags.encCERR = 1;
26
                }
27
                else {                          // only one signal changed ? OK
28
                    switch(encLast){                    // up   00-10-11-01-00...
29
                        case 0b00:                      // down 00-01-11-10-00...
30
                            if(encNew == 0b10){encState++;}
31
                            else{encState--;} break;
32
                        case 0b10:
33
                            if(encNew == 0b11){encState++;}
34
                            else{ encState--; } break;
35
                        case 0b11:
36
                            if(encNew == 0b01){encState++;}
37
                            else{ encState--; } break;
38
                        case 0b01:
39
                            if(encNew == 0b00){encState++;}
40
                            else{ encState--;} break;
41
                    }
42
                    if(encState == ENC_UP){
43
                        if(flags.encUp){
44
                            flags.encOERR = 1;  // <- breakpoint here
45
                        }
46
                        flags.encUp = 1; encState = ENC_IDLE;
47
                    }
48
                    else if(encState == ENC_DOWN){
49
                        if(flags.encDown){
50
                            flags.encOERR = 1;
51
                        }
52
                        flags.encDown = 1; encState = ENC_IDLE;
53
                    }
54
                }
55
                encLast = encNew;
56
            }
57
        }
58
        mINP_POLL_IR_CLR();
59
        return;
60
    }
Die Auswahl um welchen Typ von Encoder es sich handelt kann man jetzt 
anhand der (Um)Gestaltung des ENUMs ENC_STATE treffen.
(Für einen 20/20 liegen dann UP und DOWN bei +-4)

In dem einfachen Beispiel hier wird für Up und DOWN nur ein Flag 
gesetzt. Genauso könnte man natürlich eine Position inkrementieren 
bzw.dekrementieren.

von m.n. (Gast)


Lesenswert?

Du erwartest zuviel von jemanden, der nicht /4 teilen kann.
Vermutlich Einzelkind.

von Volker S. (vloki)


Lesenswert?

m.n. schrieb:
> Du erwartest zuviel von jemanden, der nicht /4 teilen kann.
> Vermutlich Einzelkind.

;-) Bezieht sich das jetzt auf meinen Beitrag oder den von Rufus?

von m.n. (Gast)


Lesenswert?

Volker S. schrieb:
> ;-) Bezieht sich das jetzt auf meinen Beitrag oder den von Rufus?

Auf den Beitrag von Rufus. Du hattest Dich mit Deiner Antwort einfach 
nur ein paar Millisekunden vorgedrängelt ;-)

von Alexander S. (alexander_s674)


Angehängte Dateien:

Lesenswert?

Also ich habe mir das nochmal in Ruhe angeschaut und mich letztendlich 
dazu entschieden einfach eine andere Bibliothek zu nehmen.
Ich habe eine gefunden die "etwas kürzer" bzw für mich deutlich besser 
zu verstehen ist.
Es klappt auch alles ganz gut. Allerdings habe ich jetzt das Problem das 
auf meinem Display falsche Werte angezeigt werden.
Im Seriellen monitor klappt alles perfekt. Nur die Werte auf dem Display 
stimmen oft nicht.

Ich habe jetzt z.B. das problem das wenn ich von einer dreistelligen 
zahl (zahl > 100) zurück auf eine zweistellige drehe (Zahl =< 100) die 
dritte stelle stehen bleibt. Ich drehe also von z.B. 100 eins runter auf 
99 (steht dann auch so im seriellen monitor) und auf dem Display steht 
990. Drehe ich noch eins weiter habe ich im seriellen Monitor 98 und auf 
dem Display 980.
Wenn ich mich irgendwo im minus bereich bewege ist es auch schon 
passiert das er von einer 4 stelligen minus zahl beim drehen auf eine 3 
stellige minus zahl wieder auf eine 4 stellige minuszahl springt, auch 
hier bleibt dann wieder die letzte stelle stehen.

Das liegt dann aber wohl eher an der libary für das Display?
Obwohl mich das wundert, denn mit der anderen encoder libary ist das 
nicht passiert.
Soll ich dafür besser einen neuen thread erstellen?

 Ich habe im Anhang mal die libary und den code den ich auf den Arduino 
schmeiße.

lg.
- Alex

von Manfred (Gast)


Lesenswert?

Alexander S. schrieb:
> Ich drehe also von z.B. 100 eins runter auf
> 99 (steht dann auch so im seriellen monitor) und auf dem Display steht
> 990. Drehe ich noch eins weiter habe ich im seriellen Monitor 98 und auf
> dem Display 980.
Das ist ein Mikrocontroller und entsprechend doof - Du musst Dich um 
jeden S***** selbst kümmern:

lcd.setCursor(3, 1); // Pos, Line (Vierte Stelle der zweiten Zeile)
lcd.print("    ");   // Leerzeichen schreiben
lcd.setCursor(3, 1); // wieder zur selben Stelle
lcd.print(Deinen_Wert);

(Deine library habe ich nicht angeguckt).

von Wolfgang (Gast)


Lesenswert?

Alexander S. schrieb:
> Ich drehe also von z.B. 100 eins runter auf 99 (steht dann auch so
> im seriellen monitor) und auf dem Display steht 990. Drehe ich noch
> eins weiter habe ich im seriellen Monitor 98 und auf dem Display 980.

Da hat nur jemand die Tafel nicht richtig gewischt.

Die "0" hinter der "99" oder "98" auf dem Display steht da noch von der 
Ausgabe der "100".

von Volker S. (vloki)


Lesenswert?

Manfred schrieb:
> Das ist ein Mikrocontroller und entsprechend doof - Du musst Dich um
> jeden S***** selbst kümmern

Oder die passende Bibliothek suchen! (dauert vermutlich länger ;-)

: Bearbeitet durch User
von Alexander S. (alexander_s674)


Lesenswert?

Okay, vielen Dank für eure Hilfe.
Habt mir echt weitergeholfen.

Die Tafel ist jetzt also richtig "geputzt" und alles sieht so aus wie 
ich mir das vorstelle.

Kommen wir nochmal auf den Encoder zurück. In meinem Speziellen fall 
muss ich ja quasi einen wertebereich vorgeben. Dem Encoder also sagen, 
dass wenn er größer als 359 wird, wieder den wert 1 bekommt.

Ich vermute damit ich ein Funktion wie z.B. setValue benutzen kann, muss 
ich diese in der cpp datei definieren?

Ich habe leider nicht wirklich ahnung von cpp, bin auch nur Hobbyfummler 
am Arduino.
Wenn der encoder eingelesen wird haut der cpp code den wert über die 
variable r raus. Richtig?
Also müsste ich theoretisch nur sagen das wenn die Funktion setValue 
aufgerufen wird diese der var r einen bestimmte wert gibt. Oder?

Kann mir jemand von euch evtl verraten wie ich das bewerkstellige?

Lieber Gruß,
- Alex

von Manfred (Gast)


Lesenswert?

Alexander S. schrieb:
> Die Tafel ist jetzt also richtig "geputzt"
Diese Formulierung von Wolfgang gefällt mir richtig gut - einleuchtend 
und exakt zutreffend.

> Dem Encoder also sagen,
> dass wenn er größer als 359 wird, wieder den wert 1 bekommt.
Der Encoder liefert ja keinen absoluten Wert, sondern nur Impulse. Diese 
Impulse werden in einer Variablen mitgezählt, richtig?

Sollte also genügen, den Wert zu überwachen:

if (Encoder0Pos > 359) {
  Encoder0Pos = 1;
}

von Dieter F. (Gast)


Lesenswert?

Manfred schrieb:
> if (Encoder0Pos > 359) {
>   Encoder0Pos = 1;
> }

Na ja, den kleiner 1 Fall sollte man auch noch betrachten ...

von Route_66 H. (route_66)


Lesenswert?

Alexander S. schrieb:
> dass wenn er größer als 359 wird, wieder den wert 1 bekommt.

Die Position 360 oder 0 Grad ist nicht existent?

von Michael W. (Gast)


Lesenswert?

Manfred schrieb:

> if (Encoder0Pos > 359) {
>   Encoder0Pos = 1;
> }

Da fehlt ein Grad!

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.