Forum: Mikrocontroller und Digitale Elektronik encoder STEC12E08


von wolfgang (Gast)


Lesenswert?

Hallo,
Ich nutze die Encoder-Funktion von Peter Dannegger zusammen mit einem
Drehencoder vo Reichelt,Aber leider zählt er nicht richtig,pro Rastung 
sind manchmal Sprünge von 100 drin.
Den Encoder-Wert gebe ich erstmal nur zum Terminal aus.
kann mir da einer Weiterhelfen
mfg

Leider kann ich das Datenblatt nicht Anhängen
1
/************************************************************************/
2
/*                                                                      */
3
/*                      Reading rotary encoder                     */
4
/*                      one, two and four step encoders supported  */
5
/*                                                                      */
6
/*              Author: Peter Dannegger                                 */
7
/*                                                                      */
8
/************************************************************************/
9
#include <avr\io.h>
10
#include <avr\interrupt.h>
11
12
        // target: ATmega16
13
//------------------------------------------------------------------------
14
15
#define  XTAL    8e6      // 8MHz
16
17
#define PHASE_A    (PINA & 1<<PA1)
18
#define PHASE_B    (PINA & 1<<PA3)
19
20
21
22
23
int8_t enc_delta;        // -128 ... 127
24
 uint8_t sec = 0;
25
26
void encode_init( void )
27
{
28
  TCCR0 = 1<<WGM01^1<<CS01^1<<CS00;    // CTC, XTAL / 64
29
  OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);  // 1ms
30
  TIMSK |= 1<<OCIE0;
31
}
32
33
34
ISR( TIMER0_COMP_vect )        // 1ms for manual movement
35
{
36
  static int8_t last;
37
  int8_t new, diff;
38
39
  new = 0;
40
  if( PHASE_A )
41
    new = 3;
42
  if( PHASE_B )
43
    new ^= 1;          // convert gray to binary
44
  diff = last - new;        // difference last - new
45
  if( diff & 1 ){        // bit 0 = value (1)
46
    last = new;          // store new as next last
47
    enc_delta += (diff & 2) - 1;    // bit 1 = direction (+/-)
48
  }
49
}
50
51
52
int8_t encode_read1( void )      // read single step encoders
53
{
54
  int8_t val;
55
56
  cli();
57
  val = enc_delta;
58
  enc_delta = 0;
59
  sei();
60
  return val;          // counts since last call
61
}
62
63
64
int8_t encode_read2( void )      // read two step encoders
65
{
66
  int8_t val;
67
68
  cli();
69
  val = enc_delta;
70
  enc_delta &= 1;
71
  sei();
72
  return val >> 1;
73
}
74
75
76
int8_t encode_read4( void )      // read four step encoders
77
{
78
  int8_t val;
79
80
  cli();
81
  val = enc_delta;
82
  enc_delta &= 3;
83
  sei();
84
  return val >> 2;
85
}
86
87
88
int main( void )
89
{
90
  int32_t val = 0;
91
  char encBuffer[10];
92
  encode_init();
93
  sei();
94
95
  for(;;){
96
97
   val += encode_read1();
98
99
  if(val > 0){
100
    val--;
101
    sec--;
102
  }else if(val < 0){
103
    val++;
104
    sec++;
105
   sprintf( encBuffer, "%3d", sec );
106
   uart_puts( encBuffer );    
107
  }
108
}

von Falk B. (falk)


Lesenswert?

@wolfgang (Gast)

>Ich nutze die Encoder-Funktion von Peter Dannegger zusammen mit einem

Wirklich? Ich glaube da fehtl ein volatile.

1
volatile int8_t enc_delta;        // -128 ... 127


MFG
Falk

von Falk B. (falk)


Lesenswert?

http://www.mikrocontroller.net/articles/Drehgeber#Solide_L.C3.B6sung:_Beispielcode_in_C

Selber schuld, wenn man den Code abtippt, anstatt ihr einfach 1:1 zu 
kopieren.

von Chris (Gast)


Lesenswert?

Kopieren statt Kapieren ,und dann noch Falsch Kopiert ;)

