Forum: Mikrocontroller und Digitale Elektronik Atmega32 Timer mit CTC-Modus


von Dietmar P. (dietmar2)


Lesenswert?

Hallo,

wieder einmal CTC-Modus.

Ich kann in das Vergleichsregister OCR1A eingeben was ich will, die 
Taktfrequenz der LED an Port A verändert sich nicht.
1
// Timer Testprogramm
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <stdint.h>
6
7
  volatile unsigned int Counter1 = 0;  // Zähler für Timer
8
  volatile unsigned int Counter2 = 0;  // Zähler für Timer
9
10
  ISR (TIMER1_COMPA_vect)
11
12
  {
13
    Counter1++;
14
    Counter2++;
15
  }
16
17
int main(void)
18
{  
19
  
20
  DDRA = 0xff;    // PORTA auf Ausgang
21
  
22
// ********** Timer init ******
23
24
  TCCR1A = ( 1<<WGM01);      // CTC Modus
25
  TCCR1B = ( 1 << CS00 );      // Vorteiler: 1
26
  OCR1A = 127;          // Vergleichregister Wert setzen
27
  TIMSK |= (1<<OCIE1A);       // Overflow Interrupt für Vergleichsregister einschalten
28
29
  sei();         // Interrupts aktivieren
30
  
31
 
32
  // ***** HAUPTROUTINE ******
33
34
  while(1){
35
36
  if (Counter1 >= 2){      // entspricht Takt ca. 0,25 Sekunde
37
  Counter1 = 0;
38
  PORTA ^= (1 << 0);    // PortA Pin0 high/low umschalten
39
     }
40
41
    if (Counter2 >= 4){      // entspricht Takt ca. 0,5 Sekunde
42
  Counter2 = 0;
43
  PORTA ^= (1 << 1);    // PortA Pin1 high/low umschalten
44
     }
45
     
46
  }  //while 
47
}//main

Was habe ich da verkehrt gemacht?
Danke für Eure Hilfe.

von Karl H. (kbuchegg)


Lesenswert?

Mir scheint du hast irrtümlicherweise die Konfigurationsbits vom Timer 0 
genommen und auf den Timer 1 angewendet.

Mit genügend Datenblattstudium kriegt man sicherlich raus, was du da 
beim Timer 1 wirklich eingestellt hat, aber das ist ne Menge Aufwand. 
Nimm erst mal nur die richtigen Konfigurationsbits für den Timer 1

von Shuzz (Gast)


Lesenswert?

Ich würde den Timer hier auch nicht ohne Vorteiler laufen lassen.
Wenn Du Zeitspannen von 0.25 bzw. 0.5 Sekunden haben möchtest dann würde 
ich nen Vorteiler von 512 nehmen.
Damit wird der Timer bei 8MHz Takt nur noch ca. 15000 Mal pro Sekunde 
hochgezählt und Du kannst schön über OCR1A die genaue Zeitspanne 
zwischen den Interrupts einstellen.

von ich (Gast)


Lesenswert?

1
// ********** Timer init ******
2
3
  TCCR1A = ( 1<<WGM01);      // CTC Modus
4
  TCCR1B = ( 1 << CS00 );    // Vorteiler: 1
5
  OCR1A = 127;          // Vergleichregister Wert setzen
6
  TIMSK |= (1<<OCIE1A);       // Overflow Interrupt für Vergleichsregister  einschalten

also ich weiß nicht, wie du die Init geschrieben hast oder wo du die her 
hast, aber wenn ich deine Kommentare mit dem Datenblatt vergleiche, hast 
du genau das eingestellt, was du nicht haben willst.

Nimm doch das Datenblatt und sieh nach was du eingestellt und was du 
einstellen wolltest.

von Dietmar P. (dietmar2)


Lesenswert?

Ja, da habe ich etwas gemixt.
In meiner Anwendung, wofür ich gerade mit dem Timer1 teste habe ich den 
Timer0 laufen, ohne CTC.

Mein Atmega32 läuft mit dem internen Takt von 1 MHz und ich benötige 
einen zweiten Timer mit CTC, weil ich eine Frequenz von ca. 8 kHz 
brauche. Dies soll ein Signal für einen Alarmsummer werden. Diese 8 kHz 
will ich dann über über eine weitere Frequenz von 0,5 Hz nochmals 
takten, also ein getakteter Piepton.

