Forum: Mikrocontroller und Digitale Elektronik Timer sek zähler


von Lukas G. (lukas88)


Lesenswert?

Hallo zusammen,


Ich teste gerade ein Programm für den Atmega8 das gewünschte Zeitpausen 
per Timer erzeugt. Im Beispiel unten wird mit dem Timer per Interrupt 
ein 1 sek takt generiert, der wiederum das Zählerregister temp5(r20) bei 
jeder Sekunde erhöht.

Will ich jetzt zum beispiel für eine Funktion 5 Sekunden Wartezeit, muss 
ich nur temp5 mit 0 laden, und warten bis das Register den wert 5 
enthält. Folglich sind 5 Sekunden vergangen.  Das mache ich in der 
Hauptschleifen mit:
1
main:
2
3
cpi     temp5,5 ; 5 Sekunden
4
breq  led_stat
5
rjmp  main
6
7
led_stat:
8
9
sbis  PINC,0
10
sbi  PORTC,0
11
sbic  PINC,0
12
cbi  PORTC,0
13
14
ldi  temp5,0 ; Wieder auf 0 und von vorne...
15
16
rjmp    main

Momentan lasse ich damit noch ein LED blinken, damit ich mit dem Oszi 
den Zeitabstand messen kann.

Leider bekomme ich jedes mal nur den 1Hz Takt auf den Oszi, was ja 
eigentlich nicht sein dürfte, da ja temp5 erst die 5 errechen muss, 
damit led_stat ausgeführt wird. Und ich hab keine Ahnung an was das 
liegen mag.



Noch mein gesamter Testcode...

Atmega läuft mit 4MHz, Fuses (E:FF, H:D9, L:E3)
1
;###########################################################################################################################################################
2
.nolist
3
.include "/home/lukas/Dokumente/AVR/includes/m8def.inc"
4
.list
5
6
;**************************************************************
7
;Registerdefinitionen
8
;**************************************************************
9
10
.def    temp     = r16
11
.def    temp2    = r17
12
.def    temp3    = r18
13
.def    temp4    = r19
14
15
.def   temp5   =r20
16
17
;**************************************************************
18
;Konstanten
19
;**************************************************************
20
21
;~ .equ    PD      = PORTD ;Inerruptsempfang
22
23
24
; SPI
25
26
.equ SS         = 1 ;Output active low
27
.equ SDO        = 0 ;Input
28
.equ SCK        = 2 ;Output
29
.equ SDI        = 3 ;Output
30
.equ LED    = 4 ; LED
31
32
;**************************************************************
33
;SRAM
34
;**************************************************************
35
36
.dseg
37
38
sec_counter:          .BYTE 3
39
ms_counter:          .BYTE 1
40
;~ segment_nr:        .BYTE 1
41
42
43
.cseg
44
45
;**************************************************************
46
;UART
47
;**************************************************************
48
49
;Berechnungen
50
;~ .equ F_CPU = 4000000                            ; Systemtakt in Hz
51
;~ .equ BAUD  = 9600                               ; Baudrate
52
53
;~ .equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
54
;~ .equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
55
;~ .equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
56
57
;~ .if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
58
  ;~ .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
59
;~ .endif
60
61
62
;**************************************************************
63
;Vektorentabelle
64
;**************************************************************
65
66
.org 0x0000
67
    rjmp    init
68
    
69
.org 0x0009
70
   rjmp  timerB_overflow      
71
72
73
;**************************************************************
74
;Interruptprogramme (Am ende reti)
75
;**************************************************************
76
timerB_overflow: 
77
78
79
push  temp
80
push  temp2
81
push  temp3
82
push  temp4
83
84
; Sekundenroutine
85
lds     temp,sec_counter
86
lds     temp2,sec_counter+1
87
88
ldi     temp3,LOW(1953)
89
ldi     temp4,HIGH(1953)
90
91
cp      temp3,temp
92
cpc     temp4,temp2
93
breq    sec_counter_zero
94
95
ldi     temp3,1 
96
ldi     temp4,0
97
98
add     temp,temp3
99
adc     temp2,temp4
100
101
sts     sec_counter,temp
102
sts     sec_counter+1,temp2
103
104
rjmp    timer0_exit
105
106
sec_counter_zero:
107
108
ldi     temp,0
109
sts     sec_counter,temp
110
sts     sec_counter+1,temp
111
112
inc   temp5
113
114
115
116
117
timer0_exit:
118
119
pop    temp4
120
pop    temp3
121
pop    temp2
122
pop    temp
123
reti
124
125
126
;**************************************************************
127
;Unterprogramme (Am ende ret)
128
;**************************************************************
129
130
131
;**************************************************************
132
;Initialisierung
133
;**************************************************************
134
135
init:
136
137
;Port (Richung & Pegel)
138
139
ldi     temp,0xFF
140
out     DDRC,temp
141
142
ldi     temp,0x00; F = aus 0 = ein
143
out     PORTC,temp
144
145
146
;Stackpointer init
147
ldi         temp,HIGH(RAMEND) ;Stackpointer HIGH
148
out         SPH,temp
149
ldi         temp,LOW(RAMEND)  ;Stackpointer LOW
150
out         SPL,temp
151
152
153
; Init Timer
154
155
ldi       temp,0b00000010 ; Prescaler auf 8
156
out      TCCR0,temp
157
158
ldi      temp,1 << TOIE0
159
out      TIMSK,temp
160
161
ldi     temp,0
162
sts     sec_counter,temp
163
sts     sec_counter+1,temp
164
165
ldi    temp,0
166
sts    ms_counter,temp
167
168
ldi    temp5,0
169
170
171
172
;Interrupts an INT0
173
174
;ldi     temp,(1<<ISC01)|(1<<ISC00) ; INT0 und INT1 auf fallende Flanke konfigurieren
175
;out     MCUCR,temp
176
177
;ldi     temp,0b01000000 ; INT0 aktivieren adresse 0x0001
178
;out     GIMSK,temp
179
180
;ldi     temp,0b01000000 ; INT0 aktivieren adresse 0x0001
181
;out     GIFR,temp
182
183
184
sei ;Interrupts an
185
186
187
;**************************************************************
188
;Hauprogramm
189
;**************************************************************
190
191
main:
192
193
194
cpi    temp5,5
195
breq  led_stat
196
rjmp  main
197
198
led_stat:
199
200
sbis  PINC,0
201
sbi    PORTC,0
202
sbic  PINC,0
203
cbi    PORTC,0
204
205
ldi    temp5,0
206
rjmp    main

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ich würde im Interrupt auch das Statusregister sichern...