von wolfgang (Gast)


Lesenswert?

Falk Brunner schrieb:
> Ich glaube da fehtl ein volatile int8_t enc_delta;
steht bei mir im code drin.
aber Trotzdem zählt er in zu grossen schritten und auch nicht in jeder 
rastung.
mfg

von Falk B. (falk)


Lesenswert?

@  wolfgang (Gast)

>> Ich glaube da fehtl ein volatile int8_t enc_delta;
>steht bei mir im code drin.

WAS? Und wieso nicht in dem geposteten Quelltext? Sowas kopiert man 
IMMER 1:1 und tippt NICHTS ab! Lies mal was über Netiquette!

MfG
Falk

von Jens (Gast)


Lesenswert?

Na Falk, jetzt nicht mehr Bildformate sondern Netiquette? Ist das 
überhaupt ein Wort?

>>Selber schuld, wenn man den Code abtippt, anstatt ihr einfach 1:1 zu
>>kopieren.<<

Wer anderen eine Grube gräbt. Mann soll also nett sein und sich auch 
noch dumm belehren lassen - was ist hier nur los?
Komm mal langsam wieder runter - das kommt davon wenn man hier zu lange 
im Forum ist, das macht krank!

@Wolfgang
Wenn er teilweise springt oder 2 Schritte zählt, liegt das an den 
mechanischen Rastungen. Du solltest dann mal den code mit Tabelle 
nutzen. Steht auch im tutotrial.

Hast du den code aus dem Tut oder aus dem Thread? Lies mal das tut.

Gruß,
JJ

PS.: wo das springen um 100 her kommt, kann ich nun aus dem stehgreif 
auch nicht sagen, bedenke dass der Zähler vorzeichenbehaftet ist!

von wolfgang (Gast)


Lesenswert?

Ja da ist mir wohl ein Fehler unterlaufen,
Hab mir den code von hier 
http://www.mikrocontroller.net/articles/Drehgeber#...
nochmal geladen aber mein Encoder zählt immer noch Falsch
mfg

von Martin H. (martin_h85)


Lesenswert?

Guten Morgen,

wenn du den Quelltext richtig kopiert hast und er funktioniert immer 
noch nicht wie erwartet guck dir doch mal deinen Hardware Aufbau an.
Bei Längeren Kabeln können Pullup Widerstände helfen.


Gruß Martin

von Jens (Gast)


Lesenswert?


von wolfgang (Gast)


Lesenswert?

Die Hardware Funktioniert,Pull-Ups habe ich aktiviert trozdem hauts 
nicht hin.

1
************************************************************************/
2
/*                                                                      */
3
/*                      Reading rotary encoder                      */
4
/*                      one, two and four step encoders supported   */
5
/*                                                                      */
6
/*              Author: Peter Dannegger                                 */
7
/*                                                                      */
8
/************************************************************************/
9
#include <avr/io.h>
10
#include <avr/interrupt.h>
11
#include "uart.h"
12
                // target: ATmega16
13
//------------------------------------------------------------------------
14
 
15
#define XTAL        8e6         // 8MHz
16
 
17
#define PHASE_A     (PINA & 1<<PA1)
18
#define PHASE_B     (PINA & 1<<PA3)
19
 
20
 
21
volatile uint8_t sec ;  
22
volatile int8_t enc_delta;          // -128 ... 127
23
static int8_t last;
24
 
25
 
26
void encode_init( void )
27
{
28
  int8_t new;
29
 
30
  new = 0;
31
  if( PHASE_A )
32
    new = 3;
33
  if( PHASE_B )
34
    new ^= 1;                   // convert gray to binary
35
  last = new;                   // power on state
36
  enc_delta = 0;
37
  TCCR0 = 1<<WGM01^1<<CS01^1<<CS00;     // CTC, XTAL / 64
38
  OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);   // 1ms
39
  TIMSK |= 1<<OCIE0;
