Forum: Mikrocontroller und Digitale Elektronik Problem bei Drehgeber auswertung


von Sebastian Engel (Gast)


Lesenswert?

Hallo,

ich hab mal versucht, einen Drehgeber (Handbetrieben) auszuwerten.
Und zwar sollte die Drehbewegung in je ein Impuls pro Rastung 
ausgegegebn werden, getrennt für rechts und links.

Ich verwende einen ATtiny26 mit 1MHz interner Taktung.

Den Drehgeber habe ich an PB6 und PB5 angeschlossen.
2 LEDs sind an PA0 und PA1 angeschlossen.
PB6 ist als externer Interrupt eingestellt auf "Pin Change".

Hier der code:
1
;#################################
2
;# Project: Drehgeber auswerten mit Interrupt
3
;# Date: 20.3.07
4
;# Version: 0.1
5
;# Controller: ATtiny26
6
;# Frequency: 1Mhz intern
7
;#################################
8
.include "tn26def.inc"
9
10
  rjmp main      ;Power-on-reset
11
  rjmp subroutine    ;external interrupt
12
  reti
13
  reti
14
  reti
15
  reti
16
  reti
17
  reti
18
  reti
19
  reti
20
  reti
21
  reti
22
23
;#################################
24
;# main
25
;#################################
26
27
  main:  ldi r16,low(ramend)
28
      out SP,r16
29
30
      clr r16
31
      out DDRB,r16
32
      ser r16
33
      out PORTB,r16
34
      out DDRA,r16
35
36
      ldi r16,0b01000000
37
      out GIMSK,r16    ;external interrupt on
38
      ldi r16,0b00000001
39
      out MCUCR,r16    ;ext. int at "any change"
40
      sei          ;global interrupt enable
41
42
; Mainloop
43
  loop:  rjmp loop
44
45
; Interrupt program
46
  subroutine:
47
      in r16,PINB
48
      mov r17,r16
49
      ror r17
50
      andi r16,0b01000000
51
      andi r17,0b01000000
52
      cp r16,r17
53
      brne rechts
54
      sbi PORTA,1
55
      rcall wait
56
      cbi PORTA,1
57
      reti
58
  rechts:  sbi PORTA,0
59
      rcall wait
60
      cbi PORTA,0
61
      reti
62
63
; Warteschleife
64
  wait:  ser r20
65
  wait0:  dec r20
66
      brne wait0
67
      ret

Das Ergebnis: Es werden abwechselnd PA0 und PA1 angesteuert, egal wie 
rum ich den Drehgeber drehe. Mnachmal werden beide gleichzeitig 
angesteuert.

Meine Frage ist nun: Findet jemand spontan einen Fehler?
Fehlt nur eine entprellung, oder kleine warteschleifen?
Ich bin ratlos.

Mfg
 Sebastian Engel

von Matthias (Gast)


Lesenswert?

s werden abwechselnd PA0 und PA1 angesteuert, egal wie
rum ich den Drehgeber drehe. Mnachmal werden beide gleichzeitig
angesteuert...

Aber du weißt wie ein Drehgeber funktioniert?

von Hannes L. (hannes)


Lesenswert?

Also ich nutze einen handbetätigten Drehgeber am Mega8535 mit folgender 
Routine:

;Relevante Deklarationen:
1
.equ tap=pind               ;Eingangs-Port Tasten
2
    .equ tli=7                  ;Taste links
3
    .equ tho=6                  ;Taste hoch
4
    .equ tru=5                  ;Taste runter
5
    .equ tre=4                  ;Taste rechts
6
    .equ ths=3                  ;Taste Handschuss
7
    .equ tdg=2                  ;Taster vom Drehgeber
8
.equ dgp=pinb               ;Eingangsport Drehgeber
9
    .equ dgmsk=0b00001100       ;Maske auf benutzte Bits von 'dgp'
10
    .equ dgprell=0b00010101     ;Maske auf Togglebits in 'drg'
11
12
.def drg=r5                 ;Drehgeber-Entprellvariable
13
.def tas=r13                ;entprellter Tastenstatus (gültig)
14
.def haschunu=r17           ;Handschussnummer per Drehgeber
15
.def wl=r24                 ;Working L

