Frequenz vom Timer

OP #283570
Lesenswert?

Ich versuche mit der folgenden Timerkonfig die Frequenz von einem Hz auf
einem ATMEGA16 zu erzeugen. Der Interruppt wird auch aufgerufen, aber
wesentlich öfter als einmal pro Sekunde. Die Formel stammt aus dem
Datenblatt von Seite 100.

    // CLK/64 Prescaler, Lösche Counter bei compareA match

    TCCR1B = (1<<CS10) | (1<<CS11)  | (1<<WGM12);
    OCR1A = ((F_CPU/2/64)-1);    // hier sollte jetzt 1 Hz rauskommen
    TIMSK = (1<<OCIE1A);      // Output Compare-Interrupt aktivieren
  sei();              // Globale Ints aktivieren

Sieht jmd hier einen entscheidenden Fehler, warum da mehr als 1 Hz
generiert wird? Ich hab irgendwie mittlerweile ein Blackout.
Gast #283573
Lesenswert?

>Die Formel auf Seite 100 bezieht sich auf fclk_io,
>die halb so hoch wie die CPU Frequenz ist

Achso, wo steht denn diese Falle beschrieben, das ich das übersehen
hab? Muss ich heute Abend mal testen, indem ich einfach nochmals durch
Zwei teile... Erst mal Danke, an dieser Stelle.

Das mit dem 8 Mhz sollte kein Thema darstellen, da nur ein 7,3
MHz-Quarz  angeschlossen ist.
Gast #283574
Lesenswert?

>indem ich einfach nochmals durch Zwei teile...

eben NICHT, sondern mit zwei multiplizieren.
Dann reduziert sich der maximal Takt aber auf 4,194... MHz
==> den Vorteiler vergrößern.
Gast #283577
Lesenswert?

Tobias,
ich denke dein Problem beruht auf einem Missverstaendnis. Die Formel
gilt fuer den CTC mode des timers, dein Timer laeuft aber im normal
mode (oder ?). Da wird der Timercounter mit F_CPU hochgezaehlt. Das
heisst bei 7.3MHz und einem Teiler 64 kommst du in einer Sekunde auf
ca. 114.000 ticks. Da dein Zaehler aber nur 16 bit breit ist und damit
nur bis 65535 zaehlt dauert es nur 0.57 Sekunden bis zum Ueberlauf,
wass dann 1,7 Hz entspricht.

  Daz
Gast #283580
Lesenswert?

Man, ich sollte mir ne Brille kaufen. Hast Recht. Allerdings : Die
Formel gilt fuer die Berechnung der Signal-Frequenz am OC1A pin. Im
Diagramm siehst du aber auch, dass jedesmal wenn der counter den OCR1A
Wert erreicht ein interrupt generiert wird und der output getoggelt
wird. Fuer einen output toggle cycle muss also zwei Mal der counter
durchlaufen und dabei zwei interrupts generieren. Lange Rede : kurze
Sinn : du bekommst interrupts mit 2Hz wenn dein OC1A Signal 1 Hz hat.

  Daz
OP #283585
Lesenswert?

Leute, ich häng an dem Problem einfach fest: Ich habe den Prescaler
jetzt am Maximum von 1024 und die Formel (von der ich eigentlich
annehmen muss, das sie stimmt) NICHT verändert. Ich habe also nicht den
tatsächlichen Prescalerwert eingesetzt, sondern rumeperimentiert und
kleinere Werte genommen, um die Interrupts zu drosseln. Es stimmt aber
hinten und vorne nicht.

Ich hab mich auch zig mal versichert, das der Quarz wirklich nur 7,3
MHz hat. Woran liegt es, das das einfach nicht hinhaut und da 1 Int /
Sekunde generiert wird?
Gast #283586
Lesenswert?

Wenn du den takt durch 64 teilst kommt 114062 raus. Das heist der
Counter zählt in einer Sekunde bis 114062. In den OCR1A schreibst du
aber 57031 hinein (laut Rechnung) daher sollte der Takt der herauskommt
dann 0,5 sek sein. Soweit ich das in der Schnelligkeit überblicke.

Prescaler 256 und in OCR1A F_CPU/256 dann sollte in etwa das richtige
herauskommen. Genau ist es nicht, da müsste der Quarz genau teilbar
sein.

Hubert
OP #283587
Lesenswert?

Problem ist gelöst, zwar unschön per Trial'n'Error aber wenigstens hab
ich jetzt ungefähr ne Sekunde. Hier die neuen Codezeilen, wobei ich
immernoch nicht genau verstanden hab, warum das genau so jetzt geht
(vgl. ersten Post):

    TCCR1B = (1<<CS12) | (1<<WGM12);
    OCR1A = ((F_CPU/256)-1);    // 1 Hz für den Interrupt
#283588
Lesenswert?

Das ganze hab ich auf einem AT 90S8515 getestet.
Müste aber im Prinzip auf jeden Typ laufen.
(Timer anpassen)
int main(void)
{
TCCR1B = (1<<CS10) | (1<<CS11);   //setzt den Prescaler 64
OCR1A = 62500;                    //setzt den Vergleichswert
TCNT1 = 0;                        //startewert des Counters
TIMSK = 1<<OCIE1A;                //Compare-Int aktivieren
sei();                            //globale Ints aktivieren
}

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
 //wird ausgeführt wenn der Counterwert mit dem Vergleichswert
übereinstimmt
  // Uhrenroutine
  s++;  // s jede Sekunde um 1 erhöhen
  TCNT1 = 0; //timer 1 auf null

for (;;)
{Programm}
}

OCR1A = 62500;  errechnet mit der Formel:

OutpurCompare = Fosc/prescaler * Tsoll
z.B.:
OCR1A = 4000000Mhz/64 * 1 = 62500

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren