mikrocontroller.net

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


Autor: Dietmar P. (dietmar2)
Datum:

Bewertung
0 lesenswert
nicht 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.
// Timer Testprogramm

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>

  volatile unsigned int Counter1 = 0;  // Zähler für Timer
  volatile unsigned int Counter2 = 0;  // Zähler für Timer

  ISR (TIMER1_COMPA_vect)

  {
    Counter1++;
    Counter2++;
  }

int main(void)
{  
  
  DDRA = 0xff;    // PORTA auf Ausgang
  
// ********** Timer init ******

  TCCR1A = ( 1<<WGM01);      // CTC Modus
  TCCR1B = ( 1 << CS00 );      // Vorteiler: 1
  OCR1A = 127;          // Vergleichregister Wert setzen
  TIMSK |= (1<<OCIE1A);       // Overflow Interrupt für Vergleichsregister einschalten

  sei();         // Interrupts aktivieren
  
 
  // ***** HAUPTROUTINE ******

  while(1){

  if (Counter1 >= 2){      // entspricht Takt ca. 0,25 Sekunde
  Counter1 = 0;
  PORTA ^= (1 << 0);    // PortA Pin0 high/low umschalten
     }

    if (Counter2 >= 4){      // entspricht Takt ca. 0,5 Sekunde
  Counter2 = 0;
  PORTA ^= (1 << 1);    // PortA Pin1 high/low umschalten
     }
     
  }  //while 
}//main

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Shuzz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
// ********** Timer init ******

  TCCR1A = ( 1<<WGM01);      // CTC Modus
  TCCR1B = ( 1 << CS00 );    // Vorteiler: 1
  OCR1A = 127;          // Vergleichregister Wert setzen
  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.

Autor: Dietmar P. (dietmar2)
Datum:

Bewertung
0 lesenswert
nicht 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:
  TCCR1A = ( 1<< WGM12);      // CTC Modus
  TCCR1B = ( 1 << CS10 );      // Vorteiler: 1
  OCR1A = 127;          // Vergleichregister Wert setzen
  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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> TCCR1A = ( 1<< WGM12);      // CTC Modus

WGM12 ist nicht TCCR1A Register sondern im TCCR1B-Register.

Autor: Dietmar P. (dietmar2)
Datum:

Bewertung
0 lesenswert
nicht 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:
  ISR (TIMER1_COMPB_vect)

  TCCR1B = ( 1<< WGM12);    // CTC Modus
  TCCR1B = ( 1 << CS10 );   // Vorteiler: 1
  OCR1B = 257;        // Vergleichregister Wert setzen
  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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: ich (Gast)
Datum:

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

Und dann diese ISR verwenden ISR (TIMER1_COMPA_vect).

Autor: Dietmar P. (dietmar2)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stell mal bitte das ganze geänderte Programm noch mal rein.

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso bist du jetzt auf einmal
  OCR1B = 20;        // Vergleichregister Wert setzen
  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)

Autor: Dietmar P. (dietmar2)
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...

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:
// Timer Testprogramm

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>

  volatile unsigned int Counter1 = 0;  // Zähler für Timer
  volatile unsigned int Counter2 = 0;  // Zähler für Timer

  ISR (TIMER1_COMPA_vect)

  {
    Counter1++;
    Counter2++;
  }

int main(void)
{  
  
  DDRA = 0xff;    // PORTA auf Ausgang
  
// ********** Timer init ******

  TCCR1B = (1<<WGM12) | (1<<CS10);   // CTC Modus, Vorteiler 1
  OCR1A = 127;               // Vergleichregister Wert 128-1 setzen
  TIMSK |= (1<<OCIE1A);       // Overflow Interrupt für Vergleichsregister einschalten

  sei();         // Interrupts aktivieren
  
 
  // ***** HAUPTROUTINE ******

  while(1){

  if (Counter1 >= 2){      // entspricht Takt ca. 3,9 kHz
  Counter1 = 0;
  PORTA ^= (1 << 0);    // PortA Pin0 high/low umschalten
     }

    if (Counter2 >= 3900){    // entspricht Takt ca. 1 Hz
  Counter2 = 0;
  PORTA ^= (1 << 1);    // PortA Pin1 high/low umschalten0
     }
     
  }  //while 
}//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.

Autor: ich (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...
>
> 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Dietmar P. (dietmar2)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.