Forum: Mikrocontroller und Digitale Elektronik ext. Interrupt mit Inkrementalgeber und 8051-Controller


von Michael L. (eagle87)


Lesenswert?

Hallo zusammen,
ich versuch grad mit einem Inkrementalgeber einen Zähler zu verändern 
und den aktuellen Wert des Zählers zur Kontrolle über LEDs wieder 
auszugeben. Als Controller verwende ich den AT89S8253.

Ein Signal des Gebers geht auf Port 3.2 und das andere auf Port 3.3. Der 
Interrupt wird über Port 3.2 ausgelöst. Die LEDs sind an Port 0 
angeschlossen.

Der Geber hat 15 Inkremente und 30 Raststellungen pro Umdrehung. Je 
nachdem in welcher Stelle er sich gerade befindet zeigten die LEDs 
entweder irgend ein Leuchtmuster an oder die LEDs 0 bis 6 leuchten und 
die 7. blinkt. Ich hab im Moment keine Ahnung was ich an dem Programm 
verändern muss und auch m Netz hab ich nichts gefunden.
1
#include <REG8253.H>
2
3
;------------------------------------------------
4
5
; Reservierung des Stack-Bereichs
6
7
?STACK SEGMENT IDATA    
8
9
  RSEG  ?STACK         
10
11
  DS  10H  
12
13
;------------------------------------------------
14
15
; Variablen im int. direkt adressierbaren RAM
16
17
Variablen SEGMENT DATA    ;Variablen im direkt adressierbaren internen RAM
18
19
  RSEG  Variablen       ;Variablen-Segment waehlen
20
21
zahl:  DS  1    ;Reserviere 1Byte
22
23
zeit1:  DS  1
24
25
zeit100:DS  1
26
27
;--------------------------------------------------------------------------
28
; Auf Adresse 0 im Code-Speicher muss ein LJMP zum Programmanfang stehen
29
30
  CSEG    AT  0           ;absolutes Code-Segment bei Adresse 0
31
32
  ljmp    start           ;Springe zur Marke start
33
34
;--------------------------------------------------------------------------
35
; Interrupt Vektoren
36
37
  cseg at 03h
38
39
  ljmp positionierung
40
41
;--------------------------------------------------------------------------
42
; Hier folgt Programmcode (Code-Beginn ueber Linker festgelegt)
43
44
program_code   SEGMENT CODE
45
46
        RSEG   program_code     ;waehle Code-Segment
47
48
        USING   0               ;Zeige Benuetzung von Registerbank 0 fuer den folgenden Programmcode an
49
50
;--------------------------------------------------------------------------
51
;Initialisierung  Stack und I/O-Karte
52
53
start:
54
55
  mov sp,#?stack-1  ;STACK-Definition
56
57
;--------------------------------------------------------------------------
58
59
60
  setb ea      ;Interrupts zulassen
61
62
63
64
  mov zahl,#0    ;Zahl vordefinieren
65
66
67
68
loop:
69
70
  mov a,zahl    ;Zahl ausgeben
71
72
  cpl a
73
74
  mov p0,a
75
76
  setb ex0    ;Fenster für Interrupt
77
78
  nop
79
80
  clr ex0
81
82
83
84
  ljmp loop    ;Hauptschleife
85
86
87
88
;--------------------------------------------------------------------------
89
90
91
positionierung:      ;externer Interrupt 0
92
93
  jb p3.3,invers    ;Drehrichtung
94
95
  inc zahl    ;hochzählen
96
97
  ljmp positionierung2  ;wieder zusammenführen
98
99
invers:
100
101
  dec zahl    ;runterzählen
102
103
positionierung2:
104
105
  lcall t100ms    ;Entprellzeit
106
107
  clr ie0      ;Flag löschen
108
109
  reti
110
111
112
113
;--------------------------------------------------------------------------
114
115
116
t1ms:        ;1ms Wartezeit
117
118
  mov zeit1,#250
119
120
zeitmarke1:
121
122
  nop
123
124
  nop
125
126
  djnz zeit1,zeitmarke1
127
128
  ret
129
130
131
132
t100ms:        ;100ms Wartezeit
133
134
  mov zeit100,#100
135
136
zeitmarke100:
137
138
  djnz zeit100,zeitmarke100
139
140
  ret
141
142
143
144
  END      ;END Of File

von Heinz (Gast)


Lesenswert?

Wenn das der P. D. sieht, dann springt er wie das HB-Männchen auf und 
ab.

von Michael L. (eagle87)


Lesenswert?

Wer ist P.D.? Und warum sagst du nicht einfach was nicht stimmt? So ist 
auch niemandem geholfen.

von Heinz (Gast)


Lesenswert?

Bitte diesen Artikel durcharbeiten: 
http://www.mikrocontroller.net/articles/Drehgeber

von Michael L. (eagle87)


Lesenswert?

