Forum: Mikrocontroller und Digitale Elektronik Drehgeber auslesen


von Tim D. (Gast)


Lesenswert?

Hi, erneut habe ich ein paar Frage. Denkt nicht das ich zu faul bin und 
alles machen lassen möchte ;), aber nach mehreren Stunden bin ich leider 
immer noch zu keinem vernüftigen Lösungsansatz gekommen.

Ich habe hier das solide Programm von dieser Seite um einen Drehgeber 
auszuwerten. Ich nutze zwar einen Atmega 32 aber sobald ich die Eingänge 
änder sollte dies ja kein Problem darstellen. Allerdings verstehe ich 
nicht was hier genau mit single step encoders und two step encoders usw. 
gemeint ist.

Zudem steht unten im Hauptprogramm: " LEDS = val " - was passiert hier, 
kann man den Ports einen Wert außer 1 und 0 übergeben?

Ich würde zum Test simpel eine  LED zum leuchten bringen, ab 5000 
Impulsen quasi, habe aber leider keine Idee wie ich das lösen könnte.
Mein erster Ansatz war eine IF Anweisung in den main Teil zu bringen. 
IF(val>=5000) schalte PORTA eine LED. Funkzt aber nicht.


Kann mir da wer Weiter helfen?

Hier das Programm von dem ich ausgehen möchte
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
 
4
                // target: ATmega16
5
//------------------------------------------------------------------------
6
 
7
#define XTAL        8e6         // 8MHz
8
 
9
#define PHASE_A     (PINA & 1<<PA1)
10
#define PHASE_B     (PINA & 1<<PA3)
11
 
12
#define LEDS_DDR    DDRC
13
#define LEDS        PORTC           // LEDs against VCC
14
 
15
 
16
volatile int8_t enc_delta;          // -128 ... 127
17
static int8_t last;
18
 
19
 
20
void encode_init( void )
21
{
22
  int8_t new;
23
 
24
  new = 0;
25
  if( PHASE_A )
26
    new = 3;
27
  if( PHASE_B )
28
    new ^= 1;                   // convert gray to binary
29
  last = new;                   // power on state
30
  enc_delta = 0;
31
  TCCR0 = 1<<WGM01^1<<CS01^1<<CS00;     // CTC, XTAL / 64
32
  OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);   // 1ms
33
  TIMSK |= 1<<OCIE0;
34
}
35
 
36
 
37
ISR( TIMER0_COMP_vect )             // 1ms for manual movement
38
{
39
  int8_t new, diff;
40
 
41
  new = 0;
42
  if( PHASE_A )
43
    new = 3;
44
  if( PHASE_B )
45
    new ^= 1;                   // convert gray to binary
46
  diff = last - new;                // difference last - new
47
  if( diff & 1 ){               // bit 0 = value (1)
48
    last = new;                 // store new as next last
49
    enc_delta += (diff & 2) - 1;        // bit 1 = direction (+/-)
50
  }
51
}
52
 
53
 
54
int8_t encode_read1( void )         // read single step encoders
55
{
56
  int8_t val;
57
 
58
  cli();
59
  val = enc_delta;
60
  enc_delta = 0;
61
  sei();
62
  return val;                   // counts since last call
63
}
64
 
65
 
66
int8_t encode_read2( void )         // read two step encoders
67
{
68
  int8_t val;
69
 
70
  cli();
71
  val = enc_delta;
72
  enc_delta = val & 1;
73
  sei();
74
  return val >> 1;
75
}
76
 
77
 
78
int8_t encode_read4( void )         // read four step encoders
79
{
80
  int8_t val;
81
 
82
  cli();
83
  val = enc_delta;
84
  enc_delta = val & 3;
85
  sei();
86
  return val >> 2;
87
}
88
 
89
 
90
int main( void )
91
{
92
  int32_t val = 0;
93
 
94
  LEDS_DDR = 0xFF;
95
  encode_init();
96
  sei();
97
 
98
  for(;;){
99
    val += encode_read1();          // read a single step encoder
100
    LEDS = val;
101
  }
102
}

von Karl H. (kbuchegg)


Lesenswert?

Tim D. schrieb:

> Allerdings verstehe ich
> nicht was hier genau mit single step encoders und two step encoders usw.
> gemeint ist.

