Hallo.
Ich bin zurzeit dabei mich in die AVR Welt einzuarbeiten. Dabei bin ich
auf den Artikel
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR
gestoßen. Ich habe das ganze für de n ATMega168 angepasst aud gebe die
entsprechenden Werte (ms, s, m und h) auf einem 20x4 Display aus. Es
sieht subjektiv betrachtet soweit ok aus. Trotzdem hänge ich an einem
Gedanken/Problem fest. Bei mir ist auf dem Board ein 16MHz Quarz drauf.
Über den Prescaler von 64 bekommt der Timer 250.000 mal pro Sekunde
einen Impuls. Daher soll nach 250 Impulsen ein Compare Interrupt
ausgelöst werden (Zeile: OCR0A = 250;). D.h. jede ms gibts einen Compare
Int und ein entsprechender Counter kann incrementiert werden. Bedeutet
das jetzt, dass der Timer beim 250 Impuls einen Int auslöst, der
MilliSek-Counter wird erhöht, dann Zählt der Timer weiter bis 255 und
dann fängt er wieder bei 0 an, zählt wieder bis 255 und löst vorher bei
250 wieder einen Compare Int aus. Das würde ja bedeuten, dass sich ein
Fehler von 5 Timer-Taken einschleicht, oder? Müsste nicht beim Auslösen
den Compare Int das Zählregister des Timers auf 0 zurück gesetzt werden?
Ich hatte das testweise mal mit einem Prescaler von 256 probiert und
OCR0A = 63. Sah rein subjektiv genauso gut aus(Counter für Sek wurde im
Display etwa im SekundenTakt aktualisiert), obwohl hier der Fehler viel
größer sein müsste, wenn der Timer bis 255 wiederzählt und dann bei 0
beginnt und wieder bei 63 einen Comp Int auslöst. Hab ich da irgendetwas
übersehen?
Auszug auf meinem Code:
1 | // Timer-Compare Test-Funktion
|
2 | void start_timer_compare()
|
3 | {
|
4 | char Buffer[20];
|
5 |
|
6 | /* Timer0 ( 8 bit ) konfigurieren */
|
7 | TCCR0A |= (1<<WGM01);
|
8 | TCCR0B |= ((1<<CS01)|(1<<CS00));
|
9 | // 1; Timer0 Vorteiler: 64 -> bei 16 MHz:
|
10 | // 16.000.000 / 64 = 250000 Mal pro Sek gibts einen Takt an den Timer
|
11 |
|
12 | OCR0A = 250;
|
13 | // Timer0 soll bei 250 einen Output Compare Interrupt auslösen ->
|
14 | // 250.000 / 250 = 1000 mal pro Sek gibts einen Interrupt
|
15 |
|
16 | //Compare Interrupt aktivieren
|
17 | TIMSK0 |= (1<<OCIE0A);
|
18 |
|
19 | //Globale Interrupts aktivieren
|
20 | sei();
|
21 |
|
22 | while(1)
|
23 | {
|
24 | // DisplayAsgabe
|
25 | // eine virtel Sekunde warten bis zur nächsten Anzeige
|
26 | _delay_ms( 250 );
|
27 | }
|
28 |
|
29 | return;
|
30 | }
|
31 |
|
32 | // Der Compare Interrupt Handler
|
33 | // Wird aufgerufen wenn OCR0B = 250
|
34 | ISR (TIMER0_COMPA_vect)
|
35 | {
|
36 | millisekunden++;
|
37 |
|
38 | if( millisekunden == 1000 )
|
39 | {
|
40 | sekunde++;
|
41 | millisekunden = 0;
|
42 |
|
43 | if(sekunde == 60)
|
44 | {
|
45 | minute++;
|
46 | sekunde = 0;
|
47 | }
|
48 |
|
49 | if(minute == 60)
|
50 | {
|
51 | stunde++;
|
52 | minute = 0;
|
53 | }
|
54 | }
|
55 | }
|