Forum: Mikrocontroller und Digitale Elektronik Timer0 bei ATMega 169


von S. N. (sp00ky-n1)


Lesenswert?

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.

von Michael U. (amiga)


Lesenswert?

Hallo,

mal ganz einfach gesagt: Deine Rechnung stimmt, also muß Dein Programm 
einen Fehler haben.

Das kennen wir aber nicht...

Gruß aus Berlin
Michael

von Jürgen (Gast)


Lesenswert?

>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

von wjunky (Gast)


Lesenswert?

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...

von S. N. (sp00ky-n1)


Lesenswert?

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ß.

von S. N. (sp00ky-n1)


Lesenswert?

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...

von Johannes M. (johnny-m)


Lesenswert?

Ich tendiere auch dahin, dass die CKDIV8-Fuse programmiert ist 
(Auslieferungszustand). Ist ein sehr verbreiteter Fehler.

von wjunky (Gast)


Lesenswert?

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.

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.