Hallo zusammen, ich habe mal eine Frage bgl. des CTC-Modes des Timer0 (AtMega32): Mit welchem Wert muss ich OCR laden, damit unter folgenden Bedingungen eine Interruptroutine 7200mal pro Sekunde aufgerufen wird? 7,372800MHz Baudratenquarz Timer0 mit PreScaler 256 Ich habe es mit OCR=3 ausprobiert, das funktioniert aber nicht richtig, da der INT dann nur 5760mal pro Sekunde aufgerufen wird. Mir ist schon klar, dass ich den Wert von OCR um 1 verringern muss, da der INT erst beim nächsten Timertakt ausgelöst wird, aber m.E. müsste 3 doch stimmen. Schließlich sind 7372800/256/(3+1)=7200. Lade ich OCR mit 2 passt alles. Also mit anderen Worten: Es funktioniert alles, aber ich weiß nicht warum ;-) Wo übersehe ich etwas? Vielen Dank Marcel
Der Interrupt wird ausgelöst, wenn der Timer von 0 auf max umspringt. Also muss der Reloadwert 1 kleiner sein als der gewünschte Teilerfaktor
Hallo, ich dachte er löst aus, wenn er von MAX auf 0 umspringt? Aber genau das ist es ja eigentlich. Dann müsste OCR=3 doch stimmen. Ich möchte doch schließlich die Frequenz durch 4 teilen. Viele Grüße Marcel
Der Fehler steckt nicht in der Berechnung sondern woanders, möglicherweise in dem nicht gezeigten Quellcode oder in der nicht gezeigten Schaltung oder in der nicht erkärten Messmethode :) Dieser Code
1 | // Atmega32 @ 7,372800 MHz
|
2 | #include <avr/io.h> |
3 | #include <avr/interrupt.h> |
4 | |
5 | int main(void) |
6 | {
|
7 | // CTC Modus 2, Prescaler 256
|
8 | TCCR0 = (1<<WGM01)|(1<<CS02); |
9 | OCR0 = (7372800/256)/7200-1; |
10 | TIMSK |= (1<<OCIE0); |
11 | sei(); |
12 | |
13 | while(1) |
14 | {
|
15 | }
|
16 | }
|
17 | |
18 | ISR (TIMER0_COMP_vect) |
19 | {
|
20 | }
|
ruft die ISR mit einer Frequenz von 7200 Hz auf (getestet im AVR Studio Simulator).
Hallo! Vielen Dank für die Info. Ich wollte zuerst einmal die Bestätigung haben, dass ich den CTC-Modus grundsätzlich richtig verstehe. Das wär schon mal OK, mein Weltbild ist gerettet. :-) Den Timer initialisiere ich genauso, wie Du es beschrieben hast. Ist ja auch nicht sonderlich kompliziert. Zur Messmethode: Ich habe in der Timer0_Comp einen Zähler hochzählen lassen und diesen Zählerstand gelegentlich auf einem Display ausgeben lassen. Dann konnte ich mit einer externen Stoppuhr mal nachmessen, wie weit er in 10Sek. kommt. Der Unterschied ist nach 10 Sekunden schon groß genug. Ich WEISS ja jetzt, dass weder ich noch der Timer spinnt, also muss ich den Fehler im Code suchen. Leider ist der (für meine Verhältnisse) schon ziemlich umfangreich geworden... :-( Danke! Marcel
Zur Messmethode... In 10s bei 7200 Schritten pro s muss man 16-Bit Überlauf im Hinterkopf behalten. Deine Zählervariable sollte größer 16-Bit sein (und volatile) also z.B. volatile uint32_t zaehler.
Hallo! Ja, das ist klar. Ich suche jetzt erstmal den Fehler im restlichen Code, wobei die kritischen Codeteile sehr übersichtlich sind:
1 | ISR(TIMER0_COMP_vect) |
2 | {
|
3 | if(counter<0xFFFF) counter++; //Keine Überläufe, bei 0xFFFF stehen bleiben. |
4 | }
|
Der Zähler wird in einer zweiten ISR (wird durch INT0 am externen Pin ausgelöst) zwischengespeichert und anschließend wieder auf 0 zurückgesetzt. Der zwischengespeicherte Zählerstand wird nach der Umrechnung in die richtige Einheit regelmäßig auf einem Display ausgegeben. Das INT0-Intervall liegt zwischen min. ca. 10ms und max. ca. 8s. Hinsichtlich Auflösung der Messung und Intervall der Impulse an INT0 ist 7200/s für meine Anwendung schon OK, wenns denn stimmt. Viele Grüße Marcel
Hallo zusammen, ich krame diesen Thread mal raus um des Rätsels Lösung zu präsentieren: Der AtMega32 ist kaputt. Nach monatelanger Fehlersuche habe ich den in meinen Augen absurdesten Lösungsansatz getestet und den "alten" Mega32 mal aus seiner Fassung genommen und einen neuen eingesetzt. Fuses gesetzt und programmiert: geht! Der Fehler ist reproduzierbar und tritt auf dem einen Mega32 auf, auf dem anderen nicht (gleiches Hexfile). Ich habe keine Ahnung woran es liegt, aber der kaputte Mega32 wertet das OCR0-Register offensichtlich nicht richtig aus. Jetzt läufts endlich. Viele Grüße Marcel
Hallo! Ich nehme alles zurück. Ich habe mich selbst ausgetrickst. Ich hatte im Quellcode wieder OCR0=2 eingetragen. Damit ging es schon immer. Also: Die Fehlerquelle sitzt immer noch vor dem Bildschirm. Hier nochmal mein Code:
1 | void initLEDModule() |
2 | {
|
3 | |
4 | //CTC-Mode, OC0 disconnected
|
5 | |
6 | OCR0=3; //7372800Hz/256/4= 7200. |
7 | |
8 | //OutputCompareInterupt einschalten:
|
9 | |
10 | TIMSK |= (1 << OCIE0); |
11 | |
12 | |
13 | }
|
14 | |
15 | void StartTimerLEDModule() |
16 | {
|
17 | //Hier müssen der Timer und der INT0 eingeschaltet werden.
|
18 | |
19 | //Timer0:
|
20 | TCCR0 = 0b00001100; //Timer0 einschalten (PreScaler auf 256): |
21 | |
22 | |
23 | //INT0-Eingang:
|
24 | DDRD &= ~(PIND2); //PD2=INT0 auf Eingang |
25 | MCUCR |= (1<<ISC01); //INT0 Pin aktivieren |
26 | MCUCR &= ~(1<<ISC00); //Falling Edge |
27 | GICR |= (1<<INT0); //INT einschalten |
28 | sei(); |
29 | |
30 | }
|
Trage ich OCR0=3 ein, wird der Interrupt zu selten ausgelöst, nur 5400 mal anstelle von 7200 mal. Mit OCR0=2 gehts dann, der INT kommt 7200mal pro Sekunde. Lt. Datenblatt sollte aber OCR0=3 für 7200 mal korrekt sein. Zur Erinnerung: Der ATmega32 wird mit 7,3728MHz betrieben. Es ist zum verrückt werden. Zur weiteren Eingrenzung werde ich jetzt mal den OC0 verwenden und mit einem Oszilloskop nachmessen. Viele Grüße Marcel
Hallo! Klar, ich mache gebetsmühlenartig auch immer das gleiche... Ich habe nun herausgefunden, dass der Timer tatsächlich die richtige Frequenz erzeugt, ich habe auch nichts anderes mehr erwartet. Dies konnte ich per Oszilloskop und OC0 prüfen. Ich habe auch im Simulator getestet: es geht. Auch der Rest der Software funktioniert im Simulator. Alle Berechnungen sind korrekt, in den Variablen stehen die richtigen Werte, INTs werden zum richtigen Zeitpunkt ausgelöst. Im ATMega gehts dann nicht mehr. Ich suche aber weiter... ;-) Viele Grüße Marcel
Marcel Sz schrieb: > Ich habe nun herausgefunden, dass der Timer tatsächlich die richtige > Frequenz erzeugt, ich habe auch nichts anderes mehr erwartet. Dies > konnte ich per Oszilloskop und OC0 prüfen. [...] > Im ATMega gehts dann nicht mehr. Reden wir hier von dem gleichen ATmega? D.h. die Hardware-Einheit, die OC0 togglet (?) funktioniert und Du kriegst trotzdem zuwenige Interrupts? Dann verlierst Du anscheinend an anderer Stelle Interrupts, z.B. durch einen anderen IRQ-Handler der sehr lange läuft... Viele Grüße, Simon
Hallo! Ja, der OC0 toggelt mit der korrekten Frequenz. In den Simulation verliere ich auch keine INTs, dort funktioniert alles korrekt. Aber, bevor Ihr noch lange rätselt: Ich bin jetzt erstmal auf Dienstreise und kann mich auch nicht mehr um mein Hobby kümmern. Ich werde später dann mal alles "unnötige" aus dem Code rausschmeißen und das Wesentliche einzeln testen. Danke schon mal Marcel
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.