;Routine, zyklischer Job der Mainloop alle 1ms:
1
drehgeber:              ;Drehgeber-Entprellung und -Abfrage (alle 1ms)
2
;diese Routine wird von der Mainloop aufgerufen, wenn mindestens eine 
3
;Millisekunde seit des letzten Aufrufs vergangen ist. Der Aufruf erfolgt
4
;mit 'rjmp', damit auch andere Mainloop-Jobs zum Zuge kommen, ehe der
5
;Controller am Ende der Mainloop in den Sleep fällt. Das zugehörige
6
;Jobflag (Synchronisation mittels Timer) wird in der Routine 'lcd_update'
7
;gelöscht.
8
 rcall lcd_update           ;ein Zeichen aus Bildscirmspeicher an LCD ausgeben
9
 in wl,dgp                  ;Drehgeber einlesen
10
 andi wl,dgmsk              ;nur Drehgeber-Bits (Bit 3:2)
11
 swap wl                    ;nach oben (Bit 7:6)
12
 or drg,wl                  ;neuen Zustand übernehmen
13
 mov wl,drg                 ;Bitmuster merken (neu, alt, älter, uralt)
14
 lsr drg                    ;Bitmuster nach unten schieben
15
 lsr drg                    ;(leer, neu, alt, älter)
16
 eor wl,drg                 ;Änderungen erfassen
17
 andi wl,dgprell            ;nur Änderungsbits stehen lassen
18
 cpi wl,1                   ;nur ältestes Änderungsbit gesetzt?
19
 brne drehgeber3            ;nein, kein neuer stabiler (entprellter) Zustand...
20
21
 ldi wl,1                   ;ja, erstmal normale Schrittweite
22
 sbrc tas,tdg               ;Shift-Taste (Drehgeber-Taste) betätigt? - nein...
23
 ldi wl,32                  ;ja, Geräte-Schrittweite
24
 sbrs drg,0                 ;steigende Flanke? - ja...
25
 rjmp drehgeber1            ;nein...
26
 sbrs drg,1                 ;Richtung 1? nein...
27
 add haschunu,wl            ;ja, adieren
28
 sbrc drg,1                 ;Richtung 2? nein...
29
 sub haschunu,wl            ;ja, subtrahieren
30
drehgeber1:
31
 sbrc drg,0                 ;fallende Flanke? - ja...
32
 rjmp drehgeber2            ;nein...
33
 sbrs drg,1                 ;Richtung 1? nein...
34
 sub haschunu,wl            ;ja, subtrahieren
35
 sbrc drg,1                 ;Richtung 2? nein...
36
 add haschunu,wl            ;ja, adieren
37
drehgeber2:
38
drehgeber3:
39
;Das folgende Ausgeben des veränderten Wertes ist nur möglich, weil die
40
;Ausgabe über einen Bildschirm-Speicher im AVR-SRAM erfolgt. Dem ist es
41
;recht egal, wenn er schneller beschrieben wird, als es ins LCD kopiert
42
;wird. Mit herkömmlichen LCD-Routinen geht das natürlich nicht.
43
 locate 6,21
44
 push xl
45
 mov xl,haschunu            ;Kopie von Handschussnummer
46
 rcall lcd_printsnr         ;Aufruf... (dreistellige Ausgabe 'A00'..'H31')
47
 pop xl
48
 rjmp mainloop              ;fertig, weitere Jobs der Mainloop abarbeiten...

Das müsste auch am Tiny26 funktionieren.

...

von Falk (Gast)


Lesenswert?

@Sebastian Engel

>ich hab mal versucht, einen Drehgeber (Handbetrieben) auszuwerten.

Alle Jahre wieder, komt nciht nur das Christuskind, sondern auch das 
Thema Drehgeber.

Guggst du hier.

Beitrag "Drehgeber auslesen"
http://www.mikrocontroller.net/articles/Drehimpulsgeber

>PB6 ist als externer Interrupt eingestellt auf "Pin Change".

