Encoder mit ATMEGA8

#2163460
Lesenswert?

Kann mir jemand ein einfaches Beispiel geben wie man in C mit einem 
ATMEGA8 einen Encoder auswertet?

Das Beispiel hier: http://www.mikrocontroller.net/articles/Drehgeber ist 
zwar recht nett, bezieht sich aber leider auf einen ATMEGA16. Und dort 
sind ja wieder andere Interrupts vorhanden.
#2164456
Lesenswert?

Ich habe die Datenbläter der beiden AVR's jetzt mal verglichen und den 
Code dementsprechend angepasst.
Wenn ich es richtig verstanden habe sollte das so korrekt sein:
1
#define XTAL        8e6         // 8MHz
2
 
3
#define PHASE_A     (PINC & 1<<PC0)
4
#define PHASE_B     (PINC & 1<<PC1)
5
 
6
#define LEDS_DDR    DDRD
7
#define LEDS        PORTD           // LEDs against VCC
8
 
9
 
10
volatile int8_t enc_delta;          // -128 ... 127
11
static int8_t last;
12
 
13
 
14
void encode_init( void )
15
{
16
  int8_t new;
17
 
18
  new = 0;
19
  if( PHASE_A )
20
    new = 3;
21
  if( PHASE_B )
22
    new ^= 1;                   // convert gray to binary
23
  last = new;                   // power on state
24
  enc_delta = 0;
25
  TCCR2 = 1<<WGM20^1<<CS01^1<<CS00;     // CTC, XTAL / 64
26
  OCR2 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);   // 1ms
27
  TIMSK |= 1<<OCIE2;
28
}

Wäre das korrekt?

PINC & 1<<PC0 sagt aus das am Eingang PC0 ein HI erwartet wird? Ich muß 
den Encoder also mit VCC ansteuern, richtig?
Gast #2167748
Lesenswert?

> Wäre das korrekt?
Fast OK, aber nicht komplett zu Ende gedacht.

Atmega16                  Atmega8
================================================================
Timer0 8-Bit              Timer0 8-Bit
XTAL 8 MHz                XTAL 8 MHz möglich (extern und intern)
Modus WGM01 (CTC)         Modus WGM01 (CTC) nicht möglich
                          deshalb z.B. Wechsel auf Timer2 8-Bit

TIMER0_COMP_vect          TIMER2_COMP_vect
OCIE0                     OCIE2
OCR0                      OCR2
TCCR0                     TCCR2 = 1<<WGM21^1<<CS22; // CTC2, Prescaler 
64

D.h. die Änderungen sind auf vier Zeilen begrenzt
1
ISR(TIMER2_COMP_vect)
2
{
3
 ...
4
}
5

6
  ...
7
  TCCR2 = 1<<WGM21^1<<CS22; // CTC2, Prescaler 64
8
  OCR2 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);   // 1ms
9
  TIMSK |= 1<<OCIE2;
10
}

Statt WGM21 hast du WGM20 bei TCCR2 gesetzt, das passt nicht.

Bei den Signalleitungen kannst du mit der Atmega16 Belegung arbeiten

Atmega16                               Atmega8
================================================================
#define PHASE_A  (PINC & 1<<PC0)       PC0 vorhanden
#define PHASE_B  (PINC & 1<<PC1)       PC1 vorhanden
#define LEDS_DDR DDRD
#define LEDS     PORTD                 PDx vorhanden
#2168384
Lesenswert?

Danke erstmal!
Ich bräuchte jedoch nochmal eure Hilfe.

An den ATMEGA8 hängt nun ein LCD-Display drann das mir den Wert des 
Encoders ausgeben soll.
Der Encoder ist ein ALPS STEC11B03 (15 Pulse/30 Rasterungen) Dieser 
hängt an PC0 und PC1.

Die LCD-Ausgabe erfolgt mit der Lib von Peter Fleury.
(Diese ist nur schnell mal zusammengeschustert)

Leider tut sich beim drehen so gut wie gar nichts. Nur hin und wieder 
zuckt ein neuer Wert übers LCD daher.

1
/************************************************************************/
2
/*                                                                      */
3
/*            Reading rotary encoder                                    */
4
/*            one, two and four step encoders supported                 */
5
/*                                                                      */
6
/*             Author: Peter Dannegger                                  */
7
/*                                                                      */
8
/************************************************************************/
9
#include <stdlib.h>
10
#include <avr/io.h>
11
#include "lcd.h"
12
#include <avr/interrupt.h>
13

14
// target: ATmega8
15
//------------------------------------------------------------------------
16

17
#define XTAL2    8e6              // 8MHz
18

19
#define PHASE_A    (PINC & 1<<PC0)
20
#define PHASE_B    (PINC & 1<<PC1)
21

22
volatile int8_t enc_delta;            // -128 ... 127
23
static int8_t last;
24

25
void encode_init(void)
26
{
27
  int8_t new;
28

29
  new = 0;
30
  if(PHASE_A)
31
    new = 3;
32
  if(PHASE_B)
33
    new ^= 1;                // convert gray to binary
34
  last = new;                  // power on state
35
  enc_delta = 0;
36
  TCCR2 = 1<<WGM21^1<<CS22;          // CTC2, Prescaler 64
37
  OCR2 = (uint8_t)(XTAL2 / 64.0 * 1e-3 - 0.5);  // 1ms
38
  TIMSK |= 1<<OCIE2;
39
;
40
}
41

