Forum: Mikrocontroller und Digitale Elektronik Mehrere Drehencoder gleichzeitig abfragen


von Lokus P. (derschatten)


Lesenswert?

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?

von Bastler (Gast)


Lesenswert?

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.

von Lokus P. (derschatten)


Lesenswert?

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
}

von Karl H. (kbuchegg)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Lokus P. (derschatten)


Lesenswert?

stimmt, der Teil genügt natürlich ein mal.
Hab jetzt einfach nur munter drauflos kopiert :)

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Hier mal ein Ansatz, ist aber praktisch nicht getestet.

von Lokus P. (derschatten)


Lesenswert?

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?

von Falk B. (falk)


Lesenswert?

>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
Noch kein Account? Hier anmelden.