Forum: Mikrocontroller und Digitale Elektronik Timer im CTC-MODE


von Sascha D. (plutoonline)


Lesenswert?

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!

von johnny.m (Gast)


Lesenswert?

Wie schaltest Du denn den Pin um (wär echt schön, wenn Du das
komplette Programm geschickt hättest...)? Etwa per Software?

von johnny.m (Gast)


Lesenswert?

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

von Sascha D. (plutoonline)


Lesenswert?

@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();
}

von johnny.m (Gast)


Lesenswert?

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?

von inoffizieller WM-Rahul (Gast)


Lesenswert?

#define SIGNAL(x) ISR(x)

Könnte gehen, wenn man es in das Hauptprogramm schreibt, oder?

von Sascha D. (plutoonline)


Lesenswert?

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 :-(

von johnny.m (Gast)


Lesenswert?

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

von Sascha D. (plutoonline)


Lesenswert?

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

von Sascha D. (plutoonline)


Lesenswert?

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;
}

von johnny.m (Gast)


Lesenswert?

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.

von Sascha D. (plutoonline)


Lesenswert?

Ich hab OCR2=18 initialisiert und bekomme 25us raus da kann doch
irgenwas nicht stimmen:-(

So langsam bin ich am verzweifeln.

von Björn (Gast)


Lesenswert?

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.

von johnny.m (Gast)


Lesenswert?

@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!

von Sascha D. (plutoonline)


Angehängte Dateien:

Lesenswert?

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?

von Sascha D. (plutoonline)


Lesenswert?

achso bei 4MHz.

von Sascha D. (plutoonline)


Lesenswert?

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?

von johnny.m (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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!

von Hubert.G (Gast)


Lesenswert?

Was macht dein Programm wärend der Timer läuft, ich sehe keine
Endlosschleife in main, sowas wie  for(;;){}

von johnny.m (Gast)


Lesenswert?

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.

von Sascha Dürkes (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.