Was schonmal kein guter Ansatz ist. Auswertung per Flankeninterrupt ist 
schlecht, periodische Abtastung per Timerinterrupt ist das Mittel der 
Wahl.

MfG
Falk

von Dirk (Gast)


Lesenswert?

@Falk
1
>Auswertung per Flankeninterrupt ist
2
>schlecht, periodische Abtastung per Timerinterrupt ist das Mittel der
3
>Wahl.

Warum nicht mit Interrupt ?


Grüße
Dirk

von Falk (Gast)


Lesenswert?

@Dirk

>>Auswertung per Flankeninterrupt ist
>>schlecht, periodische Abtastung per Timerinterrupt ist das Mittel der
>>Wahl.

>Warum nicht mit Interrupt ?

Das ist lang und breit und hundertmal im angegebenen Link erklärt.

MfG
Falk

von Sebastian Engel (Gast)


Lesenswert?

Erstmal:
Ja, mir ist bekannt was ein Drehgeber ist. Das Datenblatt habe ich 
ausführlich durchgeforstet

Zu den Links:
Ich habe hier schon fast alle Drehgeber Threads durchgestöbert,
aber ich dachte mir probierstes mal selber.

Zum interrupt:
So eine Lösung würde im Datenblatt vorgeschlagen.
Also ganz simpel:
positive Flanke triggert -> pin A & B vergleichen -> Wenn gleich 
"rechts" / Wenn ungleich "links" -> trigger auf fallende flanke stellen 
-> anfang ->

Ich dachte das hätte ich richtig in der Software umgesetzt.

Sonst muss ich halt nochmal die alten Threads durchstöbern.

Danke für die flotten antworten

 Mfg
 S. Engel

von Thomas (Gast)


Lesenswert?

Hast du vielleicht richtig programmiert, doch das Prellen wird das 
Genick brechen... Ohne "schlauere" Routinen geht es vielleicht bei 
optischen Gebern, aber bei mechanischen wird es zum Glückspiel.

von Falk (Gast)


Lesenswert?

@Sebastian Engel

>Ich habe hier schon fast alle Drehgeber Threads durchgestöbert,
>aber ich dachte mir probierstes mal selber.

Prinipiell OK, aber leider machen dabei die meisten Leute genau den 
Fehler, den hunderttausende vor ihnen schon gemacht haben.

>Zum interrupt:
>So eine Lösung würde im Datenblatt vorgeschlagen.
>Also ganz simpel:
>positive Flanke triggert -> pin A & B vergleichen -> Wenn gleich
>"rechts" / Wenn ungleich "links" -> trigger auf fallende flanke stellen
>-> anfang ->

Daran sieht man, dass auch Datenblätter manchmal Müll enthalten.

>Ich dachte das hätte ich richtig in der Software umgesetzt.

Kann sein, sit aber dennoch falsch, weil es nur zu 90% sauber läuft.

>Sonst muss ich halt nochmal die alten Threads durchstöbern.

Das musst du. Kleiner Tip. Stell dir mal vor, der Drehgeber kommt genau 
auf einer Flanke zum Stehen und schwingt dann lustig vor und zurück (das 
ist ein realer Fall!).

Was passiert mit deinem Controller, wenn er auf steigende/fallende 
Flanke triggert?
Was passiert mit dem Controller, wenn er nur alle 10ms abtastet?

@Thomas

>Genick brechen... Ohne "schlauere" Routinen geht es vielleicht bei
>optischen Gebern, aber bei mechanischen wird es zum Glückspiel.

Auch bei optischen ist es das gleiche Problem.

MFG
Falk

von Gugge 7. (gugge73)


Lesenswert?

@Sebastian

Laß dir keinen Müll erzählen, auch im flankengesteurten Interrupt kann 
man erfolgreich Drehgeber auswerten/abfragen. Hab bei mir zu Hause auch 
zwei Teile im Einsatz, die seit zehn Jahren funktionieren. Damals war 
mir Peters Timerroutine noch gar nicht bekannt, und ob es dieses Forum 
hier schon gab, kann nicht sagen.

von Falk (Gast)


Lesenswert?

@Gugge 73

