Timer1-Interrupt alle 20 ms

OP #5356196
Lesenswert?

Hallo zusammen,

ich möchte bei meinem ATmega2561
http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2549-8-bit-AVR-Microcontroller-ATmega640-1280-1281-2560-2561_datasheet.pdf

 mit dem Timer1 alle 50ms bzw. 49,875ms einen Interrupt erzeugen. 
Innerhalb des Interrupts zähle ich jeweils bis 20 hoch und habe somit 
eine Sekunde erreicht. Bei erreichen von 180 Sekunden soll dann eine 
while-Schleife beendet werden. Das klappt soweit, nur, die 
while-Schleife wird ca. 16 Sekunden zu früh beendet.

Woran liegt das?

F_CPU hat den Wert: #define F_CPU 7372800UL

Mein Code:


void Timer1_Frequency(uint8_t freq)
{

  TCCR1B |=
  (1<<CS12) | (1<<CS10) |        // Timer Prescaler 1024
  (1<<WGM12);           // Timer-Mode CTC

  TIMSK1 |= (1<<OCIE1A);         // Interrupt: Output Compare

  OCR1A = (F_CPU/(freq*2*1024)-1);

}

ISR(TIMER1_COMPA_vect)        // Interrupt Output Compare
{
  Timer1_interrupt++;

  if (Timer1_interrupt == 20)
  {
    Timer1_interrupt = 0;
    Timer1_180 = Timer1_180 + 1;
  }
}

Timer1_Frequency wird aus einem anderen Include-File aufgerufen mit:
Timer1_Frequency(171);

Dann folgt sofort die while-Schleife:
while(USART0_i == 0 && Timer1_180 <= 180)
{
 continue;
}
Gast #5356207
Lesenswert?

Du setzt freq auf 171, erwartest also dass die Interrupts mit 171Hz 
kommen, d.h. alle 5,8ms, und gehst dann davon aus dass sie alle 50ms 
kommen? Hä?
Und was ist 7372800 überhaupt für ne komische Zahl...
Gast #5356229
Lesenswert?

Datatom schrieb:
> Wieso läuft die CPU mit 8 mhz, ich dachte die CPU läuft mit dem Quarz-
> Wert?

Hast du die Fuses denn auch so eingestellt dass der Quarz benutzt wird, 
und nicht der interne RC-Oszillator? Die F_CPU Angabe teilt dem Code die 
Frequenz mit, aber stellt die Frequenz/Taktquelle nicht aktiv mit...
#5356243
Lesenswert?

Datatom schrieb:
> 73272800 ist der Quarz.
>
> Wieso läuft die CPU mit 8 mhz, ich dachte die CPU läuft mit dem Quarz-
> Wert?

Natürlich gibt es 7.3728MHz Quarze. Jedoch eher untypisch und für den TO 
eher ungewöhnlich bei seinem Wissensstand.

Somal er bei der Formel (F_CPU/(freq*2*1024)-1) eigentlich schon selbst 
hätte drauf kommen können das da was nicht passt. Ich rechne mal: 
(F_CPU/(50*1024)-1)
Gast #5356247
Lesenswert?

Für einen 16Bit Timer:

Eingangstakt: 7372800Hz
Modus: CTC
Prescaler: 1024
OCRxA: 359

Dann bekommst du einen Compare-Match oder Overvlow alle 50ms

Die Formel lautet:
f_CM = f_IO / ( Prescaler • ( OCRxA + 1 ) )
Gast #5356271
Lesenswert?

Warum eigentlich nicht den Prescaler auf 1024 setzen, OCR1A auf 64799, 
und dann in der ISR von 0-19 zählen? Das ergibt dann exakt
1
7372800 / 1024 / 64800 / 20 = 1/180 Hz
bei minimaler Prozessor-Last (1 Interrupt alle 9sec).
Gast #5356313
Lesenswert?

Thomas H. schrieb:

>  mit dem Timer1 alle 50ms bzw. 49,875ms einen Interrupt erzeugen.

Ja was ist denn nun tatsächlich das Ziel? 50 oder 49,875? Ich gehe mal 
von 50 aus.

> #define F_CPU 7372800UL

Das geht vollkommen problemlos. Denn:

1/50ms = 20 Hz

->

   7372800 = 5^2 * 3^2 * 2^15
-  20           = 5^1          * 2^2
                     ----------------------
                      5^1 * 3^2 * 2^13

-> ganzzahlig teilbar. Damit steht schonmal fest, das die 20Hz exakt
    erreichbar sind.

Es geht also nun nur noch darum, wie man den Teilerfaktor auf die 
Timerbaugruppen verteilt. Der Prescaler kann bis zu 2^10 wegteilen, 
also:

  5^1 * 3^2 * 2^13
-                   2^10
  ----------------------
  5^1 * 3^2 * 2^3  = 360

Sprich: das OCR-Register ist mit 360 - 1 = 359 zu laden und alles ist 
schick.