Ok, das hilft schonmal weiter. Die Auswertung nach einer festen Zeit mit 
einem Timer Interrupt werd ich gleich mal ausprobieren. Aber ich hab 
auch nochmal ins Datenblatt meines Gebers geschaut und leider hab ich 
einen, bei dem der Rastpunkt genau auf der Flanke von Signal B liegt. 
Und der AT89S8253 Mikrocontroller besitzt (so wie ich es bisher aus dem 
Datenblatt verstanden hab) nur externe Interrupts für positive Flanken. 
Daher muss ich das Signal wohl noch hardwaremäßig invertieren um ein 
Interrupt mit der negativen Flanke auslösen zu können.

von Peter D. (peda)


Lesenswert?

1
phase_a         equ     p3.2
2
phase_b         equ     p3.3
3
led_port        equ     p0
4
5
        dseg    at 30h
6
enc_delta:      ds 1
7
enc_last:       ds 1
8
9
        cseg
10
11
main:
12
        call    poll_encoder
13
        call    read_encoder2
14
        add     a, led_port
15
        mov     led_port, a
16
        jmp     main
17
18
poll_encoder:
19
        clr     a
20
        mov     c, phase_a              ; input phase_a
21
        rlc     a
22
        jnb     phase_b, _poen1         ; input phase_b
23
        xrl     a, #3                   ; convert gray to binary
24
_poen1:
25
        xch     a, enc_last             ; store new as next last
26
        subb    a, enc_last             ; difference last - new
27
        jnb     acc.0, _poen3           ; bit 0 = value (1)
28
        jnb     acc.1, _poen2           ; bit 1 = direction (+/-)
29
        inc     enc_delta
30
        ret
31
_poen2:
32
        dec     enc_delta
33
_poen3:
34
        ret
35
36
read_encoder2:                          ; read two phase encoder
37
        mov     a, enc_delta            ; read delta counts
38
        anl     enc_delta, #1           ; clear all bits except debouncing bit
39
        mov     c, acc.7                ; copy sign bit
40
        rrc     a                       ; / 2
41
        ret
42
43
end


Peter

von Ralf (Gast)


Lesenswert?

> so wie ich es bisher aus dem Datenblatt verstanden hab) nur externe
> Interrupts für positive Flanken.
Soweit ich weiss besitzt er eher welche für negative Flanken... kann 
mich aber auch täuschen...

Ralf

von Michael L. (eagle87)


Angehängte Dateien:

Lesenswert?

@ Peter:
Ich hab versucht deinen Code zu verstehen und auf meinem Controller zum 
laufen zu bringen, aber beides ist mir leider nicht gelungen. Was die 
Funktion "poll_encoder" in etwa macht konnte ich noch einigermaßen 
nachvollziehen, aber bei der Funktion "read_encoder2" und bei der 
Ausgabe auf den LEDs klappt das nicht. Im Anhang ist der Code so wie ich 
ihn kompiliert hab.

@ Ralf:
Das wäre auch möglich. Aber zumindest dürfte es nicht beides geben. Von 
daher bleibt das Problem das gleiche.

von Peter D. (peda)


Lesenswert?

Michael L. schrieb:
> Ausgabe auf den LEDs klappt das nicht.

Du solltest versuchen, sinnvolle Fehlerbeschreibungen zu machen.
klappt nicht ist voll für die Tonne, damit kann keiner was anfangen.

read_encoder2 gibt nur bei jedem 2.Puls was aus, damit pro Rastung nur 
einmal gezählt wird.
Du kannst zu Testzwecken aber auch direkt enc_delta auf die LEDs 
ausgeben.


Peter

von Michael L. (eagle87)


Angehängte Dateien:

Lesenswert?

Naja, "klappt nicht" war auch keine Fehlerbeschreibung, sondern nur die 
Aussage, dass ich den Teil des Programms nicht versteh. Aber ich muss 
zugegeben dass ich wirklich noch hätte schreiben sollen was auf dem 
LED-Port passiert: Alle LEDs flackern und wenn ich am Geber drehe ändert 
sich auch nichts.
Wenn ich enc_delta direkt auf die LEDs geb passiert das Gleiche.

Inzwischen hab ich aber ein eigenes Programm zum laufen gebracht. Das 
läuft jetzt über ein Timer-Interrupt, welches alle 10ms auslöst. Dabei 
werden auch nur die Flanken der Spur A und die Zustände der Spur B 
ausgewertet. Das Programm ist vermutlich nicht so effizient wie deines, 
aber zumindest hab ich jetzt ein Programm bei dem ich weiß was es macht.

Übrigens war der hauptsächliche Fehler dass das erste Programm nicht 
funktioniert hat der, dass der externe Interrupt voreingestellt 
zustands- und nicht flankengesteuert arbeitet. Das steht aber nicht im 
Datenblatt, sondern in einem anderen Dokument das allgemein die 
8051-Architektur beschreibt. Dort stand außerdem, dass es wirklich 
fallende Flanken sind, die ein Interrupt auslösen.

Michael

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.