Forum: Mikrocontroller und Digitale Elektronik Problem beim Einlesen eines Drehgebers


von Tobias B. (tc-soundnlight)


Lesenswert?

Hier erstmal mein momentaner Code in Assembler:
1
.include "m8515def.inc"
2
3
.set maske = 0b00001100      ; Drehgeber Bits
4
.set DrehPort = PIND      ; Drehgeber Port
5
6
.def merker = r16
7
.def temp = r17
8
.def merker2 = r18
9
.def alt = r20
10
.def zahl = r21
11
12
  ldi temp, LOW(ramend)
13
  out SPL, temp
14
  ldi temp, HIGH(ramend)
15
  out SPH, temp
16
17
  ldi temp, 0x00        
18
  out DDRD, temp        ; Port D als Eingang
19
  mov merker2, temp      ; Alt auf 0
20
  
21
  
22
  ldi temp, 0xff
23
  out DDRB, temp        ; Port B als Ausgang
24
  out PORTD, temp        ; PullUP Aktivieren
25
26
main:
27
  mov alt, merker2      ; Alt auf "alten" Zustand setzen
28
  in temp, DrehPort      ; DrehPort einlesen
29
  com temp          ; Invertieren -> Bessere Anschaulichkeit
30
  andi temp, maske      ; Ausmaskieren der Drehgeber Bits
31
  mov merker, temp      ; Sichern
32
  mov merker2, temp      ; Sichern
33
  cp alt, merker        ; Vergleiche merker mit alt
34
  brne gedreht        ; Wenn ungleich wurde gedreht
35
  rjmp main          ; Wenn gleich -> Dauerschleife
36
37
gedreht:
38
39
  dec zahl
40
  out PORTB, zahl
41
  rjmp main
42
43
;  ldi temp, maske  
44
;  cp merker, temp        ; Beide Werte 1 ?  
45
;  brne ungleich_1
46
;  rjmp weiter
47
48
;ungleich_1:
49
;  ldi temp, 0x00
50
;  cp temp, merker        ; Beide Werte 0 ?
51
;  brne ungleich    
52
;  rjmp weiter
53
;  
54
;ungleich:
55
;  com merker          ; Invertieren
56
;  andi merker, maske
57
;  rjmp weiter  
58
;
59
;weiter:
60
;  eor merker, alt
61
;  ldi temp, 0b00001000
62
;  cp merker, temp
63
;  brne rechts
64
;  rjmp links
65
;
66
;rechts: 
67
;  mov alt, merker2
68
;  inc zahl
69
;  out PORTB, zahl
70
;  rjmp main
71
;
72
;links:
73
;  mov alt, merker2
74
;  dec zahl
75
;  out PORTB, zahl
76
;  rjmp main

Ich habe ihn momentan zum Testen vereinfacht.
Es soll einfach nur wenn ich eine Taste drücke EINMAL weitergezählt 
werden.
Da ab dann der Wert "alt" mit dem Akutellen übereinstimmt sollte er 
eigentlich solang in der Main-Schleife im Kreis springen bis sich etwas 
ändert!

Im Debugger von AVR-Studio macht er das auch alles so wie es soll...
Wenn ich es aber auf den Controller schreibe und dort Teste, zählt er 
solange ich eine Taste drücke (also sich eigentlich nichts verändert?!) 
- Wenn ich loslasse gehen alle LED's wieder An (also PortB - 0x00)

Ich benutze das STK500

Was muss ich noch beachten oder was ist in meinem Code falsch?!

Achso, falls jemand "einfachere" oder bessere Methoden hat einen 
Drehgeber auszulesen bin gerne offen für - aber ich wollte erstmal 
meinen eigenen Weg verfolgen - Learning by doing :-)

Vielen Dank für Antworten

Greez Tobi

von Stefan M. (celmascant)


Lesenswert?

Suche hier im Forum mal nach Drehgeber oder bei Google nach Rotary 
Encoder.
Da gibt es einige Beispiele wie man einen Drehgeber auslesen kann.
Eine der besten Methoden findest du hier im Forum von Peter Danegger:
Beitrag "Drehgeber auslesen"

Gruss Stefan

Hab noch vergessen, der Code ist in C!

von Tobias B. (tc-soundnlight)


Lesenswert?