42
ISR(TIMER2_COMP_vect)              // 1ms for manual movement
43
{
44
  int8_t new, diff;
45

46
  new = 0;
47
  if(PHASE_A)
48
    new = 3;
49
  if(PHASE_B)
50
    new ^= 1;                // convert gray to binary
51
  diff = last - new;              // difference last - new
52
  if(diff & 1)
53
  {                      // 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
int8_t encode_read(void)            // read single step encoders
60
{
61
  int8_t val;
62
 
63
  cli();
64
  val = enc_delta;
65
  enc_delta = 0;
66
  sei();
67
  return val;                   // counts since last call
68

69
}
70

71
int main(void)
72
{
73
  int32_t val = 0;
74
  char buffer[7];
75

76
  encode_init();
77
  sei();
78
  lcd_init(LCD_DISP_ON);
79

80
  for(;;)
81
  {
82
    val += encode_read();
83
    itoa(val, buffer, 10);   // convert interger into string
84
    lcd_clrscr();            // clear display home cursor
85
    lcd_puts(buffer);        // put converted string to display
86
  }
87
}
Gast #2168680
Lesenswert?

> Ich bekomme maximal ein -1 aufs LCD.

itoa bei einem int32_t val ist nix.

Nimm ltoa 
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#ga1d4c7b84110553544081a69a0fc49c52

>   char buffer[7];

Ist für eine long (int32_t) Zahl potentiell zu klein und das 
Damoklesschwert Bufferoverflow schwebt über dem Programm. Der Puffer 
sollte 12 Zeichen groß sein.

Ich würde die LCD Ausgabe puffern, d.h. nur Löschen und Ausgeben, wenn 
sich der Anzeigewert geändert hat.
1
  val = 0;
2
  for(;;)
3
  {
4
    static int32_t last_val = 256;
5
    val += encode_read();
6
    if ( val != last_val ) { 
7
      last_val = val;
8
      itoa(val, buffer, 10);   // convert interger into string
9
      lcd_clrscr();            // clear display home cursor
10
      lcd_puts(buffer);        // put converted string to display
11
    }
12
  }
#2169261
Lesenswert?

Es ist zum verzweifeln. Das Ding läuft immer noch nicht.
Im Prinzip hat sich zu dem davor nicht viel geändert.

Die Variable "val" zuckt von selbst sporadisch zwischen 0 und 1 oder -1 
herum.
Das drehen am Encoder bewirkt gar nichts.

Liegts vielleicht daran das der Encoder bei mir auf beide ADC hängt?
Oder macht das keinen Unterschied?

Er reagiert einfach nicht.
Gast #2169391
Lesenswert?

Die I/O-Pins PC1 und PC0 arbeiten laut Programm oben nicht als ADC Pins, 
sondern als normale digitale Eingangspins.

Wie hast du den Encoder ALPS STEC11B03 (Conrad 700697) angeschlossen, 
so?
1
                 Vcc
2
                  |
3
               +--+--+
4
               |     |
5
               # 5K  |
6
               |     |
7
PC0 o----------o     |
8
               A     |
9
                     # 5K
10
                     |
11
PC1 o----------------o 
12
                     B
13

14
GND o-----o
15
          C
16

17
ARef o
18
     |
19
    === 100 nF
20
     |
21
AGND o----o GND
22
     |
23
    === 100 nF
24
     |
25
AVcc o----o Vcc

Kannst du mit dem Multimeter beim langsamen Drehen des Encoders und PLUS 
des Multimeters an den Pins PC0 oder PC1 und MINUS des Multimeters an 
GND eine mit der Drehung alternierende Spannung (<1.5V bzw. >3.5V) 
messen?
#2169622
Lesenswert?

Super, danke.
Noch eine Frage zu dem ursprünglichen Beispiel: 
http://www.mikrocontroller.net/articles/Drehgeber

Hier werden mittels dem Encoder LED's angesteuert, die gegen VCC 
geschalten sind.

Muß man, damit das funktioniert den val-Wert nicht in einen Integer 
umwandeln?

Und warum schaltet man die LED's überhaupt im Ruhezustand gegen VCC?
Gast #2169662
Lesenswert?

> Muß man, damit das funktioniert den val-Wert nicht in einen Integer
> umwandeln?

val ist doch ein Integer. Allerdings 32 Bit breit (int32_t). Wenn auf 
die 8 LEDs von PortD ausgegeben wird, findet in der Zeile

LEDS = val;

ein impliziter Cast (=> C Grundlagen) statt indem int32_t nach int8_t 
gewandelt wird. Es werden nur die unteren 8 Bits (0 bis 7) zugewiesen 
und die restlichen Bits (8 bis 31) werden verworfen.

> Und warum schaltet man die LED's überhaupt im Ruhezustand gegen VCC?

Ist hier eher Geschmackssache ob man eine active high oder eine active 
low (hier) Schaltung der LEDs macht. Die Varianten sind im AVR Tutorial 
erklärt. Historisch gibt es µC (ICs) die besser als Stromsenke (Sink) 
arbeiten statt als Stromquelle (Source). Bei denen ist die Schaltung 
gegen Vcc sinnvoller.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren