Hallo :) Ich bins schon wieder (ja, derzeit bin ich leider wirklich lästig). Ich habe einen Atmega8, welcher mit 1MHz läuft mit folgendem Code versehen: ---snip--- #include <avr/io.h> #include <avr/interrupt.h> #include <stdint.h> volatile uint8_t timerStartValue = 155; // Reload Value for Timer0 volatile uint8_t primaryRun = 0; volatile uint8_t secondaryRun = 0; // Interrupt Service Routine every 100 Cycles ISR(TIMER0_OVF_vect) { /* Test for each second: */ primaryRun++; if (primaryRun == 100) { primaryRun = 0; secondaryRun++; } if (secondaryRun == 100) { secondaryRun = 0; PORTB = !(PORTB); } } int main(void) { // Set PortB as output (we only need pins 0...2) PWM_PORT_DIRECTION = 0x00; PWM_PORT = 0x00; // Set values for Timer 0: No Prescaler, Timer start, Preload TCCR0 |= (1 << CS00); TCNT0 = timerStartValue; TIMSK |= (1 << TOIE0); // Enable global interrupts and wait sei(); while(1); } ---snip--- Im Prinzip funktioniert das auch, aber nicht mit dem Timing das ich gerne hätte. Wenn ichs richtig berechnet hätte, müsste er jede Sekunde einmal toggeln. Tut er jedoch nicht. Er toggelt zwar, aber nur alle 2,3 Sekunden (habe 10 mal getoggelt und es hat etwa 23 Sekunden gedauert). Ich habe 1 000 000 Takzyklen / Sekunde. Meine Methode stellt sicher, dass also 10 000 Zyklen mal getoggelt wird (100 * 100). Das heisst doch, ich muss einfach bei jedem 100sten Taktzyklus toggeln. Also setze ich den TCNT0 auf 155 ... er rennt hoch bis 255, dann kommt der Overflow - das wären doch 100 Zyklen - oder denke ich falsch ?
Sorry, natürlich wird meine Methode nicht alle 10000 Zyklen toggeln, aber sie muss 10 000 mal aufgerufen werden, bis sie toggelt.
Ok, natürlich hatte ich die Zeile mit TCNT0 = timerStartValue; ausgekommentiert (in meinem Testwahn). Leider stimmt es jedoch noch immer nicht ganz genau (auch wenns schon recht nahe kommt).
ok, habs nochmal ausgemessen ... 20 Toggles dauern 24 Sekunden - also ein Faktor von 1,2 .. das kann doch nicht die Ungenauigkeit des internen Takts sein, oder ?
> das kann doch nicht die Ungenauigkeit des internen Takts sein, oder?
Nein, aber der Overhead, bis die Overflow-Routine vom Timer 0 gerufen
wird, schließlich lässt du den ja mit Volldampf laufen.
Tu dir einen Gefallen und benutze einen Timerkanal, der CTC-Modus
(clear timer on compare match) beherrscht, dann führt die Hardware den
Reset des Timers beim Erreichen eines bestimmten Zählerstandes ohne
Verzögerung aus. Falls es Timer 0 sein muss, dann erwäge einen
ATmega88 statt des ATmega8 zu benutzen, der kann das auch auf Kanal 0
(und ist ansonsten der designierte Nachfolger des ATmega8).
Wenn's unbedingt Kanal 0 mit ATmega8 sein muss, dann mach den
Vorteiler größer und zirkele aus, wieviel ``fuzz'' du auf den
Ladewert
draufschlagen musst, damit das Timing stimmt. Dennoch wirst du einen
gewissen Jitter in Kauf nehmen müssen, insbesondere dann, wenn es im
System noch andere Interruptquellen gibt (sodass zumindest zeitweise
die Interrupts blockiert sind).
Also verstehe ich das so richtig: Meine Lösung: Wenn bei mir der Overflow auftritt, dann wird die ISR aufgerufen, ausgeführt und dann erst der Timer wieder neu gestartet? Wenn ich nun also Timer1 nehme (ich habe leider nut Atmega8 da), könnte ich den CTC Modus nutzen (WGM12->1), würde in OCR1A einen Wert schreiben und das würde funktionieren? Oder habe ich das jetzt falsch verstanden?
> Meine Lösung: Wenn bei mir der Overflow auftritt, dann wird die ISR > aufgerufen, ausgeführt und dann erst der Timer wieder neu gestartet? Es müssten erst einige Befehle der ISR abgearbeitet werden, bis der TCNT0 zurückgesetzt werden kann. Ohne Prescaler bedeutet ,einige Befehle' aber auch, dass der Timer bereits um einiges weitergezählt hat. Warum Konkunktiv? Du hast ja ganz und gar vergessen, am Anfang von TIMER0_OVF_vect TCNT0 überhaupt wieder auf timerStartValue zu setzen. Übrigens wäre timerStartValue eher ein #define wert, auf keinen Fall aber eine aufwändige `volatile'-Variable. Auch primaryRun und secondaryRun haben keine Notwendigkeit, sie mit `volatile' zu verumständlichen. (Sorry, habe mir den Code vorhin nicht richtig angeguckt.) > Wenn ich nun also Timer1 nehme (ich habe leider nut Atmega8 da), > könnte ich den CTC Modus nutzen (WGM12->1), würde in OCR1A einen > Wert schreiben und das würde funktionieren? So ungefähr ja. Der Unterschied ist, dass die CTC-Logik positiv ist, der Zähler zählt also von 0 bis OCR1A und wird dann von der Hardware auf 0 rückgesetzt. Die Overflow-Logik ist negativ (wenn man sie zur Verkürzung der Zählweite benutzen will), d. h. du lädst den Zähler auf (256 - Zählweite) vor und wartest den Überlauf ab.
also die volatile Lösung war nur eine quick n dirty lösung. Das Setzen des TCNT hatte ich nur vergessen, mitzukopieren (steht aber eh 2 Postings drunter). Dank dir auf jeden Fall mal. Ich werde es jetzt mal mit dem CTC vom 8bit Timer2 probieren :) Herzlichen Dank nochmals derweil :)
omg jetzt bin ich baff ... Hat auf Anhieb funktioniert. Erstes Mal das Programm reingeschrieben, geht ... Dank dir vielmals :) So macht das Spaß :)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.