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
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
intmain(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
voidinitLEDModule()
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
voidStartTimerLEDModule()
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