Hallo allerseits,
sitze hier vor einem kleinen Problem und kommen einfach nicht dahinter,
wo der Fehler steckt. Ich muss auf einem einen ATMega 169 eine Uhr
programmieren. Habe mir auch schon das Tutorial dazu angeschaut und
damit versucht, eine Lösung zu finden.
Soweit funktioniert das auch: Ich kann die Uhr einstellen, die Zeit wird
korrekt dargestellt etc.
Das Problem ist der Timer0 den ich verwenden muss. Der Prozessortakt
beträgt 2 MHz, habe mir einen Prescaler von 8 gewählt und verwende den
CTC-Modus des Timers. gezählt wird bis 249, so dass bei jedem 250. Takt
ein Interrupt erzeugt wird. Somit habe ich jede Millisekunde einen
Interrupt. Um nun auf eine Sekunde zu kommen, muss ich doch einfach bis
1000 zählen?
Wenn ich das aber mache, läuft die Uhr etwa 8 mal zu langsam!
Ich zähle jetzt nur noch bis 125, damit treffe ich etwa die Sekunden.
Ich hab aber keinen Plan, an was das liegen könnte? Dachte auch schon
mal, dass vielleicht der Interrupt Handler zu lang ist, aber der braucht
keine Millisekunde (er braucht nur 170µs) und ist dann fertig.
So wie das Programm jetzt läuft, läuft die Uhr nach einer halben Stunde
Betrieb schon 22s vor, das könnte ich natürlich noch ändern indem ich
bis zu einem höheren Wert zähle.
Ich wüsste aber dennoch gerne, woher dieses Problem kommt??
Gruß,
Sebastian.
>Wenn ich das aber mache, läuft die Uhr etwa 8 mal zu langsam!
Schau Dir mal die FUSE Einstellung an!
Bin mir nicht sicher aber meim Mega88 ist standart Einstellung
Fclock/8.
Vielleicht ist das dein Problem!
gruß
Jürgen
Hast du den Prescaler wirklich korrekt gesetzt? Nach 8 kommt 64, was den
Faktor 8 erklären könnte...
Poste mal den relevanten Sourcecode.
Woher bekommt der µC seinen Takt? Wirklich sauberen Takt bekommt man
glaube ich nur von einem externen Quarz.
Macht der µC noch irgend etwas anderes außer die Uhr zu benutzen?
A/D-Conversionen mit Sleep halten meines Wissens nach bspw. die Clk_I/O
und damit die Clk_T0 aus...
Habe den A/D Wandler ausgeschaltet. Der Takt kommt vom internen Quarz,
der ist natürlich immer noch nicht wahnsinnig genau. Er müsste aber doch
in etwa so genau sein.
Hier mal meine Timer Initialisierung:
1
.MACRO Timer_Initialization
2
ldi temp1, 0b00001010 ;set Timer0 Mode (CTC with 8 as presacler)
3
out TCCR0A, temp1
4
5
ldi temp1, 0x00 ;set start value
6
out TCNT0, temp1
7
8
ldi temp1, 0xF9 ;set maximum value, i.e. 2Mhz/(8*250)=1 kHz
9
out OCR0A, temp1
10
11
ldi temp1, 0x02 ;enable Compare Match Interrupts for Timer0
12
sts TIMSK0, temp1
13
14
ldi temp1, 0x03 ;clear Output Compare Match Flags
15
out TIFR0, temp1
16
.ENDMACRO
Die Fuse Einstellungen überprüfe ich nachher mal, wenn ich daheim bin.
Sitz grad in Messtechnik fest^^
Und zum Interrupt Handler:
1
Timer_Interrupt_Handler:
2
cli ;disable interrupts
3
4
ldi temp1, 0x3b
5
ldi temp2, 0x17
6
7
dec counter ;1 second is reached after 8 interrupts
8
brne Return
9
10
; dec counter2
11
ldi counter, 0x7D
12
; brne Return
13
14
; ldi counter2, 0x04 ;reset counter
15
16
cp temp1, second ;check, if the seconds have reached 59,
17
brne increase_sec ;if not, increase them
18
19
cp temp1, minute ;check, if also the minutes have reached 59,
20
brne increase_min ;if not, increase them and reset seconds
21
22
cp temp2, hour ;check, if hour has reached 23, if not, increase them
23
brne increase_hour ;and reset seconds and minutes
24
25
ldi second, 0x00 ;reset time if it switches from 23:59:59 to 00:00:00
26
ldi minute, 0x00
27
ldi hour, 0x00
28
29
call Output
30
31
sei
32
33
reti
In den Subroutinen increase_sec, increase_min und increas_hour werden
natürlich auch jedes Mal ein Output gestartet, Interrupts erlaubt und
mit reti abgeschlossen.
Das auskommentierte counter2 stammt noch von meiner ersten Rechnung, die
Schleife war über eine innere mit 250 und die äußere mit 4 realisiert.
Gruß.
Ich sollte noch hinzufügen: In der Simulation liefert das Programm mit
den im ersten Beitrag genannten Einstellungen Ausgabe in Abständen von
exakt einer Sekunde... Denke daher, dass das Problem irgendwo im µC
liegt. Habe es schon auf 2 unterschiedlichen ausprobiert, gleiches
Problem...
cli und sei kannst du dir sparen. Der Interrupt Call löscht I
automatisch und reti setzt I wieder.
Das 1:8 Verhältnis wird von der Fuse kommen.
Die 22s auf 30min sind 1,2% Abweichung. Das könnte am internen Takt
liegen, der ist halt nicht so toll...
Lösung:
Fuses prüfen und ggf. richtig programmieren.
Externen Quarz für Taktung benutzen; alternativ: die Countervariable zum
Word machen und nicht Sekunden, sondern Minuten zählen (sekundengenaue
Anzeige ist ja trotzdem möglich). Dann kann man den Wert recht genau
anpassen. Das löst allerdings keine Probleme bei
Temperaturabhängigkeiten...
Daher auch mal überlegen, den µC zwischendurch in Idle-Sleep zu setzen,
und ungerauchte Devices abzuschalten (AC muss glaube ich explizit
ausgeschaltet werden), um den Chip kühl zu halten.