Ich möchte gerne mittels einem ATMEGA8-16PU jeweils 5 Drehencoder gleichzeitig abfragen. Für einen gibt es ja bereits dieses schöne Beispiel hier: http://www.mikrocontroller.net/articles/Drehgeber Wie muß ich das ganze jedoch erweitern für 5 Stück?
PeDa Lösung einfach 5-mal hintereinander in ISR. Bei akuter Speichernot die 2-Bit Status je Encoder packen (4 in ein Byte). Oder die 4-fach-parallel-Lösung à la PeDa Entprellung (er)finden.
Also am einfachsten in einer Wurst hintereinander setzen:
1 | void encode_init( void ) |
2 | { |
3 | int8_t new1, new2, new3, new4, new5; |
4 | |
5 | new1 = 0; |
6 | if( PHASE_A1 ) |
7 | new1 = 3; |
8 | if( PHASE_B1 ) |
9 | new1 ^= 1; |
10 | last1 = new1; |
11 | enc_delta1 = 0; |
12 | TCCR0 = 1<<WGM01^1<<CS01^1<<CS00; |
13 | OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5); |
14 | TIMSK |= 1<<OCIE0; |
15 | |
16 | new2 = 0; |
17 | if( PHASE_A2 ) |
18 | new2 = 3; |
19 | if( PHASE_B2 ) |
20 | new2 ^= 1; |
21 | last2 = new2; |
22 | enc_delta2 = 0; |
23 | TCCR0 = 1<<WGM01^1<<CS01^1<<CS00; |
24 | OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5); |
25 | TIMSK |= 1<<OCIE0; |
26 | |
27 | new3 = 0; |
28 | if( PHASE_A3 ) |
29 | new3 = 3; |
30 | if( PHASE_B3 ) |
31 | new3 ^= 1; |
32 | last3 = new3; |
33 | enc_delta3 = 0; |
34 | TCCR0 = 1<<WGM01^1<<CS01^1<<CS00; |
35 | OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5); |
36 | TIMSK |= 1<<OCIE0; |
37 | |
38 | new4 = 0; |
39 | if( PHASE_A4 ) |
40 | new1 = 3; |
41 | if( PHASE_B4 ) |
42 | new4 ^= 1; |
43 | last4 = new4; |
44 | enc_delta4 = 0; |
45 | TCCR0 = 1<<WGM01^1<<CS01^1<<CS00; |
46 | OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5); |
47 | TIMSK |= 1<<OCIE0; |
48 | |
49 | new5 = 0; |
50 | if( PHASE_A5 ) |
51 | new5 = 3; |
52 | if( PHASE_B5 ) |
53 | new5 ^= 1; |
54 | last5 = new5; |
55 | enc_delta5 = 0; |
56 | TCCR0 = 1<<WGM01^1<<CS01^1<<CS00; |
57 | OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5); |
58 | TIMSK |= 1<<OCIE0; |
59 | } |
60 | |
61 | |
62 | ISR( TIMER0_COMP_vect ) |
63 | { |
64 | int8_t new1, diff1, new2, diff2, new3, diff3, new4, diff4, new5, diff5, |
65 | |
66 | new1 = 0; |
67 | if( PHASE_A1 ) |
68 | new1 = 3; |
69 | if( PHASE_B1 ) |
70 | new1 ^= 1; |
71 | diff1 = last1 - new1; |
72 | if( diff1 & 1 ){ |
73 | last1 = new1; |
74 | enc_delta1 += (diff1 & 2) - 1; |
75 | } |
76 | |
77 | new2 = 0; |
78 | if( PHASE_A2 ) |
79 | new2 = 3; |
80 | if( PHASE_B2 ) |
81 | new2 ^= 1; |
82 | diff2 = last2 - new2; |
83 | if( diff2 & 1 ){ |
84 | last2 = new2; |
85 | enc_delta2 += (diff2 & 2) - 1; |
86 | } |
87 | |
88 | new3 = 0; |
89 | if( PHASE_A3 ) |
90 | new3 = 3; |
91 | if( PHASE_B3 ) |
92 | new3 ^= 1; |
93 | diff3 = last3 - new3; |
94 | if( diff3 & 1 ){ |
95 | last3 = new3; |
96 | enc_delta3 += (diff3 & 2) - 1; |
97 | } |
98 | |
99 | new4 = 0; |
100 | if( PHASE_A4 ) |
101 | new4 = 3; |
102 | if( PHASE_B4 ) |
103 | new4 ^= 1; |
104 | diff4 = last4 - new4; |
105 | if( diff4 & 1 ){ |
106 | last4 = new4; |
107 | enc_delta4 += (diff4 & 2) - 1; |
108 | } |
109 | |
110 | new5 = 0; |
111 | if( PHASE_A5 ) |
112 | new5 = 3; |
113 | if( PHASE_B5 ) |
114 | new5 ^= 1; |
115 | diff5 = last5 - new5; |
116 | if( diff5 & 1 ){ |
117 | last5 = new5; |
118 | enc_delta5 += (diff5 & 2) - 1; |
119 | } |
120 | } |
121 | |
122 | int8_t encode_read1( void ) |
123 | { |
124 | int8_t val1; |
125 | |
126 | cli(); |
127 | val1 = enc_delta1; |
128 | enc_delta1 = val1 & 1; |
129 | sei(); |
130 | return val1 >> 1; |
131 | } |
132 | |
133 | int8_t encode_read2( void ) |
134 | { |
135 | int8_t val2; |
136 | |
137 | cli(); |
138 | val2 = enc_delta2; |
139 | enc_delta2 = val2 & 1; |
140 | sei(); |
141 | return val2 >> 1; |
142 | } |
143 | |
144 | int8_t encode_read3( void ) |
145 | { |
146 | int8_t val3; |
147 | |
148 | cli(); |
149 | val3 = enc_delta3; |
150 | enc_delta3 = val3 & 1; |
151 | sei(); |
152 | return val3 >> 1; |
153 | } |
154 | |
155 | int8_t encode_read4( void ) |
156 | { |
157 | int8_t val4; |
158 | |
159 | cli(); |
160 | val4 = enc_delta4; |
161 | enc_delta4 = val4 & 1; |
162 | sei(); |
163 | return val4 >> 1; |
164 | } |
165 | |
166 | int8_t encode_read5( void ) |
167 | { |
168 | int8_t val5; |
169 | |
170 | cli(); |
171 | val5 = enc_delta5; |
172 | enc_delta5 = val5 & 1; |
173 | sei(); |
174 | return val5 >> 1; |
175 | } |
Aber ein bischen mitdenken ist schon auch erlaubt Den Teil
1 | TCCR0 = 1<<WGM01^1<<CS01^1<<CS00; |
2 | OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5); |
3 | TIMSK |= 1<<OCIE0; |
brauchst du nicht 5 mal. Einmal den Timer auf den Vorteiler und CTC Modus einstellen, den Compare Wert setzen und den Interrupt freigeben reicht völlig aus. Wenn man schon Code kopiert, sollte man sich zumindest ansehen, was man da kopiert.
Es wäre auch eine gute Übung för den Schööööler, das Ganze auf eine mehrkanalige Auswertung mit einem Array zu erweitern, ohne den Code X-fach zu kopieren. Oder auf Macrobasis. Oder, oder, oder. Copy & Paste ist bäh.
stimmt, der Teil genügt natürlich ein mal. Hab jetzt einfach nur munter drauflos kopiert :)
Hier mal ein Ansatz, ist aber praktisch nicht getestet.
Ich habe mir das Beispiel mal angesehen und würde es gerne als alternative zu meinem anderen Versuch ausprobieren und habe es entsprechend angepasst:
1 | /************************************************************************/
|
2 | /* */
|
3 | /* Reading rotary encoder, multi channel version */
|
4 | /* one, two and four step encoders supported */
|
5 | /* */
|
6 | /* based on Peter Dannegger's example code */
|
7 | /* */
|
8 | /* example for ATmega664, 8 MHz internal clock */
|
9 | /* */
|
10 | /************************************************************************/
|
11 | |
12 | #include <avr/io.h> |
13 | #include <avr/interrupt.h> |
14 | #include "encoder.h" |
15 | |
16 | #define XTAL 8e6 // 8MHz
|
17 | |
18 | #define ENCODER_COUNT 2
|
19 | |
20 | encoder_t encoder_array[ENCODER_COUNT] = { |
21 | // PINx of phase A
|
22 | // | bitmask of phase A
|
23 | // | | PINx of phase B
|
24 | // | | | bitmask of phase B
|
25 | // | | | | high nibble: encoder step size, low nibble internal
|
26 | // | | | | | internal postion
|
27 | // | | | | | |
|
28 | // | | | | | |
|
29 | {&PINC, (1<<PC0), &PINC, (1<<PC1), 0x20 ,0 }, |
30 | {&PINC, (1<<PC3), &PINC, (1<<PC4), 0x20 ,0 }, |
31 | };
|
32 | |
33 | // positions of encoders for normal use in main loop and functions
|
34 | int16_t encoder_position[ENCODER_COUNT]; |
35 | |
36 | // 1ms timer ISR, sufficient for manual movement
|
37 | |
38 | ISR( TIMER0_COMPA_vect ) { |
39 | |
40 | encoder_process(encoder_array, ENCODER_COUNT); |
41 | }
|
42 | |
43 | int main( void ) { |
44 | |
45 | // init a timer
|
46 | |
47 | TCCR0A = (1<<WGM01); |
48 | OCR0A = (uint8_t)(F_CPU / 64.0 * 1e-3 - 0.5); |
49 | TCCR0B = (1<<CS01 | 1<<CS00); |
50 | TIMSK0 = (1<<OCIE0A); |
51 | |
52 | DDRA = 0xFF; // init test port, diplay valu with LEDs |
53 | PORTC = 0xFF; // init test port, pull Ups on |
54 | |
55 | encoder_init(encoder_array, ENCODER_COUNT); |
56 | sei(); |
57 | |
58 | while(1){ |
59 | encoder_read_all(encoder_array, ENCODER_COUNT, encoder_position); // read all encoders |
60 | PORTA = encoder_position[0]; |
61 | PORTA = encoder_position[1]; |
62 | }
|
63 | }
|
Das funktioniert auch soweit. Allerdings habe ich bei mir die Situation, das ich pro Port unterschiedliche LED's von mehreren Encoder anzeigen möchte. Also die ersten 4 PIN's vom ersten Encoder, die nächsten 2 PIN's vom zweiten Encoder, usw. Ich muß die Ports also unterteilen. Wie macht ich das am besten?
>Ich muß die Ports also unterteilen. >Wie macht ich das am besten? Exakt genau so, wie es dieses Beispiel macht, nur mit dem Unterschied, dass du Ports schreibst anstatt zu lesen. Siehe Bitmanipulation.
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.