Hat mir trotzdem jemand eine Antwort warum mein programm nicht will???

von MaWin (Gast)


Lesenswert?

> Hat mir trotzdem jemand eine Antwort warum mein programm nicht will???

Ich sehe ein DEC zahl.

Inkrementiert wird gar nicht.

Was soll da funktionieren ?

Im Übergang von einem Zustand zum anderen ändert sich wegen prellen der 
Kontakte das Signal mehrmals. Dann dekrementierst du mehrmals.

> Im Debugger von AVR-Studio macht er das auch alles so wie es soll...

Da prellen Kontakte auch nicht, es sei denn, du simulierst das, durch 
wiederholtes Ein- und Ausschalten.

Aber warum machen eigentlich immer alle Leute dieselben Fehler ?

Ist es so schwer, vorher mal zu gucken, wie es richtig geht?

http://dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29

von Stefan M. (celmascant)


Lesenswert?

Bei deinem Link ist es richtig erklärt, jedoch ist folgendes falsch:
    0: ab (Spur A LOW, Spur B LOW)
    1: Ab (Spur A HIGH, Spur B LOW)
    2: aB (Spur A LOW, Spur B HIGH)
    3: AB (Spur A HIGH, Spur B HIGH)
Zustand 2 und 3 der Signale sind vertauscht.

Richtig wäre die Bitfolge so:
    0: ab (Spur A LOW, Spur B LOW)
    1: Ab (Spur A HIGH, Spur B LOW)
    2: AB (Spur A HIGH, Spur B HIGH)
    3: aB (Spur A LOW, Spur B HIGH)
An sonsten ist das eine sehr gute Erklärung!
Es gibt auch Drehgeber die Zusätzlich noch eine "Null"-Markierung haben. 
Da wird ein 3. Ausgang 1x pro Umdrehung gesetzt, zum Abgleich mit den 
Softwarezählern. Da kann dann (fast) nichts mehr schief gehen und es ist 
auch nicht so schlim wenn man mal 1 oder 2 Schritte/U nicht mitgezählt 
hat, denn es wird ja nach jeder Umdrehung abgeglichen ;)

Gruss Stefan

von MaWin (Gast)


Lesenswert?

Die Beschreibung passt schon, denn es ist zunächstmel eine Aufzählung 
der möglichen Zustände, nicht die Reihenfolge beim Drehen. Derzeit ist 
die Reihenfolge nach binärer Wertigkeit der Eingänge.

Die Frage wäre, ob zu dieser Definition die Beschreibnng darunter passt. 
Sie passt. Also ist die Zustandsbeschreibung korrekt.

Ich kann zur Kenntnis nehmen, dass du die Auflistung der möglichzen 
Zustände schon in der Reihenfolge der Zustände beim Drehen sehen willst. 
Das hat was für sich, zumindest wennn man gleich daneben zeichnet, bei 
welcher Drehrichtung es sich ergibt.

von Stefan M. (celmascant)


Lesenswert?

Naja, wenn man die Zustände schon Durchnummeriert, sollten sie (meiner 
Meinung nach)auch in der richtigen Reihenfolge da stehen, sonnst gibt es 
hinterher vieleicht Verständnissprobleme.
Ein "Neuling" (der nicht in sein Datenblatt geschaut hat) wird dann auch 
nicht interpretieren können, wie er die Drehrichtung auswerten kann.

Gruss Stefan

von Tobias B. (tc-soundnlight)


Lesenswert?

Im Übergang von einem Zustand zum anderen ändert sich wegen prellen der
Kontakte das Signal mehrmals. Dann dekrementierst du mehrmals.

Ein Taster prellt aber nicht 10sec lang :-)

Warum ich nicht Inkrementiere?

Weil ich wie gesagt das Programm wegen diesem Problem verkürzt hab und 
einfach nur sehen wollte wo er nicht das tut was ich will ...

Und ich sehe das er auch wenn keine Änderung zum vorigen Zustand (trotz 
Prellen - welches aber niemals SOOO lange und SOOO oft ist) 
weiterzählt...

Danke aber für die Links und erklärungen - will aber trotzdem schaffen 
meienn Ansatz weiter zu bekommen - und ich denke das Prellen kann ich 
ausschließen ... wo könnte der fehler noch liegen?!

