Forum: Mikrocontroller und Digitale Elektronik Timer0 CTC Mode, OCR-Frage


von Marcel S. (marcel_74)


Lesenswert?

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

von Ingo (Gast)


Lesenswert?

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

von Marcel S. (marcel_74)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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).

von Marcel S. (marcel_74)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Marcel S. (marcel_74)


Lesenswert?

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

von Marcel S. (marcel_74)


Lesenswert?

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

von Marcel S. (marcel_74)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich kann mich leider nur wiederholen:
Beitrag "Re: Timer0 CTC Mode, OCR-Frage"

von Marcel S. (marcel_74)


Lesenswert?

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

von Simon B. (nomis)


Lesenswert?

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

von Marcel S. (marcel_74)


Lesenswert?

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
Noch kein Account? Hier anmelden.