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
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.
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.
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
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
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.
Tante Gurgel ist bekannt? http://playground.arduino.cc/Main/RotaryEncoders Oder hier die Erklärung S. 4 rechts http://www.imc-berlin.de/fileadmin/Public/Downloads/Whitepapers/WP_Inkrementalgeber_I.pdf
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
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 ;-)
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 | ...
|
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
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.
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 ;-)
> 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
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 ;-)
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
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" ;-)
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...
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
|
> 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?
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.
Du erwartest zuviel von jemanden, der nicht /4 teilen kann. Vermutlich Einzelkind.
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?
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 ;-)
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
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).
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".
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
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
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; }
Manfred schrieb: > if (Encoder0Pos > 359) { > Encoder0Pos = 1; > } Na ja, den kleiner 1 Fall sollte man auch noch betrachten ...
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.