Hallo alle, ich bin irgendwie ein bisschen verwirrt, ich fahre einen Mega32 mit 2Mhz und möchte einen Timer verwenden der einen Interrupt in 0.1ms intervallen aufruft. Nun meine "Rechnungen": 2.000.000 = 1sec 200 = 0.1msec 0.1msec entsprechen 10 Khz. folglich muss ich eine 10KHz taktung erzeugen. in 1 sec vergehen 2.000.000 takte, in 0.1msec folglich also 200. Nun nehme ich mir den 8Bit timer0 vom mega32 im überlauf modus und setze das TCNT0 auf 56 (damit es nach 200 takten überläuft und meine routine aufruft). #define CLK_RATE 10000 #define CNT 256 - (XTAL / CLK_RATE) void init_int_timer() { TCCR0 |= 1 << CS00; TCNT0 = CNT; TIMSK |= (1<<TOIE0); sei(); } ISR(TIMER0_OVF_vect) { static short i = 0; TCNT0 = CNT; i++; if(i == 10000) { add_time(&dset.timeofday, 1); } } Ich schreib das alles so ausführlich weil es nicht richtig funktioniert, das intervall ist zu groß, ich habs mal im Simulator durchgespielt und gesehen das da immer exakt 241 Takte statt 200 vergehen. Wie kann das sein, wo ist mein Fehler? Danke im vorraus, Dennis
Der mega32 wir mit internem 2Mhz Oszilator getaktet, sitzt auf nem STK500, soweit ich weiss haben nur die 16bit timer CTC
Hmm, irgendwas ist hier schräg. Einerseits STK500, andererseits lese ich grad "Simulator". Wenns echte Hardware ist, hätte ich auf unkalibrierten RC-Oszillator getippt. Beim Simulator geht das schlecht.
Timer 0 hat CTC. Beim Mega8 hatte er es noch nicht. Ab ATMega16 haben auch die 8-Bit-Timer PWM und CTC.
Simulator: Hab das im AVR-Studio simuliert nachdem's aufm STK500 halt zu langam lief und da werden mir halt auch die akutelle taktzahl und weiteres ausgegeben... Ich verstehe immer noch nicht wirklich warum das Problem überhaupt besteht
und ansonsten musst du natürlich die Anzahl der Takte berücksichtigen, die vergehen, bevor TCNT nachgeladen wird. Konmmt einerseits auf dein Programm (steht richtig an 1.Stelle), allerdings baut dir der Compiler etliches ein, was du nicht direkt siehst (Sicherung diverser Sachen). Das kann man berücksichtigen, ist allerdings bei einem Compilerupdate/anderen Optimierungseinstellungen und auch schon bei simplen Sourcecode-Änderungen schon wieder ein anderer Wert. CTC-mode ist genau das richtige für sowas.
Dilligent wrote: > Ich verstehe immer noch nicht wirklich warum das Problem überhaupt > besteht Erstmal hat die ISR ne Menge Overhead. 40 Takte sind da zumindest nicht ganz abwegig, immerhin machst Du in der ISR 16-Bit-Operationen. Also mach es mit CTC, dann sollte es präzise klappen. Hast Du die Compiler-Optimierung eingeschaltet? Wenn nicht, dann machen.
Ein paar Takte gehen aufgrund des fehlenden CTC-Modus drauf, das ist klar, denn die Reaktionszeit des Interrupt-Handlers geht so voll ins Timing ein. 41 Takte erscheinen mir dafür aber etwas viel.
Johannes M. wrote:
> ganz abwegig, immerhin machst Du in der ISR 16-Bit-Operationen.
Aber erst nach dem entscheidenen Reload vom TCNT0.
Andreas Kaiser wrote: >> ganz abwegig, immerhin machst Du in der ISR 16-Bit-Operationen. > > Aber erst nach dem entscheidenen Reload vom TCNT0. Richtig. Aber bei bestimmten Operationen in der ISR werden u.U. mehr Register gesichert, als wenn man nur 8-Bit-Fummeleien macht.
Möchte mich bei allen ganz herzlich bedanken, hab im datenblatt nochma nachgeschaut, natürlich hzat der 8Bit timer CTC.. Gut, da ich aber sowieso gerne mal die Taktfrequenz anheben wollte hab ich mich entschieden nun doch einen 16Bit timer zu nehemn und habs nun am laufen. Es scheint auch alles wunderbar zu funktionieren :) #define CLK_RATE 10000 #define CNT XTAL / CLK_RATE void init_int_timer() { /* CTC1 enabled, CLK source */ TCCR1B |= (1<<WGM12) | (1<<CS10); /* Set Counter to 0 */ TCNT1 = 0; /* Interrupt on compare match */ TIMSK |= (1 << OCF1A); OCR1A = CNT - 1; } ISR(TIMER1_COMPA_vect) { static short i = 0; i++; if(i == 10000) { add_time(&dset.timeofday, 1); i = 0; } } Funktioniert wunderbar, (CNT - 1) macht aus irgendeinem Grunde den Timer viel genauer da sonst aus irgendeinem Grunde immer 200 - 202 takte gemacht wurden. Nun gleicht sich das immer wieder von selbst aus, vertsehe ich nicht, funktioniert aber. Wunderbar, dann hab ich ja jetzt einen guten Zeitbezug ;) Schöne Grüße, Dennis
Dilligent wrote: > Funktioniert wunderbar, (CNT - 1) macht aus irgendeinem Grunde den Timer > viel genauer da sonst aus irgendeinem Grunde immer 200 - 202 takte > gemacht wurden. 201 Takte vermute ich mal... Schließlich wird das Compare-Flag erst im der Gleichheit der Werte folgenden Takt gesetzt. Wenn Du nach 200 Takten den Timer zurückgesetzt haben willst, muss im Compare-Register 199 stehen.
Und da du jetzt den Timer 1 benutzt, macht es auch Sinn den OCR Wert auf 1999 hoch zu setzen und dafür nur auf 1000 Interrupts zu warten. Alternativ: den OCR Wert auf 19999 und nur 100 Interrupts. Oder 39999 und 50 Interrupts. Insebsondere die letzten beiden Kombinationen ermöglichen dann, dass dein i in der ISR nur noch ein uint8_t sein muss, was die ISR wiederrum von 16 Bit Arithmetik (zumindest für das i) befreit. Je weniger Interrupts, desto mehr Zeit hat dein µC um dazwischen noch Däumchen zu drehen :-)
Die unschöne 16Bit Arithmetik mag ich auch nicht so unbedingt, leider hab ich aber Signale deren Länge ich mit 0.1msec auflösung auslesen müsste :/ Bleibt mir leider nicht viel übrig, übrigens geht die Uhr ziehmlich vor, 7sec nach 4 minuten, hab daraufhin mal das #define XTAL angepasst, is schon echt viel, (bei 8Mhz jetzt)
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.