40
}
41
 
42
 
43
ISR( TIMER0_COMP_vect )             // 1ms for manual movement
44
{
45
  int8_t new, diff;
46
 
47
  new = 0;
48
  if( PHASE_A )
49
    new = 3;
50
  if( PHASE_B )
51
    new ^= 1;                   // convert gray to binary
52
  diff = last - new;                // difference last - new
53
  if( diff & 1 ){               // bit 0 = value (1)
54
    last = new;                 // store new as next last
55
    enc_delta += (diff & 2) - 1;        // bit 1 = direction (+/-)
56
  }
57
}
58
 
59
 
60
int8_t encode_read1( void )         // read single step encoders
61
{
62
  int8_t val;
63
 
64
  cli();
65
  val = enc_delta;
66
  enc_delta = 0;
67
  sei();
68
  return val;                   // counts since last call
69
}
70
 
71
 
72
int8_t encode_read2( void )         // read two step encoders
73
{
74
  int8_t val;
75
 
76
  cli();
77
  val = enc_delta;
78
  enc_delta = val & 1;
79
  sei();
80
  return val >> 1;
81
}
82
 
83
 
84
int8_t encode_read4( void )         // read four step encoders
85
{
86
  int8_t val;
87
 
88
  cli();
89
  val = enc_delta;
90
  enc_delta = val & 3;
91
  sei();
92
  return val >> 2;
93
}
94
 
95
 
96
int main( void )
97
{
98
  int32_t val = 0;
99
 char encBuffer[10];
100
 //Pull-Up einschalten
101
  DDRA  &= ~(1<<PHASE_A);  
102
  PORTA |= (1<<PHASE_A);   
103
  DDRA  &= ~(1<<PHASE_B);  
104
  PORTA |= (1<<PHASE_B);   
105
  encode_init();
106
  sei();
107
 
108
  for(;;){
109
  val += encode_read1();
110
111
  if(val > 0){
112
    val--;
113
    sec--;
114
115
  }  else if(val < 0){
116
     val++;
117
     sec++;
118
119
 }
120
 
121
  sprintf( encBuffer, "%3d", sec );
122
  uart_puts( encBuffer );  }
123
}

von Falk B. (falk)


Lesenswert?

@  wolfgang (Gast)

>Die Hardware Funktioniert,Pull-Ups habe ich aktiviert

Nö.


>#define PHASE_A     (PINA & 1<<PA1)
>#define PHASE_B     (PINA & 1<<PA3)

> //Pull-Up einschalten
>  DDRA  &= ~(1<<PHASE_A);
>  PORTA |= (1<<PHASE_A);
>  DDRA  &= ~(1<<PHASE_B);
>  PORTA |= (1<<PHASE_B);

besser so.

1
  // Inputs
2
  DDRA  &= !((1<<PA1) | (1<<PA3));  
3
  PORTA |= (1<<PA1) | (1<<PA3);

Siehe auch Bitmanipulation. Hier ist leider eine Mischung aus den 
Bitdefinitionen drin.

http://www.mikrocontroller.net/articles/Bitmanipulation#Bitmanipulation_beim_MSP430

MFG
Falk

von Jens (Gast)


Lesenswert?

aus dem Artikel:

Im wahren Leben gibt es immer wieder Dinge, welche der Theorie zwar 
widersprechen, dennoch weit verbreitet sind. Da machen Drehgeber keine 
Ausnahme. Gerade die heute so beliebten Drehgeber für manuelle Bedienung 
sind in großer Anzahl von verschiedenen Herstellern verfügbar. Umso 
merkwürdiger ist es, dass hier die Rastpunkte oft genau auf dem 
Pegelwechsel einer Spur liegen, meist Spur B. So zum Beispiel beim 
Drehgeber EC11E15244B2 von Alps, welcher u.a bei Pollin ehältlich ist.