Mein Timer-Init habe ich nach dem Datenblatt, soweit ich das verstanden 
habe, geändert:
1
  TCCR1A = ( 1<< WGM12);      // CTC Modus
2
  TCCR1B = ( 1 << CS10 );      // Vorteiler: 1
3
  OCR1A = 127;          // Vergleichregister Wert setzen
4
  TIMSK |= (1<<OCIE1A);       // Overflow Interrupt für Vergleichsregister einschalten

Die Frequenz kann ich ja dann über den Counter bzw. den Wert des 
Vergleichsregisters anpassen.

Wäre toll, wenn Ihr mir weiter helfen würdet.

von Karl H. (kbuchegg)


Lesenswert?

Dietmar P. schrieb:

> Wäre toll, wenn Ihr mir weiter helfen würdet.

Hast du das schon ausprobiert?

Noch ein Tip:
Im AVR Studio hast du einen Simulator. Auch wenn der so manchen Bug hat, 
mit den CTC Modi kommt der aber wunderbar klar.

von ich (Gast)


Lesenswert?

> TCCR1A = ( 1<< WGM12);      // CTC Modus

WGM12 ist nicht TCCR1A Register sondern im TCCR1B-Register.

von Dietmar P. (dietmar2)


Lesenswert?

Ausprobiert und .... geht nicht.

Ich habe kein AVR-Studio, ich arbeite mit Linux und avrdude.

Habe aufgrund des Hinweises von "ich" nochmals im Datenblatt 
nachgesehen. Danach dürfte beim Timer 1 Teil A kein CTC gehen, nur bei 
B, also das Init umgebaut:
1
  ISR (TIMER1_COMPB_vect)
2
3
  TCCR1B = ( 1<< WGM12);    // CTC Modus
4
  TCCR1B = ( 1 << CS10 );   // Vorteiler: 1
5
  OCR1B = 257;        // Vergleichregister Wert setzen
6
  TIMSK |= (1<<OCIE1B);     // Overflow Interrupt für V.-Reg.einschalten

Die LED von Port A takten nach wie vor mit ca. 0,25 und 0,5 Hz.

Hat jemand noch eine Idee, was ich noch falsch habe?
Die Datenblätter sind ja ganz gut, wenn man weiß was der einzelne 
Parameter tut und nur den Inhalt braucht, wenn aber die notwendige 
Kombination nicht kennt, dann rennt man halt immer wieder an die Wand.

von Karl H. (kbuchegg)


Lesenswert?

Dietmar P. schrieb:
> Ausprobiert und .... geht nicht.
>
> Ich habe kein AVR-Studio, ich arbeite mit Linux und avrdude.

OK.
Dann bist du entschuldigt.
Im AVR Studio sieht man solche Sachen nämlich ziemlich gut :-)


> nachgesehen. Danach dürfte beim Timer 1 Teil A kein CTC gehen, nur bei
> B, also das Init umgebaut:

Leider jedoch falsch
>
>   ISR (TIMER1_COMPB_vect)
>
>   TCCR1B = ( 1<< WGM12);    // CTC Modus
>   TCCR1B = ( 1 << CS10 );   // Vorteiler: 1

Mit dieser Zuweisung überschreibst du TCCR1B komplett. Also auch das 
WGM12 Bit, das danach wieder 0 ist

     TCCR1B |= ( 1 << CS10 );   // Vorteiler: 1

oder aber besser

     TCCR1B = (1<<WGM12) | (1<<CS10);   // CTC Modus, Vorteiler 1

von ich (Gast)


Lesenswert?

Also ich würde die INIT so machen, weiß aber nicht, ob es funktioniert, 
da ich es nicht ausprobieren kann.
1
TCCR1B = (1<<WGM12)|(1<<CS10);
2
OCR1A = vergleichtwert;
3
TIMSK |= (1<<OCIE1A);

Und dann diese ISR verwenden ISR (TIMER1_COMPA_vect).

von Dietmar P. (dietmar2)


Lesenswert?

OK, geändert.
Jetzt leuchten die LED aber dauernd.

Irgendwie werde ich den Verdacht nicht los, dass da noch etwas fehlt. Im 
Datenblatt steht da etwas von einem "I-flag":

