Forum: Mikrocontroller und Digitale Elektronik Stoppuhr-Programm für ATmega8 bleibt immer an der gleichen Stelle hängen


von n-regen (Gast)


Lesenswert?

Hallo!

Ich versuche gerade, anhand dieses Tutorials 
(http://www.mikrocontroller.net/articles/AVR-Tutorial:_Uhr) ein 
Assembler-Programm für den ATmega8 zu schreiben, das eine Stoppuhr auf 
einer 4-Zeichen-7-Segment-Anzeige anzeigen soll.
Allerdings bleibt dieses Programm zwischen der 9. und 10. Sekunde hängen 
(vermutlich in der Schleife zum Ermitteln der Zehnerziffer des 
Sekundenregisters). Sobald allerdings die nächste Minute anfängt, zeigt 
das Display wieder 10 Sekunden (z.B. von 1:00 bis 1:09) die aktuelle 
Zeit an, um dann beim Umschalten von 9:59 auf 10:00 wieder (allerdings 
für 50 Minuten) hängen zu bleiben. Ist die Stunde vorbei, werden wieder 
(mit den genannten Aussetzern) die ersten 9 Sekunden der ersten 9 
Minuten angezeigt.
Während das Programm hängt, wird auf der Anzeige nur die 9 als 4. Ziffer 
angezeigt (um eine Zahl anzuzeigen, zeige ich normalerweise die erste 
Ziffer an, warte 2,5ms, zeige die zweite Ziffer an, usw.).

Hat irgendwer von euch eine Idee, wo der Fehler liegt, der zu dieser 
Endlosschleife führt (wobei allerdings ein Interrupt den µC aus der 
Schleife holt - was ja normal ist - und außerdem die normale 
Funktionalität wiederherstellt - was ich mir nicht erklären kann)?

Hier ist mein aktueller Quelltext (ich habe mich allerdings nicht um das 
Hinzufügen sinnvoller und Entfernen sinnloser Kommentare gekümmert, die 
Kommentare sind also nutzlos):
1
.include "m8def.inc"
2
 
3
.def temp1 = r16
4
.def temp2 = r17
5
 
6
.def SubCount = r21
7
.def Sekunden = r22
8
.def Minuten  = r23
9
.def Stunden  = r24
10
11
.def digit1 = r25
12
.def digit2 = r26
13
.def digit3 = r27
14
.def digit4 = r28
15
 
16
.org 0x0000
17
        rjmp    main                ; Reset Handler
18
.org OVF0addr
19
        rjmp    timer0_overflow     ; Timer Overflow Handler
20
 
21
main:
22
        ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren
23
        out     SPL, temp1
24
        ldi     temp1, HIGH(RAMEND)
25
        out     SPH, temp1
26
 
27
        ldi     temp1, 0b00000101   ; Teiler 1024
28
        out     TCCR0, temp1
29
 
30
        ldi     temp1, 0b00000001   ; TOIE0: Interrupt bei Timer Overflow
31
        out     TIMSK, temp1
32
 
33
        clr     Minuten             ; Die Uhr auf 0 setzen
34
        clr     Sekunden
35
        clr     Stunden
36
        clr     SubCount
37
38
    ldi digit1, 0x00
39
    ldi digit2, 0x00
40
    ldi digit3, 0x00
41
    ldi digit4, 0x00
42
    ldi r16, 0b11111111
43
    out DDRB, r16
44
    out DDRC, r16
45
 
46
        sei
47
 
48
loop:   rcall zehner
49
    ldi r31, 0b00000001
50
    sbrc digit1,7
51
    ori r31, 0b00100000
52
    sbrc digit1,6
53
    ori r31, 0b00010000
54
    mov r18, digit1
55
    andi r18, 0b00111111
56
    ori r18, 0b00001000
57
    out PORTB, r31
58
    out PORTC, r18
59
60
    ldi  R29, $21
61
    WGLOOP0:  ldi  R30, $64
62
    WGLOOP1:  dec  R30
63
    brne WGLOOP1
64
    dec  R29
65
    brne WGLOOP0
66
67
    ldi r31, 0b00000010
68
    sbrc digit2,7
69
    ori r31, 0b00100000
70
    sbrc digit2,6
71
    ori r31, 0b00010000
72
    mov r18, digit2
73
    andi r18, 0b00110111
74
    out PORTB, r31
75
    out PORTC, r18
76
77
    ldi  R29, $21
78
    WGLOOP2:  ldi  R30, $64
79
    WGLOOP3:  dec  R30
80
    brne WGLOOP3
81
    dec  R29
82
    brne WGLOOP2
83
84
    ldi r31, 0b00000100
85
    sbrc digit3,7
86
    ori r31, 0b00100000
87
    sbrc digit3,6
88
    ori r31, 0b00010000
89
    mov r18, digit3
90
    andi r18, 0b00111111
91
    ori r18, 0b00001000
92
    out PORTB, r31
93
    out PORTC, r18
94
95
    ldi  R29, $21
96
    WGLOOP4:  ldi  R30, $64
97
    WGLOOP5:  dec  R30
98
    brne WGLOOP5
99
    dec  R29
100
    brne WGLOOP4
101
102
    ldi r31, 0b00001000
103
    sbrc digit4,7
104
    ori r31, 0b00100000
105
    sbrc digit4,6
106
    ori r31, 0b00010000
107
    mov r18, digit4
108
    andi r18, 0b00111111
109
    ori r18, 0b00001000
110
    out PORTB, r31
111
    out PORTC, r18
112
113
    ldi  R29, $21
114
    WGLOOP6:  ldi  R30, $64
115
    WGLOOP7:  dec  R30
116
    brne WGLOOP7
117
    dec  R29
118
    brne WGLOOP6
119
 
120
        rjmp    loop
121
 
122
timer0_overflow:                    ; Timer 0 Overflow Handler
123
 
124
        push    temp1               ; temp 1 sichern
125
        in      temp1,sreg          ; SREG sichern
126
        push    temp1
127
 
128
        inc     SubCount            ; Wenn dies nicht der 15. Interrupt
129
        cpi     SubCount, 60        ; ist, dann passiert gar nichts
130
        brne    end_isr
131
 
132
                                    ; Überlauf
133
        clr     SubCount            ; SubCount rücksetzen
134
        inc     Sekunden            ; plus 1 Sekunde
135
        cpi     Sekunden, 60        ; sind 60 Sekunden vergangen?
136
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon
137
                                    ; gemacht werden
138
 
139
                                    ; Überlauf
140
        clr     Sekunden            ; Sekunden wieder auf 0 und dafür
141
        inc     Minuten             ; plus 1 Minute
142
        cpi     Minuten, 100         ; sind 60 Minuten vergangen ?
143
        brne    Ausgabe             ; wenn nicht, -> Ausgabe
144
 
145
                                    ; Überlauf
146
        clr     Minuten             ; Minuten zurücksetzen und dafür
147
        inc     Stunden             ; plus 1 Stunde
148
        cpi     Stunden, 24         ; nach 24 Stunden, die Stundenanzeige
149
        brne    Ausgabe             ; wieder zurücksetzen
150
 
151
                                    ; Überlauf
152
        clr     Stunden             ; Stunden rücksetzen
153
 
154
Ausgabe: 
155
end_isr:
156
 
157
        pop     temp1
158
        out     sreg,temp1          ; sreg wieder herstellen
159
        pop     temp1
160
        reti                        ; das wars. Interrupt ist fertig
161
162
zehner:                
163
    ldi temp1, 0x00
164
    ldi temp2, 0x00
165
    mov temp1, Minuten
166
        subi    temp1, 10           ; abzählen wieviele Zehner in
167
        brcs    einer        ; der Zahl enthalten sind
168
        inc     temp2
169
        rjmp    zehner
170
einer:
171
        mov r20, temp2
172
    rcall vergleich
173
    mov digit1, r20
174
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
175
                                    ; vorhergehende Schleife 10 zuviel
176
                                    ; abgezogen hat
177
                                    ; das Subtrahieren von -10
178
                                    ; = Addition von +10 ist ein Trick
179
                                    ; da kein addi Befehl existiert
180
        ;ldi     temp2, '0'          ; die übrig gebliebenen Einer
181
        ;add     temp1, temp2        ; noch ausgeben
182
        mov r20, temp1
183
    rcall vergleich
184
    mov digit2, r20
185
zehnerb:                
186
    ldi temp1, 0x00
187
    ldi temp2, 0x00
188
    mov temp1, Sekunden
189
        subi    temp1, 10           ; abzählen wieviele Zehner in
190
        brcs    einerb        ; der Zahl enthalten sind
191
        inc     temp2
192
        rjmp    zehnerb
193
einerb:
194
        mov r20, temp2
195
    rcall vergleich
196
    mov digit3, r20
197
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
198
                                    ; vorhergehende Schleife 10 zuviel
199
                                    ; abgezogen hat
200
                                    ; das Subtrahieren von -10
201
                                    ; = Addition von +10 ist ein Trick
202
                                    ; da kein addi Befehl existiert
203
        ;ldi     temp2, '0'          ; die übrig gebliebenen Einer
204
        ;add     temp1, temp2        ; noch ausgeben
205
        mov r20, temp1
206
    rcall vergleich
207
    mov digit4, r20
208
    ret
209
210
vergleich:
211
    cpi     r20,9
212
    brne    zweig_0
213
  ;9
214
  ldi r20, 0b00001010
215
    rjmp    ende_vergleich
216
zweig_0:
217
    cpi     r20,1
218
    brne    zweig_1
219
  ;1
220
  ldi r20, 0b11101110
221
    rjmp    ende_vergleich
222
zweig_1:
223
    cpi     r20,2
224
    brne    zweig_2
225
  ;2
226
  ldi r20, 0b10011000
227
    rjmp    ende_vergleich
228
zweig_2:
229
    cpi     r20,3
230
    brne    zweig_3
231
  ;3
232
  ldi r20, 0b10001010
233
    rjmp    ende_vergleich
234
zweig_3:
235
    cpi     r20,4
236
    brne    zweig_4
237
  ;4 
238
  ldi r20, 0b01001110
239
    rjmp    ende_vergleich
240
zweig_4:
241
    cpi     r20,5
242
    brne    zweig_5
243
  ;5
244
  ldi r20, 0b00001011
245
    rjmp    ende_vergleich
246
zweig_5:
247
    cpi     r20,6
248
    brne    zweig_6
249
  ;6
250
  ldi r20, 0b00001001
251
    rjmp    ende_vergleich
252
zweig_6:
253
    cpi     r20,7
254
    brne    zweig_7
255
  ;7
256
  ldi r20, 0b10101110
257
    rjmp    ende_vergleich
258
zweig_7:
259
    cpi     r20,8
260
    brne    zweig_8
261
  ;8
262
  ldi r20, 0b00001000
263
    rjmp    ende_vergleich
264
zweig_8:
265
    ;0
266
  ldi r20, 0b00101000
267
ende_vergleich:
268
  ret

von Hannes L. (hannes)


Lesenswert?

Schau mal hier:
Beitrag "Re: 7 Segmentanzeige falsch eingekauft, reagiert nur auf low"
http://www.mikrocontroller.net/attachment/23620/eieruhr1.asm

Achte besonders darauf, wie die Umwandlung Ziffer->Segment-Bitmuster 
erfolgt. Das löst zwar Dein Problem noch nicht, versetzt Dich aber in 
die Lage, etwas effizienteren Code zu schreiben, in dem es auch Spaß 
macht, einen Fehler zu suchen.

Und gib Dir bitte auch etwas mehr Mühe mit den Kommentaren. Es macht 
keinen Spaß, in einem nicht bzw. falsch kommentierten Programm Fehler zu 
suchen. Meine eigene Erfahrung sagt mir, dass man viele Fehler bereits 
(selbst) dadurch findet, dass man das Programm kommentiert, also dass 
man den Programmablauf mit verständlichen Worten beschreibt.

...

von brumbaer (Gast)


Lesenswert?

zehner:
    ldi temp1, 0x00
    ldi temp2, 0x00
    mov temp1, Minuten
        subi    temp1, 10           ; abzählen wieviele Zehner in
        brcs    einer        ; der Zahl enthalten sind
        inc     temp2
        rjmp    zehner

Wenn du mehr als 9 Minuten hast, erhöhst du temp2 und springst nach 
zehner, dadurch setzt tu temp1 wieder auf den Anfangswert und hast eine 
Endlos Schleife.

Eher so was:

zehner:
    ldi temp1, 0x00
    ldi temp2, 0x00
    mov temp1, Minuten
zehner_loop:
        subi    temp1, 10           ; abzählen wieviele Zehner in
        brcs    einer        ; der Zahl enthalten sind
        inc     temp2
        rjmp    zehner_loop

Nach weiteren Schleifen habe ich nicht gesucht.

mfg
SH

von Nils ‫. (n-regen)


Lesenswert?

ES FUNKTIONIERT!

Das Problem war tatsächlich die Endlosschleife, die brumbaer entdeckt 
hat.
Ich habe das Setzen der Register temp1 und temp2 jetzt vor den Aufruf 
von zehner bzw. von zehnerb geschrieben (und den Code ansatzweise 
kommentiert) und jetzt funktioniert die Stoppuhr.
Vielen Dank für deine Hilfe, brumbaer.
Den Vorschlag von Hannes werde ich vielleicht beim Verbessern des Codes 
(nach den Berechnungen aus dem Tutorial geht die Stoppuhr um 1,7% vor, 
das lässt sich sicher noch verbessern) umsetzen.

Hier noch der korrigierte Code:
1
.include "m8def.inc"
2
 
3
.def temp1 = r16
4
.def temp2 = r17
5
 
6
.def SubCount = r21
7
.def Sekunden = r22
8
.def Minuten  = r23
9
10
.def digit1 = r25
11
.def digit2 = r26
12
.def digit3 = r27
13
.def digit4 = r28
14
 
15
.org 0x0000
16
        rjmp    main                ; bei Reset zum Hauptprogramm springen
17
.org OVF0addr
18
        rjmp    timer0_overflow     ; bei Timer-Overflow zur Behandlungsroutine springen
19
 
20
main:
21
        ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren
22
        out     SPL, temp1
23
        ldi     temp1, HIGH(RAMEND)
24
        out     SPH, temp1
25
 
26
        ldi     temp1, 0b00000101   ; Teiler des Timers auf 1024 setzen
27
        out     TCCR0, temp1
28
 
29
        ldi     temp1, 0b00000001   ; TOIE0: Interrupt bei Timer-Overflow
30
        out     TIMSK, temp1
31
 
32
        clr     Minuten             ; Uhr und Digit-Register auf 0 setzen
33
        clr     Sekunden
34
        clr     SubCount
35
    clr digit1
36
    clr digit2
37
    clr digit3
38
    clr digit4
39
40
    ldi r24, 0b11111111      ; Port B und C auf "Ausgabe" schalten
41
    out DDRB, r24
42
    out DDRC, r24
43
 
44
        sei              ; Interrupts aktivieren
45
 
46
loop:   ldi temp1, 0x00
47
    ldi temp2, 0x00
48
    mov temp1, Minuten
49
    rcall zehner        ; Aktuelle Zeit abfragen und digit1-4 entsprechend setzen
50
    ldi r31, 0b00000001      ; erste Ziffer der Anzeige aktivieren
51
    sbrc digit1,7        ;  und digit1 in die benötigten Bitmuster für Port B und C
52
    ori r31, 0b00100000      ;  zerlegen
53
    sbrc digit1,6
54
    ori r31, 0b00010000
55
    mov r18, digit1
56
    andi r18, 0b00111111
57
    ori r18, 0b00001000
58
    out PORTB, r31        ; Bitmuster ausgeben
59
    out PORTC, r18
60
61
    ldi  R29, $21        ; 2,5ms warten
62
    WGLOOP0:  ldi  R30, $64
63
    WGLOOP1:  dec  R30
64
    brne WGLOOP1
65
    dec  R29
66
    brne WGLOOP0
67
68
    ldi r31, 0b00000010      ; zweite Ziffer und Punkt ausgeben
69
    sbrc digit2,7
70
    ori r31, 0b00100000
71
    sbrc digit2,6
72
    ori r31, 0b00010000
73
    mov r18, digit2
74
    andi r18, 0b00110111    ; die 0 bei Bit 3 ist der Punkt
75
    out PORTB, r31
76
    out PORTC, r18
77
78
    ldi  R29, $21        ; 2,5ms warten
79
    WGLOOP2:  ldi  R30, $64
80
    WGLOOP3:  dec  R30
81
    brne WGLOOP3
82
    dec  R29
83
    brne WGLOOP2
84
85
    ldi r31, 0b00000100      ; dritte Ziffer ausgeben
86
    sbrc digit3,7
87
    ori r31, 0b00100000
88
    sbrc digit3,6
89
    ori r31, 0b00010000
90
    mov r18, digit3
91
    andi r18, 0b00111111
92
    ori r18, 0b00001000
93
    out PORTB, r31
94
    out PORTC, r18
95
96
    ldi  R29, $21        ; 2,5ms warten
97
    WGLOOP4:  ldi  R30, $64
98
    WGLOOP5:  dec  R30
99
    brne WGLOOP5
100
    dec  R29
101
    brne WGLOOP4
102
103
    ldi r31, 0b00001000      ; vierte Ziffer ausgeben
104
    sbrc digit4,7
105
    ori r31, 0b00100000
106
    sbrc digit4,6
107
    ori r31, 0b00010000
108
    mov r18, digit4
109
    andi r18, 0b00111111
110
    ori r18, 0b00001000
111
    out PORTB, r31
112
    out PORTC, r18
113
114
    ldi  R29, $21        ; 2,5ms warten
115
    WGLOOP6:  ldi  R30, $64
116
    WGLOOP7:  dec  R30
117
    brne WGLOOP7
118
    dec  R29
119
    brne WGLOOP6
120
 
121
        rjmp    loop
122
 
123
timer0_overflow:                    ; Timer 0 Overflow Handler
124
 
125
        inc     SubCount            ; Wenn dies nicht der 60. Interrupt (Vorteiler 1024, 4MHz, also 60 Interrupts pro Sekunde)
126
        cpi     SubCount, 60        ; ist, dann passiert gar nichts
127
        brne    end_isr
128
 
129
                                    ; Überlauf
130
        clr     SubCount            ; SubCount rücksetzen
131
        inc     Sekunden            ; plus 1 Sekunde
132
        cpi     Sekunden, 60        ; sind 60 Sekunden vergangen?
133
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon
134
                                    ; gemacht werden
135
 
136
                                    ; Überlauf
137
        clr     Sekunden            ; Sekunden wieder auf 0 und dafür
138
        inc     Minuten             ; plus 1 Minute
139
        cpi     Minuten, 100         ; sind 60 Minuten vergangen ?
140
        brne    Ausgabe             ; wenn nicht, -> Ausgabe
141
 
142
                                    ; Überlauf
143
        clr     Minuten             ; Minuten zurücksetzen
144
        brne    Ausgabe             ; und zu reti springen
145
 
146
Ausgabe: 
147
end_isr:
148
        reti                        ; Interrupt-Behandlung abgeschlossen
149
150
zehner:                
151
        subi    temp1, 10           ; vor dem Aufruf von zehner wurde temp1 mit den Minuten gefüllt
152
        brcs    einer            ; Zehnerstellen zählen und pro Zehnerstelle temp2 um 1 erhöhen
153
        inc     temp2
154
        rjmp    zehner
155
einer:
156
        mov r20, temp2
157
    rcall vergleich
158
    mov digit1, r20
159
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
160
                                    ; vorhergehende Schleife 10 zuviel
161
                                    ; abgezogen hat
162
                                    ; das Subtrahieren von -10
163
                                    ; = Addition von +10 ist ein Trick
164
                                    ; da kein addi Befehl existiert
165
        ;ldi     temp2, '0'          ; die übrig gebliebenen Einer
166
        ;add     temp1, temp2        ; noch ausgeben
167
        mov r20, temp1
168
    rcall vergleich
169
    mov digit2, r20
170
    ldi temp1, 0x00
171
    ldi temp2, 0x00
172
    mov temp1, Sekunden
173
zehnerb:                
174
        subi    temp1, 10           ; abzählen wieviele Zehner in
175
        brcs    einerb        ; der Zahl enthalten sind
176
        inc     temp2
177
        rjmp    zehnerb
178
einerb:
179
        mov r20, temp2
180
    rcall vergleich
181
    mov digit3, r20
182
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
183
                                    ; vorhergehende Schleife 10 zuviel
184
                                    ; abgezogen hat
185
                                    ; das Subtrahieren von -10
186
                                    ; = Addition von +10 ist ein Trick
187
                                    ; da kein addi Befehl existiert
188
        ;ldi     temp2, '0'          ; die übrig gebliebenen Einer
189
        ;add     temp1, temp2        ; noch ausgeben
190
        mov r20, temp1
191
    rcall vergleich
192
    mov digit4, r20
193
    ret
194
195
vergleich:
196
    cpi     r20,9
197
    brne    zweig_0
198
  ;9
199
  ldi r20, 0b00001010
200
    rjmp    ende_vergleich
201
zweig_0:
202
    cpi     r20,1
203
    brne    zweig_1
204
  ;1
205
  ldi r20, 0b11101110
206
    rjmp    ende_vergleich
207
zweig_1:
208
    cpi     r20,2
209
    brne    zweig_2
210
  ;2
211
  ldi r20, 0b10011000
212
    rjmp    ende_vergleich
213
zweig_2:
214
    cpi     r20,3
215
    brne    zweig_3
216
  ;3
217
  ldi r20, 0b10001010
218
    rjmp    ende_vergleich
219
zweig_3:
220
    cpi     r20,4
221
    brne    zweig_4
222
  ;4 
223
  ldi r20, 0b01001110
224
    rjmp    ende_vergleich
225
zweig_4:
226
    cpi     r20,5
227
    brne    zweig_5
228
  ;5
229
  ldi r20, 0b00001011
230
    rjmp    ende_vergleich
231
zweig_5:
232
    cpi     r20,6
233
    brne    zweig_6
234
  ;6
235
  ldi r20, 0b00001001
236
    rjmp    ende_vergleich
237
zweig_6:
238
    cpi     r20,7
239
    brne    zweig_7
240
  ;7
241
  ldi r20, 0b10101110
242
    rjmp    ende_vergleich
243
zweig_7:
244
    cpi     r20,8
245
    brne    zweig_8
246
  ;8
247
  ldi r20, 0b00001000
248
    rjmp    ende_vergleich
249
zweig_8:
250
    ;0
251
  ldi r20, 0b00101000
252
ende_vergleich:
253
  ret

von Martin V. (oldmax)


Lesenswert?

Hi
Du hast eine schöne große Programmschleife. Da was zu ändern oder u 
erweitern wird schwierig und irgendwann verlierst du den Überblich. 
Daher empfehle ich dir viel mehr Variable einzusetzen und mehr 
verteilung auf Unterprogramme. Sind diese in sich getestet, kannst du 
sie abhaken. Bei einer Fehlersuche wirst du dankbar sein, nicht immer 
den ganzen Code durchsehen zu müssen. Hier mal ein Vorschlag, ist aber 
nur ein grobes Gerüst:
Ich hab das bei meinem Atmega8 bei 8MHz folgendermaßen gemacht:
1
.DEF ms0    = R4   ; Millisekunden einer
2
.DEF ms1    = R5  ; Millisekunden Zehner
3
.DEF ms2    = R6  ; Millisekunden Hunderter
4
.DEF Sekunden  = R7  ; Sekunden 
5
.DEF Minuten  = R8  ; Minuten 
6
.DEF Stunden  = R9  ; Stunden 
7
8
.DSEG
9
ms0_Var:  .Byte
10
ms1_Var:  .Byte
11
ms2_Var:  .Byte
12
Sek_Var:  .Byte
13
Min_Var:  .Byte
14
Std_Var:  .Byte
15
Segment0:  .Byte  ; Aufnahme vom Bittmuster für die 7 Segmente
16
Segment1:  .Byte  ; zuordnen in einer Initialisierung
17
Segment2:  .Byte   ; in Unterprogramm Set_Segment wird aus einer 
18
Segment3:  .Byte  ; Zahl das Segmentmuster in Anzeige kopiert
19
Segment4:  .Byte  ; welche Zahl dargestellt werden soll steht in 
20
Segment5:  .Byte  ; der Variablen Anz_Nr
21
Segment6:  .Byte
22
Segment7:  .Byte
23
Segment8:  .Byte
24
Segment9:  .Byte
25
Anzeige:  .Byte  ; Anzuzeigendes Bitmuster
26
Anz_Nr:  .Byte  ; Bit Nummer der anzuzeigenden Stelle 
27
Gem_Anz:  .Byte  ; Bit wird geschoben und steuert Anode oder Kathode
Danach am Anfang meines Programmes, nicht in der Programmschleife, 
sondern direkt nach der Stack-Initialisierung das UP für die 
Parametrierung des Timers 1 aufgerufen.
.CSEG
1
Start: .....                         ; Stack setzen
2
          RCALL  Init_Timer1  ; Timer 1 initialisieren 
3
          weitere Initialisierungen
4
Loop:  Read_Port  ; Programmschleife beginne mit Eingaben lesen
5
         ....
6
         Set_Segment  ; Bitmuster für 7Segment setzen
7
  Write_Port  ; Ausgänge schreiben  
8
       RJMP Loop
9
10
; --------- Bereich Unterprogramme -----------
11
12
;-----------Timer 1 Parametrierung -----------
13
;----------aus dem Tutorial angepaßt----------
14
Init_Timer1:  LDI  Temp_Reg, high( 8000 - 1 )
15
    OUT  OCR1AH, Temp_Reg        
16
    LDI  Temp_Reg, low( 8000 - 1 )        
17
    OUT  OCR1AL, Temp_Reg  ; CTC Modus                                   ; Vorteiler auf 1        
18
    LDI  Temp_Reg, ( 1 << WGM12 ) | ( 1 << CS10 )        
19
    OUT  TCCR1B, Temp_Reg         
20
    LDI  Temp_Reg, 1 << OCIE1A          OUT  TIMSK, Temp_Reg
21
    RET
22
 
23
24
;----------Interruptroutine Timer 1 Zeitzähler----------
25
26
isrTimer1:  PUSH  Temp_Reg    ; temp_Reg sichern
27
    IN  Temp_Reg, SREG  ; SREG sichern    
28
    PUSH  Temp_Reg
29
    PUSH  Calc_Reg  
30
    INC  ms0
31
    CPI  ms0, 10
32
    BRLO  End1_Isr
33
    CLR  ms0
34
    INC  ms1
35
    CPI  ms1, 10
36
    BRLO  End1_Isr
37
    CLR  ms1
38
    INC  ms2
39
    CPI  ms2, 10
40
    BRLO  End1_Isr
41
    CLR  ms2
42
    INC  Sekunden  
43
    CPI  Sekunden, 60
44
    BRLO  End1_Isr
45
    CLR  Sekunden
46
    INC  Minuten  
47
    CPI  Minuten, 60                 
48
    BRLO  End1_Isr
49
    CLR  Minuten
50
    INC  Stunden
51
    CPI  Stunden, 24
52
    BRLO  End1_Isr
53
    ;usw
54
End1_Isr:  POP  Calc_Reg
55
    POP  Temp_Reg    
56
    OUT  SREG, Temp_Reg  ; SREG wiederherstellen
57
    POP  Temp_Reg
58
    RETI              ;Ende der Interrupt-Service-Routine
Ich habe mal nicht allzuviele Komentare stehen lassen, aber diese ISR 
zählt die Zeit. Um eine Stoppuhr draus zu machen, kannst du dir ein Bit 
irgendwo setzen und in der ISR abfragen. Nenn die Bytevariable Time_Ctrl
 dann ergänzt du z. B: in der ISR folgendermaßen:
 am Anfang
1
  LDS Temp_Reg, Time_Ctrl ; Kontrollbyte holen
2
  ANDI Temp_Reg, 0b00000001  ; Zählerfreigabe-Bit abfragen
3
  BREQ End1_Isr
Um eine Möglichkeit zur Anzeige von Zwischenwerten zu haben, kopierst du 
am Ende der ISR die Zeitwerte in Variablen
Vorher fragst du aber dein Kontrollbyte, ob der Zähler laufen, oder ob 
die Anzeige stehen bleiben soll
1
End1_Isr:   LDS   Temp_Reg, Time_Ctrl   ; Kontrollbyte holen
2
  ANDI   Temp_Reg, 0b00000010   ; Zähleranzeige aktuell halten
3
  BREQ End2_Isr
4
  STS ms0_Var, ms0      ; Registerwerte in Variablen schreiben
5
  STS ms1_Var, ms1
6
  STS ms2_Var, ms2
7
  STS Sek_Var, sekunden
8
  STS Min_Var, minuten
9
  STS Std_Var, Stunden
10
End2_Isr:  POP ….
Wenn du nun in einer der ms den Aufruf zur Anzeige bringst und dort 
entsprechend durchzählst, das Bit für die Stelle schiebst und die 
Ausgabe an die Anzeige schickst, steht die Anzeige lange genug, damit 
sie erkennbar ist. Willst du diese Werte nun auch mal an einen PC 
schicken, so greifst du auf die Variablen zu. Um das Programm zu 
kontrollieren, kannst du über RS232 und PC mein hier veröffentlichtes 
OpenEye nutzen. Es zeigt dir die Werte im µC in den Variablen sind. Ist 
unter dem Thread "UART mit atmega 16" zu finden.
Ich hoffe, dir weiter geholfen zu haben.
Gruß oldmax

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.