Forum: Compiler & IDEs 100ms Takt mit 16Bit Timer


von Michael K. (michaelkorb)


Lesenswert?

Für mein aktuelles Projekt benötige ich einen möglichst genauen 100ms 
Zyklus. Ich setze den Atmega128 ein mit einer Taktfrequenz von 7,372800 
MHz. Demnach kommt nur ein 16Bit Timer mit Vorteiler 1024 in Frage, der 
bei Erreichen des Vergleichswertes von 720 einen Compare-Interrupt 
auslöst. Trotz eingehender Studie der Datenblätter und zahlreicher 
Versuche will es einfach nicht gelingen. Mit einem 8Bit Timer war ich 
bereits erfolgreich, der 16Bit will einfach nicht das tun was ich will. 
Irgendein Flag sitzt wahrscheinlich falsch.

// 16-Bit-Zähler initialisieren
void initZyklusTimer()
{
  TCCR3B = (1<<CS30) | (1<<CS32);  // Vorteiler 1024
  TCCR3C = (1<<FOC1A);    // Output Compare Match
         // Comparewert
  OCR3CH = 5;
  OCR3CL = 80;
  ETIMSK = (1<<OCIE3A);  // Match Interrupt Kanal A
  ETIFR = (1<<OCF3A);
}

// Interrupt-Routine Timer 3 CompareMatch Kanal A
ISR (TIMER3_COMPA_vect)
{
}

Wer kann helfen?

von johnny.m (Gast)


Lesenswert?

Wenn Du einen 100ms-Takt brauchst, dann musst Du auch dafür sorgen, dass 
der Timer, wenn die 100 ms um sind, also der Compare-Wert erreicht ist, 
zurückgesetzt wird und bei 0 wieder zu zählen anfängt. Du musst ihn also 
im CTC-Modus betreiben. Den musst Du allerdings nach Datenblatt 
einstellen, das macht der Timer nicht von allein...

von Martin (Gast)


Lesenswert?

Was geht denn nicht? Wird die ISR nicht angesprungen, stimmt das Timing 
nicht...?

von johnny.m (Gast)


Lesenswert?

> OCR3CH = 5;
> OCR3CL = 80;
Was soll das denn?

1.: Wenn Du mit WINAVR-C programmierst, solltest Du zum Zugriff auf 
16-Bit-Register auch die in der Headerdatei definierten 16-Bit-Register 
benutzen, allein schon wegen der korrekten Reihenfolge beim Zugriff, 
über die Du Dir dann keine Gedanken mehr machen musst. Also anstatt 
OCR3CH und OCR3CL einfach OCR3C nehmen. In diesem Fall ist die 
Reihenfolge allerdings tatsächlich (zufällig?) richtig...

2.: 5*256 + 80 = 1360. Und das ist definitiv nicht gleich 720! Ich weiß 
nicht, was Du da gerechnet hast, aber so stimmts definitiv nicht. Und tu 
Dir selbst und anderen einen Gefallen und benutze beim getrennten 
Schreiben von Low- und High-Byte keine Dezimalzahlen. Am besten aber 
erst gar keine getrennten Zugriffe, zumindest nicht dann, wenn es die 
Möglichkeit gibt, die 16-Bit-Register als solche anzusprechen (siehe 1.) 
...

3.: Fazit: Wenn es laufen soll, dann Timer im CTC-Modus betreiben 
(Tabelle im Datenblatt gucken, WGM-Bits korrekt setzen) und schreiben
1
OCR3C = 720;
Dann klappts auch mit den Nachbarn...

von johnny.m (Gast)


Lesenswert?

Ach ja, mit der 720 kriegste übrigens auch Probleme. Das OCR3C kann 
nicht direkt als TOP-Wert der CTC verwendet werden. Außerdem würde der 
Pin OC3C mit dem Wert nur alle 100 ms umgeschaltet, was eine Periode von 
200 ms ergäbe. Also sinnvolle Vorgehensweise: CTC-Modus mit OCR1A oder 
ICR1 als TOP. In das TOP-Register die 720 reinschreiben, OCR3C mit 
1/2*720 = 360 beschreiben und den Pin entsprechend konfigurieren. Dann 
sollte es funktionieren und Du hast einen echten 100ms-Takt.

von johnny.m (Gast)


Lesenswert?

Upps, muss oben natürlich "OCR3A" und "ICR3" heißen. So langsam werde 
ich wach...

von Michael K. (michaelkorb)


Lesenswert?

Vielen Dank Leute,

der entscheidende Fehler war der CTC-Modus, den ich nicht eingeschaltet 
hatte. Mit dem hier funktioniert es:

// 16-Bit-Zähler initialisieren
void initZyklusTimer()
{
  // CTC mit OCR3A als TOP, Vorteiler 1024
  TCCR3B = (1<<WGM32) | (1<<CS30) | (1<<CS32);
  TCCR3C = (1<<FOC1A);    // Output Compare Match
  OCR3A = 720;
  ETIMSK = (1<<OCIE3A);  // Compare Match Interrupt Kanal A
  ETIFR = (1<<OCF3A);
}

Bei 7,372800 MHz und Vorteiler 1024 ergibt sich ein Comparewert von 720 
für 100ms.

von Philipp B. (philipp_burch)


Lesenswert?

Hallo Michael,

wenn es sich vermeiden lässt, solltest du nicht unbedingt den CTC-Modus 
verwenden. Aus dem einfachen Grund, das du den Timer dann nur für genau 
diese eine Aufgabe verwenden kannst. Die bessere Lösung wäre, deinen 
OCR-Wert irgendwo als Konstante zu definieren und bei jedem 
Compare-Interrupt das OCR um diese Konstante zu erhöhen. Funktioniert 
einwandfrei und du kannst den Timer auch für den zweiten 
Compare-Interrupt, sowie den Überlauf verwenden. Wenn du ihn sonst aber 
überhaupt nicht verwendest, ist das natürlich nicht unbedingt notwendig.

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.