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
volatileunsignedintCounter1=0;// Zähler für Timer
8
volatileunsignedintCounter2=0;// Zähler für Timer
9
10
ISR(TIMER1_COMPA_vect)
11
12
{
13
Counter1++;
14
Counter2++;
15
}
16
17
intmain(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.
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
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.
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.
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.
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.
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.
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
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
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
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.
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).
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)
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:
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.
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.
> 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 :-)
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.