Danke :-)

von Stefan M. (celmascant)


Lesenswert?

Ich hab dein Programm mal kopiert und im Simulator getestet. Da sieht es 
wirklich gut aus, also theoretisch funktioniert es.
Mess doch mal die Spannungen an den beiden Eingängen. wenn kein Taster 
gedrückt, sollte sich die Spannung bei ca. 4,9V befinden.
Bei gedrücktem Taster sollten 0V anliegen.
Wenn irgendwas dazwischen gemessen wird, stimmt entweder die Schaltung 
nicht (Taster muss gegen GND schalten^^) oder dein Taster ist nicht in 
Ordnung, also hochomig. Im Datenblatt des MC steht, ab welcher Spannung 
High und unter welcher Spannung Low erkannt wird. Alles dazwischen ist 
unzulässig, denn dann wäre ein unbestimmter (zufälliger) Zustand im 
Register PinD. Dadurch würde sich die Zählerei erklären.

Was passiert denn, wenn du die Taster komplett abhängst und nur die 
Pull-Ups einschaltest? Zählt er dann immer noch?

Gruss Stefan

von geb (Gast)


Lesenswert?

Ich hab einen Drehgeber mal ausgelesen mit einem Siemens C161. Der Hatte 
externe Interrups mit fallender und steigender Flanke.Den hab ich an 
Ausgang A des drehgebers gelegt. B an einen anderen Pin.
Es geht auch mit 2 Interrupteingängen wenn nur auf eine Flanke 
getriggert werden kann.

void resolver_trap(void) interrupt 0x1A//bei pos. und neg. Flanke von A
{
#define TIM_COUNT 0xFFFF-18430
static uint old_system_counter;
static uint old_tim_counts;
uint system_counts;
static ulong speed_counts;
if((P2&0x0400)==0){//A=0?
    if((P3&0x0010)==0)res_pos--;//A=0,B=0,runterzählen
    else res_pos ++;//A=0,B=1,raufz.
          }
else{if((P3&0x0010)==0)res_pos++;//A=1,B=0,raufzählen
     else res_pos --;//A=1,B=1,runterz.
          }

system_counts=(system_counter-old_system_counter);
speed_counts=(ulong)((ulong)(T2-old_tim_counts)+(ulong)(TIM_COUNT*system 
_counts));
old_system_counter=system_counter;
old_tim_counts=T2;
}

Grüße Gebhard

von Tobias B. (tc-soundnlight)


Lesenswert?

Danke für deinen Tipp...

Das ist es aber leider nicht.. wie gesagt nutze ich z.Z. das STK500 - 
Hab die OnBoard verfügbaren Taster genommen - und die auch mal überprüft 
- Funktionieren einwandfrei oO ...

Dann hab ich auch mal externe Taster genommen - da auch - sobald ich 
etwas drücke Zählt er wenn ich nichts Drücke passiert auch nichts...

Auch wenn ich einfach einen Drehgeber einbaue funktioniert es nicht...

*verwirrt bin und nachher nommal ne Stunde rumprobier -.- *

von Karl H. (kbuchegg)


Lesenswert?

Kann an dem Programm auch nichts finden, was mich stören würde. Meiner 
Meinung nach müsste es funktioniereen.
Bist du sicher, dass du das richtige Programm geflasht hast?

Ansonsten lass dir doch einfach mal alt oder merker am Port ausgeben und 
sieh nach, was sich da ständig ändert, wenn du eine Taste drückst.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Vieleicht hat auch der Drehgeber ne Macke? Ich hab mal EWIG (gefühlt) 
nach dem Fehler in einer Verstärkerschaltung gesucht warum der eine 
Kanal (obwohl identisch aufgebaut) nicht funktionieren wollte, bis ich 
dann einfach mal ein anderes Stereopoti genommen habe und auf einmal 
alles lief ;)

von Tobias B. (tc-soundnlight)


Lesenswert?

Ich hab jetzt mal den merker2 komplett raus getan weil ich gemerkt habe, 
dass dieser unnötig ist - jetzt zählt er sozusagen kurz eins hoch 
(taster bleibt gedrückt) und geht sofort wieder auf null...

Irgendwo wird "zahl" resettet aber wo und warum?!