• Bit 3 – OCIE1B: Timer/Counter1, Output Compare B Match Interrupt 
Enable
When this bit is written to one, and the I-flag in the Status Register 
is set (interrupts globally enabled), the Timer/Counter1 Output Compare 
B match interrupt is enabled. The corresponding Interrupt Vector (See 
“Interrupts” on page 44.) is executed when the OCF1B Flag, located in 
TIFR, is set.

Das verstehe ich allerdings nicht ganz.

Das Init sieht jetzt so aus:

[c]
  TCCR1B = (1<<WGM12) | (1<<CS10);   // CTC Modus, Vorteiler 1
  OCR1B = 20;        // Vergleichregister Wert setzen
  TIMSK |= (1<<OCIE1B);     // Overflow Interrupt für V.-Reg.einschalten
  sei();         // Interrupts aktivieren

von ich (Gast)


Lesenswert?

Stell mal bitte das ganze geänderte Programm noch mal rein.

von Justus S. (jussa)


Lesenswert?

Dietmar P. schrieb:
> Irgendwie werde ich den Verdacht nicht los, dass da noch etwas fehlt. Im
> Datenblatt steht da etwas von einem "I-flag":

> When this bit is written to one, and the I-flag in the Status Register
> is set (interrupts globally enabled),

seufz

>   sei();         // Interrupts aktivieren

von Karl H. (kbuchegg)


Lesenswert?

Dietmar P. schrieb:
> OK, geändert.
> Jetzt leuchten die LED aber dauernd.

Dann rechne mal ein wenig!

Du betreibst deinen µC mit 1 Mhz

Bei einem Vorteiler von 1 würde der Timer, wenn er könnte, in 1 Sekunde 
daher bis 1 Million zählen.

Jetzt lässt du ihn aber nicht bis 1 Million zählen, sondern nur bis 20

Wie lange braucht er dafür?


        1000000    .....    1 Sekunde
             20    .....    x Sekunden
      -----------------------------------

                 20 * 1
            x = ---------  = 0.00002 Sekunden
                 1000000

Alle 0.00002 Sekunden schaltest du den Port von 0 auf 1 bzw 1 auf 0.
Da f = 1 / t
ist bedeutet das, dass du den Port mit   1 / 2 * 0.00002  = 25000 Hz 
schaltest. Da musst du schon schnell schauen, um das Blinken noch zu 
sehen.

von ich (Gast)


Lesenswert?

Ich würde mal sagen, du liest dir auf Seite 98 den CTC-Mode durch und 
dann auf Seite 109 in der Tabelle sieht man, wenn man den Mode 4 benutzt 
(was du auch tust), steht der Vergleichswert in dem OCR1A-Register (also 
kein OCR1B).

von Karl H. (kbuchegg)


Lesenswert?

Wieso bist du jetzt auf einmal
1
  OCR1B = 20;        // Vergleichregister Wert setzen
2
  TIMSK |= (1<<OCIE1B);     // Overflow Interrupt für V.-Reg.einschalten
auf den B-Kanal ausgewichen? Dir ist klar, dass dann die ISR anders 
heissen muss? Und vor allen Dingen, dass der CTC Modus zwingend 
erfordert, dass du mit dem A-Kanal arbeitest?

(Die Namen der Steuerregister TCCR1A und TCCR1B haben nichts mit der ISR 
oder den Vergleichsregistern zu tun! Das sind einfach nur 2 
Konfigurationsregister, von denen das eine hinten ein A und das andere 
hinten ein B hat um sie unterscheiden zu können. Man hätte sie genauso 
gut auch TCCR1_CONFIG_1 und TCCR1_CONFIG_2 nennen können)

von Dietmar P. (dietmar2)


Lesenswert?

Hallo,

ich danke Euch einmal wieder, es läuft jetzt. Ich hatte angenommen, dass 
ich alles auf B setzen muss.

Ich hatte zwar auch im Tutorial von Mikrocontroller.net

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_ZÄhler_des_AVR#Einleitung

nachgelesen, kam aber mit dem Timer1 nicht klar.

Gibt es ein deutsches Tutorial das man einem Einsteiger empfehlen kann 
und trotzdem umfassend ist?

Hier jetzt mein kpl. Code:
1
// Timer Testprogramm
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <stdint.h>
6
7
  volatile unsigned int Counter1 = 0;  // Zähler für Timer
8
  volatile unsigned int Counter2 = 0;  // Zähler für Timer
9
10
  ISR (TIMER1_COMPA_vect)