Tja: zumindest wenn die Kiste tatsächlich mit 7,3728Mhz läuft. Allein 
davon, dass du das als #define hinschschreibst, tut sie das aber noch 
lange nicht...

Übrigens: wenn das Ziel eigentlich garnicht die 20Hz, sondern 1Hz sind, 
geht das auch, wie man leicht erkennen kann:

 360 * 20 = 7200

-> Passt noch locker in das 16Bit-Zählregister.

Sprich: Wenn das eigentliche Ziel 1Hz ist, wird der Interrupt erstens 
viel zu häufig aufgerufen und ist zweitens viel zu kompliziert. Rüstet 
man ihn auf das Nötige ab, bleibt bloß noch das Setzen des Flags übrig. 
Das aber gibt es schon in Hardware, also wird die ISR am Ende des Tages 
vollkommen überflüssig...
OP #5356363
Lesenswert?

Dr. Sommer schrieb:
> Datatom schrieb:
>> Wieso läuft die CPU mit 8 mhz, ich dachte die CPU läuft mit dem Quarz-
>> Wert?
>
> Hast du die Fuses denn auch so eingestellt dass der Quarz benutzt wird,
> und nicht der interne RC-Oszillator? Die F_CPU Angabe teilt dem Code die
> Frequenz mit, aber stellt die Frequenz/Taktquelle nicht aktiv mit...


Hier mein Quarz 7372800 Mhz:
https://www.alvidi.de/shop/product_info.php?language=en&info=p17_Quarz-16-MHz.html

Also die Fuses habe ich folgenermaße eingestellt:
s.Bild

Wobei mir die Start-up time leider nichts sagt:-(
Angehängte Dateien:
Gast #5356403
Lesenswert?

Thomas H. schrieb:

> Also die Fuses habe ich folgenermaße eingestellt:
> s.Bild

Und auch so programmiert? Davon, dass man's einstellt, ist's 
normalerweise noch nicht programmiert. Dazu muß man üblicherweise noch 
irgendeinen Button anklicken, beschriftet mit "Program" o.s.ä....

> Wobei mir die Start-up time leider nichts sagt:-(

Die spielt für den Takt selber keine Rolle, die sorgt nur dafür, dass 
der Quarzoszillator genug Zeit zum Anlaufen bekommt, bevor der Takt 
tatsächlich benutzt wird. Und du hast die "konservativste" Einstellung 
gewählt. Also: die Konfiguration der Fuses an sich ist vollkommen 
korrekt.
OP #5357199
Lesenswert?

Ich habe jetzt einen 16000 Mhz Quarz eingebaut. So wie im 
ATMEL-Beispiel, deshalb.

Wenn ich jetzt den Wert für OCR1A mit folgender Formel berechne:

OCR1A = (F_CPU/(freq*2*256)-1);

und freq = 2 ist, dann sind die 180 Sekunden auch wirklich 180 Sekunden. 
Aber eigentlich müssten doch bei freq = 1 die 180 Sekunden exakt sein.

Oder stimmt die Formel nicht?
Gast #5357244
Lesenswert?

Vielleicht wäre es für den Moment zielführender, ganz ohne Formel die 
Sache naiv anzugehen: 16,000 MHz, daraus soll 1 Hz werden per Timer, 
folglich muss dieser durch 16000000 teilen; der Timer hat feste 
Vorteiler, versuchen wir es mit dem größten, nämlich 1024: 16000000/1024 
= 15625. Also folgt OCR1A = 15625-1 (er beginnt bei 0). Ziehen wir, 
warum auch immer, als Vorteiler 256 vor, so geht auch das: 16000000/256 
= 62500, OCR1A = 62500-1.
  Danach kann man sich selbst eine Formel daraus entwickeln.
OP #5357258
Lesenswert?

Rene K. schrieb:
> Thomas H. schrieb:
>> OCR1A = (F_CPU/(freq*2*256)-1);
>
> Falsch... Wenn dein Vorteilen 256 ist dann DARF dort nicht Frequenz*2
> stehen. Denn dies ist dafür da den Flankenwechsel am Pin auszufüllen -
> wie in deinem Beispiel. Richtig ist:
>
> OCR1A = (F_CPU/(freq*256)-1);

Wenn ich die von dir genannte Formel anwende, dann wird, bei freq = 1, 
der Interrupt 45 x in 180 Sekunden durchlaufen.

Bei einer Frequenz von 1, sollte der Interrupt doch 1 x pro Sekunde 
durchlaufen werden oder nicht?
#5358201
Lesenswert?

... oder auch, wenn eine Frequenz manuell per Bitbanging in einer ISR 
erzeugt werden würde (was man nicht unbedingt machen muss):

ISR wird alle 1 mSek angesprungen und darin ein Pin getoggelt. Dann 
geschieht der Aufruf eben alle mSek und ein Puls- und eine Pausezeit 
sind dann jeweils 1 mSek lang, die Gesamtperiodendauer aber 2 mSek.

Analoges gilt für TAKTERZEUGUNG mittels Hardware.

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