Bei diesem Drehgeber kommt es bei der klassischen, eigentlich soliden 
Auswertung zu dem Effekt, dass der Drehgeber in Ruhelage auf einem 
Rastpunkt pendeln kann. Damit erhält das Programm sporadisch einen 
Schritt vor und zurück. Auch wenn sich die Auswertung daran nicht 
verschluckt, so ist dieses Pendeln doch ärgerlich, denn eine 
Menusteuerung würde dann komische Sachen machen.


Schau dir mal das zweite Codeposting mit dieser:

int8_t table[16] PROGMEM = {0,0,-1,0,0,0,0,1,1,0,0,0,0,-1,0,0};

Tabelle an.

Springt er um 100 oder vielleicht 127? Wie sieht deine Konvertierung von 
int8 auf die serielle ss aus?

JJ

von Peter D. (peda)


Lesenswert?

Falk Brunner schrieb:
> besser so.
>
>   // Inputs
>   DDRA  &= !((1<<PA1) | (1<<PA3));
>   PORTA |= (1<<PA1) | (1<<PA3);

Warum sind 4 Bytes mehr Code besser?
Und außerdem ist das falsch.
Der ! Operator liefert nur 0 oder 1.


Peter

von Peter D. (peda)


Lesenswert?

wolfgang schrieb:
> Aber leider zählt er nicht richtig,pro Rastung
> sind manchmal Sprünge von 100 drin.

Das glaube ich Dir nicht. Wo soll die 100 denn herkommen?
Vermutlich ein Ablesefehler, da Du die Ausgaben ohne einen Trenner 
aneinander reihst.
Versuch mal:
1
  sprintf( encBuffer, "%4d\n", sec );
2
  _delay_ms( 200 );

Rastende Enkoder machen 2 oder 4 Phasenwechsel, nimm also die dazu 
passende Auslesefunktion.


Peter

von Falk B. (falk)


Lesenswert?

@  Peter Dannegger (peda)

>Warum sind 4 Bytes mehr Code besser?

Lies mal das Original vom OP. Dort wird doppelt gemoppelt Bits 
geschoben, nicht wirklich im Sin des Erfinders.

>Und außerdem ist das falsch.
>Der ! Operator liefert nur 0 oder 1.

Jaja, Flüchtigkeitsfehler.

1
   DDRA  &= ~((1<<PA1) | (1<<PA3));
2
   PORTA |= (1<<PA1) | (1<<PA3);

MFG
Falk

von Peter D. (peda)


Lesenswert?

Falk Brunner schrieb:
> Lies mal das Original vom OP. Dort wird doppelt gemoppelt Bits
> geschoben, nicht wirklich im Sin des Erfinders.

Ja, der ist schlichtweg falsch.
Richtig:
1
 //Pull-Up einschalten
2
  DDRA  &= ~(1<<PA1);  
3
  PORTA |= (1<<PA1);   
4
  DDRA  &= ~(1<<PA3);  
5
  PORTA |= (1<<PA3);

Dann sinds 2 CBI und 2 SBI, also 2 Befehle gespart gegenüber IN+ORI+OUT, 
IN+ANDI+OUT.


Peter

von wolfgang (Gast)


Lesenswert?

Guten Morgen
Vielen Dank für eure Hilfe und es lag bei mir doch am Aufbau.
Wenn ich 2Encoder auswerten will muss ich doch für den zweiten Encoder 
alle Routienen einen anderen Namen geben auch die im Interrupr, oder bin 
ich da jetz falsch.
mfg

von Falk B. (falk)


Lesenswert?

@wolfgang (Gast)

>Wenn ich 2Encoder auswerten will muss ich doch für den zweiten Encoder
>alle Routienen einen anderen Namen geben auch die im Interrupr,

Ja.

MfG
Falk

von Jens (Gast)


Lesenswert?

...au man...

JJ

von Jens (Gast)


Lesenswert?

>>mit einem Drehencoder<<

so viel zum Thema, die Antworten können nur maximal so präzise sein, wie 
die Informationen der Problemstellung...

Na zumindest läufts dann ja jetzt...

JJ

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.