>Laß dir keinen Müll erzählen, auch im flankengesteurten Interrupt kann
>man erfolgreich Drehgeber auswerten/abfragen. Hab bei mir zu Hause auch

Man kann auch 20 Jahre ohne Sturzhelm Moped fahren und es passiert nix.

>zwei Teile im Einsatz, die seit zehn Jahren funktionieren. Damals war
>mir Peters Timerroutine noch gar nicht bekannt, und ob es dieses Forum
>hier schon gab, kann nicht sagen.

Der Aufstieg und Fall der Elektronikbranche wird wohl kaum an dieser 
Webseite hängen ;-)
Und auch wenn es Peters Routine noch nciht gab, so gab es schon Leute 
die wussten wie man Drehgeber richtig auswertet. Aber bestimmte Mythen 
sind eben sehr zäh.

MFG
Falk

P.S. Stell dir bitte auch mal die Fragen aus meinem vorherigen Posting. 
Was passiert mit dem Controller? Die Antwort ist auch im verlinkten 
Thread zu finden.

von Sebastian Engel (Gast)


Lesenswert?

1
;#################################
2
;# Project: Drehgeber auswerten mit Interrupt
3
;# Date: 20.3.07
4
;# Version: 0.1
5
;# Controller: ATtiny26
6
;# Frequency: 1Mhz intern
7
;#################################
8
.include "tn26def.inc"
9
10
  rjmp main      ;Power-on-reset
11
  rjmp subroutine    ;external interrupt
12
  reti
13
  reti
14
  reti
15
  reti
16
  reti
17
  reti
18
  reti
19
  reti
20
  reti
21
  reti
22
23
;#################################
24
;# main
25
;#################################
26
27
  main:  ldi r16,low(ramend)
28
      out SP,r16
29
30
      clr r16
31
      out DDRB,r16
32
      ser r16
33
      out PORTB,r16
34
      out DDRA,r16
35
36
      ldi r16,0b01000000
37
      out GIMSK,r16    ;external interrupt on
38
      ldi r16,0b00000001
39
      out MCUCR,r16    ;ext. int at "any change"
40
      sei          ;global interrupt enable
41
42
; Mainloop
43
  loop:  rjmp loop
44
45
; Interrupt program
46
  subroutine:
47
      rcall wait           ;<---- Das ist NEU
48
      in r16,PINB
49
      mov r17,r16
50
      rol r17              ;<---- ror durch rol ersetzt, der eigendliche Fehler
51
      andi r16,0b01000000
52
      andi r17,0b01000000
53
      cp r16,r17
54
      brne rechts
55
      sbi PORTA,1
56
      rcall wait
57
      cbi PORTA,1
58
      reti
59
  rechts:  sbi PORTA,0
60
      rcall wait
61
      cbi PORTA,0
62
      reti
63
64
; Warteschleife
65
  wait:  ser r20
66
  wait0:  dec r20
67
      brne wait0
68
      ret

Hab nur die beiden oben genannten dinge geändert, und schon läufts.

Funktioniert zu 98,7% :-)
Ab und zu kommt ein "Fehlimpuls".
Zum testen habe ich anstatt 2 pins zu toggeln, einfach an Port A durch 
LEDs  ein Register ausgegeben, welches man durch drehen +1 / -1 
durchzählen kann.

von Hannes L. (hannes)


Lesenswert?

Naja, Warteschleife in der ISR ist nicht mein Ding, aber wenn Du damit 
klar kommst, dann nur zu...

...

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

>>Funktioniert zu 98,7% :-) Ab und zu kommt ein "Fehlimpuls".

Mach mal je 33nF Keramikkondensatoren von jedem der beiden Drehgeberpins 
nach Masse. Das schluckt einen Großteil der Prellimpulse, flacht aber 
die Flanken ab. Es könnte die Fehler aber auf nahezu 0 reduzieren. Trotz 
aller Deiner Argumente würde ich aber nie einen Interrupt an einem 
externen Schaltelement anbinden. Das sorgt im Zweifelsfalle (schnelle 
Betätigungen) für Instabilität im Programm.

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.