Hallo ich habe ein kleines Problem mit dem Timer im CTC-Modus auf einem Mega8 mit 4MHz. Egal was ich in OCR2 einstelle es verändert sich nix... Der Timer sollte bei 4Mhz ohne Prescaler laufen. Bei OCR2=100 sollte also alle 25us der Timer ausgelöst werden. Ich lasse im Programm vom Timer einen Pin toggeln, was auch funktioniert, nur nicht in der richtigen Frequenz. Und wenn ich das OCR2 verändere ändert sich an der Frequenz laut Oszi gar nichts. [so habe ich den Timer initialisiert] void Init_Timer_2(void) { TCCR2 = (1 << WGM21)|(1 << CS20); TIMSK |= (1 << OCIE2); OCR2 = 100; } Vielen Dank schonmal für eure Hilfe!
Wie schaltest Du denn den Pin um (wär echt schön, wenn Du das komplette Programm geschickt hättest...)? Etwa per Software?
Magst net mehr? Na gut, kleiner Tip: Setze das COM20-Bit im TCCR2 und miss direkt am OC2-Pin. Wenn sich dann was ändert, wenn Du OCR2 änderst, dann ist es ein Fehler im Programm. Ansonsten ist es zunächst mal ziemlich mysteriös...
@johnny.m wie gewünscht...... void Init_Timer_2(void) { TCCR2 = (1 << WGM21)|(1 << CS20); TIMSK |= (1 << OCIE2); OCR2 = 100; } SIGNAL(SIG_OUTPUT_COMPARE2) { PORTB ^= (1 << PB0); } int main (void) { DDRB |= (1<<PB0); sei(); Init_Timer_2(); }
Und haste das mit dem OC2-Pin (PB3) mal ausprobiert? Oder ist der anderweitig belegt und nicht zugänglich? Am Programm an sich kann ich keinen Fehler finden. Änderst Du das OCR2 durch neuprogrammieren? BTW: Mach mal bei Gelegenheit ein Update vom WINAVR. SIGNAL ist mittlerweile veraltet. Das geht jetzt mit ISR. Wie es geht steht im AVR-GCC-Tutorial. Die aktuelle AVR-libc-Version unterstützt zwar noch die alten SIGNALs, aber die Frage ist, wie lange noch?
#define SIGNAL(x) ISR(x) Könnte gehen, wenn man es in das Hauptprogramm schreibt, oder?
Also muß es wohl so heissen --> ISR (TIMER2_COMP_vect) { PORTB ^= (1 << PB0); } aber ich glaube nicht das daher der fehler kommt?! Der Timer läuft ja, nur nicht so wie er soll. Habe ich eigentlich den Timer richtig initialisiert? Kann leider im moment nichts testen in auf der Arbeit :-(
Wie schon gesagt, für das, was Du ursprünglich anscheinend wolltest, scheint die Initialisierung korrekt zu sein. Bei so kurzen Zeiten würde ich persönlich aber keinen Pin in einer ISR umschalten sondern eben das Hardware-Feature nutzen. Dafür ist es da. Wenn Du die Einstellungen so wie oben beibehältst und zusätzlich das COM20 im TCCR2 setzt, toggelt der PB3 automatisch bei jedem Compare. Wenigstens zum testen würd ich es ausprobieren...
@johnny.m Ich will natürlich nicht nur einen Pin toggeln sondern ein bestimmtes Signal erzeugen. Das Pin toggeln ist nur zum testen gedacht. Solange ich aber nichtmal das auf die reihe bekommen brauch ich mit dem rest erst gar nicht anzufangen. Vielen Dank erstmal, ich werde dann berichten wenn ich das heute Abend getestet habe.
Bin gestern leider nicht zu testen gekommen. Aber kann es sein das ich bei der Initialisierung einen fehler gemacht habe? Muß vielleicht erst OCR2 gesetzt werden und dann der Timer enabled werden? void Init_Timer_2(void) { TCCR2 = (1 << WGM21)|(1 << CS20); TIMSK |= (1 << OCIE2); OCR2 = 100; }
Nö, das dürfte kaum einen Unterschied machen. Wenn Du den Timer startest und danach erst das OCR schreibst, ist das schlimmste was Dir passieren kann, dass das TCNT zum Zeitpunkt des Schreibens bereits einen höheren Wert hat und dann eben einmal überläuft. Danach müsste aber der korrekte Takt rauskommen.
Ich hab OCR2=18 initialisiert und bekomme 25us raus da kann doch irgenwas nicht stimmen:-( So langsam bin ich am verzweifeln.
Welche Taktfrequenz verwendest du denn...? Variiere mal OCR2 zwischen 15 und 25. Wenn immer 25µs herauskommen, kann es sein das die minmialste Impulslänge welche du mit mit diesem Takt erzeugen kannst 25µs ist. Stimmen denn die Längen bei höheren Werten für OCR2? Hatte ein ähnliches Problem im µs-Bereich. Brauchte 10µs aber konnte minimal 14,3 erzeugen. Hab dann nen größeren Quarz verwendet und alles funktionierte bestens.
@Björn: Der arbeitet, wie er ganz oben geschrieben hat, mit 4 MHz. Da dürfte das keine Rolle spielen. Er sagt ja auch nicht, dass er nicht unter einen bestimmten Wert kommt, sondern dass sich unabhängig von den OCR-Werten angeblich nix ändert. Selbst mit 100 hat es ja anscheinend nicht geklappt!
Ich hab mal ein programm angehängt. Was sollte eures erachtens am Pin B0 rauskommen? Bei mir kommt 2ms High und 18ms Low raus. Rein rechnerisch sollte 0,3ms High und 3,24ms Low rauskommen, oder liege ich da falsch?
Ich hab mal ein bischen rumgetestet, also bei ORC2 kleiner 100 verändert sich nix mehr. Bei allen Werten unter 100 nacht er 25us. Bei Werten über 100 scheint alles korrekt zu laufen. Hat jemand dafür eine Erklärung?
> if (delay == 720) {delay=0;PORTB |= (1 << PB0);} > if (delay <= 80) {PORTB |= (1 << PB0);} Dir scheint nicht klar zu sein, dass wenn delay 720 ist auch das zweite if ausgeführt wird, da Du delay in der ersten if-Abfrage ja wieder auf Null setzt. Da wäre ein else if angebracht! Abgesehen davon solltest Du keine static-Variable in einer ISR deklarieren. Mach delay global! Hast Du es denn wenigstens mal ohne die ganzen Abfragen in der ISR ausprobiert? Oder einfach mal, wie ich Dir geraten hatte, ohne Interrupt, sondern nur hardwaremäßig den Pin toggeln?
Ach ja, wenn Du natürlich jetzt mit so niedrigen Werten (OCR2 = 18) arbeitest, wundert es mich natürlich nicht, dass es schief geht. Was glaubst Du, wie lange die Bearbeitung der ISR dauert? Auf jeden Fall länger als 18 Taktzyklen. Dadurch entgeht Dir auf jeden Fall mindestens jeder zweite Interrupt, möglicherweise eher mehr! Der Einsprung in den Interrupt-Vektor dauert beim Mega8 4 Taktzyklen. Dann kommen 3 Zyklen für den Sprungbefehl in die ISR dazu. Dann werden Register gesichert, was auch noch mal 10-15 Zyklen dauern dürfte. Dann kommt Deine if-Abfrage (sicher so um die 30-40 Zyklen, geschätzt). Der Am Ende werden die Register wieder geladen (noch mal 10-15 Zyklen) und der Rücksprung dauert noch mal 4 Zyklen. Dann noch mindestens ein Befehl im Hauptprogramm (mindestens ein Zyklus) und erst dann kann der nächste Interrupt bearbeitet werden! Also ist es verständlich, dass sich bei Werten unter 100 nix mehr ändert!
Was macht dein Programm wärend der Timer läuft, ich sehe keine Endlosschleife in main, sowas wie for(;;){}
Gehe mal davon aus, dass der Compiler hier automatisch eine Endlosschleife einfügt. Andernfalls hätte Sascha gar nix gemessen... Aber der Einwand ist durchaus berechtigt. Also ein while(1); oder for(;;); ans Ende von main.
So ein Mist, hätte ich ja auch selbst drauf kommen können. Da ist meine Timerroutine wohl etwas zu lang für die kurze Zeit. Da muß ich an die Sache etwas anders dran gehen. Mal sehen wie ich das Ganze Umsetzen kann. Vielen Dank vorerst mal an alle!!!!
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.