Hallo,
habe folgendes Problem. Ich möchte eine Stoppuhr programmieren. Habe das
Programm erstmal für die ersten drei Zahlen geschrieben aber in meinem
Programm werden die Zahlen einfach nicht zusammen angezeigt. Jetzt
laufen die zehntel sekunden einmal durch dann wird für eine Zehntel
sekunde auf der zweiten Anzeige eine 1 angezeigt und dann laufen wieder
die zehntel Sekunden bis 10 und dann wird ne 2 angezeigt usw. Die
Sekunden bleiben nicht angezeigt während die Zehntel sekunden
weiterlaufen. Bin dankbar für jede Hilfe.
1
.include <m8def.inc>
2
.cseg
3
.def counter=r0
4
.def count_sekunden2=r1
5
.def count_sekunden=r2
6
7
8
9
.org 0x00
10
rjmp reset
11
12
.org 0x08
13
rjmp timer
14
15
16
reset:
17
18
ldi r16,0xff
19
out ddrc, r16
20
ldi r16,0xff
21
out DDRD,r16
22
ldi r16,0xff
23
out DDRB,r16
24
25
ldi r16, LOW(RAMEND)
26
out spl,r16
27
ldi r16, HIGH(RAMEND)
28
out sph,r16
29
30
ldi r16,0b00000101
31
out tccr1b,r16
32
ldi r17,0xfe
33
ldi r18,0x98
34
out tcnt1h,r17
35
out tcnt1l,r18
36
ldi r16, 0b00000100
37
out timsk,r16
38
ldi r16,0x00
39
mov counter,r16
40
mov count_sekunden2,r16
41
mov count_sekunden,r16
42
ldi r20, 0b00000000 ; Zahl 0 ausgeben
43
ldi r24, 0b00000000
44
ldi r26, 0b00000000
45
ldi r22,0b00000001
46
sei
47
48
start:
49
rjmp start
50
51
52
timer:
53
inc counter ;Zähler um eins erhöhen
54
mov r16,counter
55
56
ldi r19,0b00001101 ;6.Segment von links an
57
out portb,r19
58
59
ldi r17,0xfe
60
ldi r18,0x98
61
out tcnt1h,r17
62
out tcnt1l,r18
63
cpi r16,10
64
brlo zehntelsekunden ;Verzweige nach zehntelsekunden solange R16<10
65
breq null ;Wenn 10 erreicht, verzweige nach null damit die Null angezeigt wird
66
67
rjmp timer
68
69
zehntelsekunden:
70
push r17
71
push r18
72
push r16
73
add r20,r22 ;Anzeige um eins erhöhen
74
out portc,r20 ;ausgeben
75
pop r16
76
pop r18
77
pop r17
78
reti
79
80
null:
81
82
inc count_sekunden
83
mov r23, count_sekunden
84
ldi r20, 0b00000000 ; Zahl 0 ausgeben
85
out portc,r20
86
ldi r16,0x00 ;counter auf null setzen
87
mov counter,r16
88
cpi r23,10
89
brlo sekunden ;Verzweige nach sekunden solange R23<10
90
breq null_sekunden
91
92
93
reti
94
95
sekunden:
96
ldi r19,0b00001100 ;5.Segment von links an weil 1 sekunde vorbei
Hi
Sehr verwirrend.
> ldi r17,0xfe> ldi r18,0x98> out tcnt1h,r17> out tcnt1l,r18
Kannst du dir sparen, wenn du den Timer im CTC-Mode laufen lässt.
>timer:> inc counter ;Zähler um eins erhöhen> mov r16,counter> .....> breq null ;Wenn 10 erreicht, verzweige nach null damit die Null> rjmp timer <------ ???????
Das ist Unsinn
Fang am besten noch einmal von vorn an:
1. Timer im CTC-Mode und in der Interruptroutine zählst du nur die
Zehntel und Sekunden hoch und setzt ein Flag, das dem Hauptprogramm
anzeigt, das neu angezeigt werden muss. Und die Interruptroutine hat nur
ein reti.
2. Die Anzeige verlagerst du zwischen
>start:
und
> rjmp start
MfG Spess
Danke für die Antwort, aber ich verstehe sie nicht. Sorry aber ich bin
noch blutiger Anfänger was heißt ctc Mode und ich bin ja froh das ich es
bis hierhin hinbekommen habe. Gibt es da nicht ne Lösung des Problems
für meinen Quellcode, den habe ich nämlich gerade verstanden?
Hanna schrieb:> weiterlaufen. Bin dankbar für jede Hilfe.
Dein ganzes Programm ist
* verwirrend
* unlogisch
Wie ist deine Hardware eigentlich angeschlossen? Was hast du da
eigentlich für eine Hardware drann?
Bau deinen Interrupt grundsätzlich so auf:
Timer: ; wird alle x Sekundenbruchteile aufgerufen
inc Zähler
1 Sekunde vorbei?
+-- Nein
| Einerstelle der Sekunde erhöhen
| Einerstelle gleich 10?
+-- Nein
| Einerstelle auf 0 setzen
| Zehnerstelle um 1 erhöhen
| Zehnerstelle gleich 6?
+-- Nein
| Zehnerstelle auf 0 setzen
|
|
+-> Zähler ausgeben
Einerstelle ausgeben
Zehnerstelle ausgeben
reti
Mit anderen Worten:
Trenne das Hochzählen (oder Runterzählen) der Uhr stärker von der
Ausgabe. Die Ausgabe fasst du erst mal komplett am Ende der ISR
zusammen.
Hanna schrieb:> bis hierhin hinbekommen habe. Gibt es da nicht ne Lösung des Problems> für meinen Quellcode,
Mit Verlaub (und ohne frech sein zu wollen):
Dein Code ist ziemlicher Müll. Schmeiss ihn weg und fang nochmal von
vorne an, der Code ist nicht zu retten.
Du hast noch nicht verinnerlicht, dass die ISR Aufrufe, die der Timer
auslöst, im Grunde das Ticken der Uhr darstellen. In der ISR braucht es
daher keine Schleife, die auf irgendwas wartet oder wie bei dir einen
Counter hochzählt. Die ISR soll einfach nur einen Timertick
registrieren, indem sie die entsprechenden Zähler um 1 hochzählt,
inklusive aller notwendigen Überläufe. Mehr muss die ISR im Grunde nicht
tun. Da das updaten der Anzeige bei dir anscheinend nicht lange dauert,
kann man das in die ISR reinmachen, besser wäre es allerdings die Dinge
komplett voneinander zu trennen: die ISR kümmert sich um das Hochzählen
der Uhren-Register und in der Hauptschleife wird die Anzeige gemacht.
Hanna schrieb:> Ist die Hauptschleife das start?
Bei dir: Ja.
PS: Du hast genug Register frei. Lege dir nicht selbst eine Beschränkung
auf, in dem du die 'kleinen' Register benutzt, auf die man nur mit einem
eingeschränktem Befehlssatz operieren kann. Es gibt in deinem Code
keinen Grund, warum du ausgerechnet R0 bis R3 für deine Zeiten hernehmen
musst.
1
.....
2
ldi count_sekunden2, 1
3
ldi count_sekunden, 5
4
ldi counter, 0
5
6
start:
7
<hier dein Code>
8
9
rjmp start
Setze an der Stelle <hier dein Code> den Code ein, so dass deine Anzeige
genau das wiederspiegelt, was du vorher den 3 Registern zugewiesen hast.
Egal welche (vernünftigen) Zahlenwerte du den Registern zuweist, die
Anzeige muss diese anzeigen, indem sie mit den Werten in den Registern
etwas sinnvolles macht um daraus die Portwerte zu bestimmen, so dass die
Anzeige richtig ist.
Im gezeigten Beispiel muss auf deiner Anzeige dann eben 15 0 zu sehen
sein.
Und wenn du stattdessen andere Werte angibst, dann müssen eben diese
anderen Werte zu sehen sein.
Das ist dein erster Schritt: Dass die Anzeige immer und unter allen
Umständen das anzeigt, was in den Registern steht. Erst wenn das klappt,
kümmerst du dich darum, dass die Register von deinem Timer systematisch
wie bei einer Uhr hochgezählt werden. Aber erst mal muss die Anzeige
laufen.
Hanna schrieb:> ok danke ich werde es versuchen aber wofür steht> bei:> .....> ldi count_sekunden2, 1> ldi count_sekunden, 5> ldi counter, 0>> die 1,5 und 0 ?
Das sind einfach nur Zahlen die ich erfunden habe. Mit diesen Zahlen
soll auf deiner Anzeige 15 0 stehen.
Gibst du andere Zahlen an
ldi count_sekunden2, 3
ldi count_sekunden, 8
ldi counter, 6
dann muss eben auf deiner Anzeige 38 6 stehen.
Und wenn du
ldi count_sekunden2, 9
ldi count_sekunden, 9
ldi counter, 4
angibst, dann muss auf deiner Anzeige eben 99 4 zu sehen sein.
Wie muss der Code hier
Weiss nicht :(
muss ich jetzt keine Variablen mehr deklarieren?
start:
ldi counter,2
ldi counter2,3
ldi counter3,4
rjmp start
Dann wird 2 3 4 angezeigt meinst du es so?
Hanna schrieb:> Das ist eine Mutiplex-Ansteuerung> AVR-Tutorial: 7-Segment-Anzeige>> das habe ich mir schon durchgelesen bin aber völlig dran gescheitert
Ein Zeichen dafür, dass die Aufgabe im Moment für dich noch viel zu
schwer ist. Deine restlichen Aussagen hier im Forum unterstreichen das
nur noch.
Es hat keinen Sinn, wenn du dir Dinge vornimmst, die weit über deinem
Horizont sind. Fang mit dem Tutorial systematisch von vorne an. Alles
andere ist vergebene Liebesmühe.