Nochmal der Quellcode:
1
.include "m8515def.inc"
2
3
.set maske = 0b00001100      ; Drehgeber Bits
4
.set DrehPort = PIND      ; Drehgeber Port
5
6
.def temp = r16
7
.def merker = r17
8
.def alt = r18
9
.def zahl = r19
10
11
  ldi temp, LOW(ramend)
12
  out SPL, temp
13
  ldi temp, HIGH(ramend)
14
  out SPH, temp
15
16
  ldi temp, 0x00        
17
  out DDRD, temp        ; Port D als Eingang
18
  mov merker, temp      ; Alt auf 0
19
  
20
  
21
  ldi temp, 0xff
22
  out DDRB, temp        ; Port B als Ausgang
23
  out PORTD, temp        ; PullUP Aktivieren
24
  mov zahl, temp
25
  out PORTB, zahl
26
27
main:
28
  in temp, DrehPort      ; DrehPort einlesen
29
  com temp          ; Invertieren -> Bessere Anschaulichkeit
30
  andi temp, maske      ; Ausmaskieren der Drehgeber Bits
31
  mov merker, temp      ; Sichern
32
  cp alt, merker        ; Vergleiche merker mit alt
33
  brne gedreht        ; Wenn ungleich wurde gedreht
34
  rjmp main          ; Wenn gleich -> Dauerschleife
35
36
gedreht:
37
38
  mov alt, merker
39
  inc zahl
40
  out PORTB, zahl
41
  rjmp main

Natürlich noch gekürzt weil erstmal die Grundfunktion laufen soll danach 
kommt dann irgenwann der Teil mit dem eigentlichen Drehgeber...

von Karl H. (kbuchegg)


Lesenswert?

Tobias Binkowski schrieb:
> Ich hab jetzt mal den merker2 komplett raus getan weil ich gemerkt habe,
> dass dieser unnötig ist - jetzt zählt er sozusagen kurz eins hoch
> (taster bleibt gedrückt) und geht sofort wieder auf null...

Die einzige Möglichkeit, wo Zahl auf einen bestimmten Wert gesetzt wird, 
ist am Anfang in der Initialisierung.

D.h. die Initialisierung wird erneut durchlaufen, was wiederrum heißt, 
dass dein µC das Programm von vorne abarbeitet, was wiederrum bedeutet 
das der µC resettet wurde. Das könnte zb sein, wenn du mit dem Taster 
einen Kurzen gebaut hast.

von Peter D. (peda)


Lesenswert?

Die Darstellung von Zahlen im 2-er Komplement hat eine sehr nützliche 
Eigenschaft. Differenzen funktionieren immer, auch bei Überlauf.

Nehmen wir als Beispiel den Überlauf von 127 nach -128, jetzt rechnen 
wir also: -128 - 127 = 0x80 - 0x7F = 1

D.h. wenn wir 2 aufeinanderfolgende Zahlen subtrahieren, stimmt das 
Ergebnis immer.

Nun gibt es ne kleine Aufgabe, ein Encoder liefert keine Binärzahlen, 
sondern Graycode. Das hat den Vorteil, daß es keine falschen Codes gibt.

Schauen wir uns also mal 2 Bit als Graycode und als Binärzahl an:
1
Gray  Binär
2
0 0   0 0
3
0 1   0 1
4
1 1   1 0
5
1 0   1 1

Wie man leicht sieht, läßt sich Gray sehr einfach nach binär umwandeln, 
einfach das 0. Bit umdrehen, wenn das 1. gesetzt ist.

Das ist das ganze Geheimnis meines sehr einfachen Codes und warum er 
sicher entprellt.


Peter

von Tobias B. (tc-soundnlight)


Lesenswert?

Ah wie geil - Ich flipp gleich aus...

Es lag nicht an den Tastern und nicht am Code...

Bah eigentlich sollte ich solche fehler aus erfahrung immer als erstes 
ausschließen aber ich hab nicht dran gedacht.. mein ATMega (der schon 
laaange zeit als experimentier stein herhält) hat irgend einen Schuss 
gehabt - IC getauscht - Funktioniert -.- oh man .. :-) *jetz dafür 
rumjubel*

Trotzdem allen ein Danke die mir den ein oder anderen neuen Link gezeigt 
haben...

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.