von Stefan F. (Gast)


Lesenswert?

Lukas G. schrieb:
> muss ich nur temp5 mit 0 laden, und warten bis das Register
> den wert 5 enthält.

Nicht ganz. Den Zählerstand 5 erreichst du möglicherweise schon nach 
4,01 Sekunden. Du weißt ja nicht, wann nach dem Zurücksetzen der erste 
Interrupt stattfindet.

von Lukas G. (lukas88)


Lesenswert?

Es hat tatsächlich daran gelegen....

SREG gesichert und funktioniert wie gewünscht!

Scheinbar hat mir der Timer die Prüfung CPI immer 
unterbrochen/verfälscht.


Kenne zwar die SREG Sicherung bei Interrupts, bis jetzt habe ich sie 
jedoch nur mäßig angewandt. Muss ich wohl in Zukunft Standardmäßig 
einbauen, um Konflikte zu vermeiden.

Schon wieder was gelernt....


Vielen Dank!

von Lukas G. (lukas88)


Lesenswert?

Ja ist mir bewusst, darum messe ich auch immer mit dem Oszi nach. Dann 
kann ich gegeben falls die zu erreichenden Zählerstände anpassen. Hab 
ich auch bein 1Hz Takt nachgemessen, und musste ein wenig anpassen.



Vielen Dank.

von Jacko (Gast)


Lesenswert?

SREG sichern ist das eine:
Schön, wenn du das jetzt als "Ohne geht's nicht!" verinnerlicht
hast.

Deine 5 Sekunden Verzögerung sind (unabhängig von SREG & Co.)
vom Prinzip her nur irgendwas von 4...5 Sekunden.

Wenn dir das reicht, OK. Wenn es genauer sein soll, muss dein
Zähler mit Steps von z.B. ms von Null bis 5000 gezählt haben.

von Wolfgang (Gast)


Lesenswert?

Jacko schrieb:
> Wenn dir das reicht, OK. Wenn es genauer sein soll, muss dein
> Zähler mit Steps von z.B. ms von Null bis 5000 gezählt haben.

Meist ist es deutlich günstiger, den Zähler mit dem Wert für die Dauer 
zu initialisieren und dann runter zu zählen. Der Vergleich kann dann 
immer gegen die 0 stattfinden und ist damit unabhängig von der 
gewünschten Verzögerung.

von Stefan F. (Gast)


Lesenswert?

Wolfgang schrieb:
> Meist ist es deutlich günstiger, den Zähler mit dem Wert für die Dauer
> zu initialisieren und dann runter zu zählen.

Ich denke nicht, dass das irgend etwas an der Ungenauigkeit von 4 bis 5 
Sekunden ändert. Auch beim herunterzählen weißt du nicht, wann der erste 
Interrupt stattfindet.

von Wolfgang (Gast)


Lesenswert?

Stefanus F. schrieb:
> Ich denke nicht, dass das irgend etwas an der Ungenauigkeit von 4 bis 5
> Sekunden ändert.

Das ändert nichts am Jitter durch die Zeitdiskretisierung, aber es 
erlaubt die Routine so aufzubauen, dass man sich den Speicher für den 
Endwert sparen kann.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ich würde hier einfach 250x 20ms zählen, dann wäre der Jitter mit +-10ms 
vermutlich in tolerlierbarem Rahmen und der Zähler passt noch in ein 
Byte.

Oder gleich den großen Koffer auspacken, und mit einem 1ms Zyklus und 2 
Bates auf 5000 zählen. Dann wäre der Jitter mit +-500µs vermutlich 
vernachlässigbar...

von Jacko (Gast)


Lesenswert?

... da kann man viel von der Ungenauigkeit durch viel zu
geringe Zeitauflösung erzählen...

Die Leute, die Erfolgserlebnisse suchen, werden irgendwann schon
durch Erfahrung klüger werden. Bei den anderen ist es eh Wurscht.

- Oder habt ihr jeden Einwand von nörgelnden Lehrern  Eltern 
Tanten beherzigt? DANN wärt ihr jetzt so dumm, wie damals! ;-)

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.