Es gibt Encoder, die liefern von einer fühlbaren Rastposition zur 
nächsten 1 'Schritt' und es gibt welche die liefern für dieselbe 
Bewegung 2 Schritte bzw. 4 Schritte. D.h. bei einem two step Encoder 
kriegst du auch in der Mitte zwischen den fühlbaren Rastpositionen einen 
Puls.

> Zudem steht unten im Hauptprogramm: " LEDS = val " - was passiert hier,
> kann man den Ports einen Wert außer 1 und 0 übergeben?

Da hier der ganze Port angesprochen wird, werden alle 8 Bit verändert. 8 
Bit - 256 verschiedene unterscheidbare Zahlen. val ist ein 32 Bit Wert, 
dann werden halt eben nur die untersten 8 Bit davon auf die 8 
Portleitungen geschaltet. Um zu sehen, dass sich was tut und die 
Binärzahl sich um einen kleinen Betrag ändert, wenn du am Rad drehst, 
sollte es das allemal tun.

von MaWin (Gast)


Lesenswert?

> int8_t encode_read2( void )         // read two step encoders
> ...
> int8_t encode_read4( void )         // read four step encoders
> ...

Wer kommt auf so einen Quatsch ?

enc_delta ist signed.

> LEDS = val;

32 bit auf 8 bit abbilden ? Nennt man wohl Bitstauchung.

von Falk B. (falk)


Lesenswert?

@ MaWin (Gast)

>> int8_t encode_read2( void )         // read two step encoders
>> int8_t encode_read4( void )         // read four step encoders

>Wer kommt auf so einen Quatsch ?

>enc_delta ist signed.

Wo ist das Problem? int8_t ist das auch.

>> LEDS = val;

>32 bit auf 8 bit abbilden ? Nennt man wohl Bitstauchung.

Naja, im Bereich von C ist DAS die kleinste Schlamperei.

von Falk B. (falk)


Lesenswert?

@Tim D. (Gast)

>auszuwerten. Ich nutze zwar einen Atmega 32 aber sobald ich die Eingänge
>änder sollte dies ja kein Problem darstellen.

Naja, die meisten Encoder haben einfache Kontakte gegen GND, da braucht 
man Pull-Up Widerstände. Die kann man im AVR einschalten, das muss man 
aber tun.

>Ich würde zum Test simpel eine  LED zum leuchten bringen, ab 5000
>Impulsen quasi, habe aber leider keine Idee wie ich das lösen könnte.
>Mein erster Ansatz war eine IF Anweisung in den main Teil zu bringen.
>IF(val>=5000) schalte PORTA eine LED. Funkzt aber nicht.

Betreibe eine systematische Fehlersuche.

Miss die Spannung an den Eingängen vom AVR, wenn du den Encoder drehst, 
muss sich die Spannung dort ändern.

Nein? -> Pull Ups einschalten.

PORTA <= (1<<PA1) | (1<<PA3);

Dann lässt man erstmal die LEDs einfach blinken. AN, Pause, AUS, Pause. 
Die Pausen macht man einfach mit _delay_ms(1000);

Wenn das geht, solte auch der Rest laufen.

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

MaWin schrieb:
> 32 bit auf 8 bit abbilden ? Nennt man wohl Bitstauchung.

nö, nennt man Variablenkomprimierung. Bite nur verlustfreie 
Komprimierungs-Verfahren anwenden!

von Tim D. (Gast)


Lesenswert?

Hammer, vielen vielen Dank für eure schnelle Hilfe und die Antworten!

@Falk: das mit den Pull Ups habe ich irgendwie völlig verdrängt, aber 
klar.

(nach 8 Stunden Internet Recherche und Rumprobieren wird mein Kopf 
langsam doch etwas matsche^^)


Aber ich werde es direkt mal ausprobieren und dann mal schreiben sobald 
es geklappt hat.

Und wie geschrieben, vielen Dank euch noch mal :)

von Wolfgang H. (frickelkram)


Lesenswert?

Leider hat Tim nicht geschrieben welchen Encoder er verwendet.
Bei 5000 Impulsen vermute ich mal das es kein einfacher Handencoder ist, 
sondern vielleicht ein optischer Industrie-encoder den man z.B. auf eine 
Motorwelle montieren kann. In dem Fall kann es sein das die PullUps 
nicht nötig sind. Dann kann es aber auch sein das das Timing mit 1ms zu 
langsam ist ... Vermutungen über Vermutungen ...

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.