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; }
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...
Dr. Sommer schrieb: > Und was ist 7372800 überhaupt für ne komische Zahl... Für einen Baudraten-Quarz ist das gar nicht so komisch... MfG Paul
Und die 2 in der OCR1A-Formel ist auch falsch. Ja, im Datenblatt steht die Formel so, aber die ist gedacht für "Frequenz des Ausgangssignals bei Toggeln des Pins". Für "Frequenz im Sinne von Interrupthäufigkeit" muss die 2 weg.
Andreas B. schrieb: > #define F_CPU 7372800UL > > und die CPU läuft vermutlic mit 8Mhz 73272800 ist der Quarz. Wieso läuft die CPU mit 8 mhz, ich dachte die CPU läuft mit dem Quarz- Wert?
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...
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)
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 ) )
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).
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...
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:-(
:
Bearbeitet durch User
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.
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?
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);
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.
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?
Thomas H. schrieb: > Oder stimmt die Formel nicht? Das habe ich dir weiter oben doch schon erklärt. Das "Freq" in dieser Formel steht für was anderes, als du denkst.
Thomas H. schrieb: > Bei einer Frequenz von 1, sollte der Interrupt doch 1 x pro Sekunde > durchlaufen werden oder nicht? Eben nicht. Das freq in der Formel steht für die Frequenz eines Ausgangssignsls, wenn im Interrupt (oder direkt per Compare Match) ein Pin ge-toggle-t wird. Daher der Faktor 2. Edit: Mit "Formel" meine ich die im Datenblatt.
:
Bearbeitet durch User
... 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.
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.