11
12
  {
13
    Counter1++;
14
    Counter2++;
15
  }
16
17
int main(void)
18
{  
19
  
20
  DDRA = 0xff;    // PORTA auf Ausgang
21
  
22
// ********** Timer init ******
23
24
  TCCR1B = (1<<WGM12) | (1<<CS10);   // CTC Modus, Vorteiler 1
25
  OCR1A = 127;               // Vergleichregister Wert 128-1 setzen
26
  TIMSK |= (1<<OCIE1A);       // Overflow Interrupt für Vergleichsregister einschalten
27
28
  sei();         // Interrupts aktivieren
29
  
30
 
31
  // ***** HAUPTROUTINE ******
32
33
  while(1){
34
35
  if (Counter1 >= 2){      // entspricht Takt ca. 3,9 kHz
36
  Counter1 = 0;
37
  PORTA ^= (1 << 0);    // PortA Pin0 high/low umschalten
38
     }
39
40
    if (Counter2 >= 3900){    // entspricht Takt ca. 1 Hz
41
  Counter2 = 0;
42
  PORTA ^= (1 << 1);    // PortA Pin1 high/low umschalten0
43
     }
44
     
45
  }  //while 
46
}//main

Noch eine abschließende Frage. Sollte man die 3,9-4 kHz über PWM 
erzeugen? Das ist aber auch Neuland für mich und ihr lauft Gefahr, dass 
ich wieder mit weiteren Frage auftauche.

von ich (Gast)


Lesenswert?

Also ich kenne kein Tutorium auf deutsch.
Aber guck dir mal das an:
http://www.physik.uni-regensburg.de/studium/edverg/elfort/Diplomarbeit_BLiehr.pdf
vielleicht hilft es dir einwenig weiter.

von Karl H. (kbuchegg)


Lesenswert?

Dietmar P. schrieb:
> Hallo,
>
> ich danke Euch einmal wieder, es läuft jetzt. Ich hatte angenommen, dass
> ich alles auf B setzen muss.
>
> Ich hatte zwar auch im Tutorial von Mikrocontroller.net
>
> 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Zähler_des_AVR#Einleitung
>
> nachgelesen, kam aber mit dem Timer1 nicht klar.

Kannst du das etwas präzisieren.
Dann kann das Tutorial eventuell angepasst werden.

> Gibt es ein deutsches Tutorial das man einem Einsteiger empfehlen kann
> und trotzdem umfassend ist?

Tja.
Das widerspricht sich.
Auf der einen Seite bedingt Einfachheit, dass die komplexeren Dinge und 
ab und an ein momentan unwichtiges Detail weggelassen wird. Auf der 
anderen Seite bedingt 'umfassend' ein Unmenge an zu lesendem Text, um 
alle Möglichkeiten aufzuzeigen.

Irgendwann muss jeder anfangen, sich die Dinge aus den Datenblättern 
zusammenzusuchen und dabei Sorgfalt walten lassen, ob er jetzt das 
richtige Bit im richtigen Register anspricht oder nicht.

> erzeugen? Das ist aber auch Neuland für mich und ihr lauft Gefahr, dass
> ich wieder mit weiteren Frage auftauche.

Das ist an und für sich kein Problem-
Solange du gewappnet bist, das eine oder andere mal aufs Datenblatt 
verwiesen zu werden.

von Karl H. (kbuchegg)


Lesenswert?

> Sollte man die 3,9-4 kHz über PWM erzeugen?

Kommt drauf an, ob und was der µC sonst noch so zu tun hat.
In deinem Fall kannst du auch das Port Umschalten direkt in die ISR 
hineinziehen. Das solltest du sogar, um den Jitter in der erzeugten 
Frequenz niedrig zu halten.

Ausserdem hast du dann keine Probleme mit volatile und atomaren Zugriff 
(etwas das du bisher nämlich sträflich ignoriert hast :-)

von Dietmar P. (dietmar2)


Lesenswert?

Was ist denn der Nachteil von volatile und was ist denn der atomare 
Zugriff?

Im Tutorial ist der 8-Bit Timer mit Beispielen gut beschrieben, diese 
fehlen meiner Ansicht nach bei dem 16-Bit Timer. Solche Beispiele 
fördern einfach das Verständnis für die Anwendung der im Datenblatt 
einzeln erklärten Parameter und Begriffe.

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.