Forum: Mikrocontroller und Digitale Elektronik Problem bei Stoppuhr


von Hanna (Gast)


Lesenswert?

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
97
  out portb,r19
98
  add r24,r22      ;Anzeige um eins erhöhen
99
  out portc,r24    ;ausgeben
100
  reti
101
null_sekunden:
102
  inc count_sekunden2
103
  mov r25, count_sekunden2
104
  
105
  ldi r19,0b00001100    ;5.Segment von links an
106
  out portb,r19
107
  ldi r24, 0b00000000    ; Zahl 0 ausgeben
108
  out portc,r24
109
  ldi r23,0x00      ;counter auf null setzen
110
  mov count_sekunden,r23  
111
112
  cpi r25,6
113
  brlo sekunden2      
114
  breq null_sekunden2
115
116
  reti
117
118
sekunden2:
119
120
121
  ldi r19,0b00001011    ;4.Segment von links an 
122
  out portb,r19
123
  add r26,r22      ;Anzeige um eins erhöhen
124
  out portc,r26    ;ausgeben
125
  reti
126
null_sekunden2:
127
128
  ldi r19,0b00001011    ;4.Segment von links an 
129
  out portb,r19
130
131
  ldi r26, 0b00000000    ; Zahl 0 ausgeben
132
  out portc,r26
133
  ldi r25,0x00      ;counter auf null setzen
134
  mov count_sekunden2,r25  
135
  reti

von spess53 (Gast)


Lesenswert?

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

von Hanna (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hanna (Gast)


Lesenswert?

Das Board ist Atmega8 und die Anzeige avr / Segment ADD-ON.
Hier die Beschreibung:
http://www.myavr.info/download/produkte/my7-Segment-Add-On/techb_my7-Segment-add-on_de_en.pdf

Ist die Hauptschleife das start?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hanna (Gast)


Lesenswert?

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 ?

von Karl H. (kbuchegg)


Lesenswert?

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
1
start:
2
    <hier dein Code>
3
4
    rjmp start
aussehen, damit das erfüllt ist?

von Karl H. (kbuchegg)


Lesenswert?

Hanna schrieb:
> Das Board ist Atmega8 und die Anzeige avr / Segment ADD-ON.
> Hier die Beschreibung:
> 
http://www.myavr.info/download/produkte/my7-Segment-Add-On/techb_my7-Segment-add-on_de_en.pdf

Das ist eine Mutiplex-Ansteuerung
AVR-Tutorial: 7-Segment-Anzeige

von Hanna (Gast)


Lesenswert?

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?

von Hanna (Gast)


Lesenswert?

Das ist eine Mutiplex-Ansteuerung
AVR-Tutorial: 7-Segment-Anzeige

das habe ich mir schon durchgelesen bin aber völlig dran gescheitert

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hanna (Gast)


Lesenswert?

Ok vielen Dank :)

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.