Hallo!
Wie bekomme ich einen durchlaufenden Timer, der Interrupts zu
verschiedenen Zeiten auslösen kann?
Ich habe Timer1 so programmiert, dass er durchläuft. Er beginnt bei
0x0000 und zählt bis 0xFFFF. Dieser soll nicht verändert werden, da er
als Zeitbasis für verschiedene Dinge dient.
Nun möchte ich erreichen, dass bei einem bestimmten Zählerstand ein
Interrupt ausgelöst wird. Dies soll aber nicht bewirken, dass der Zähler
zurückgesetzt wird.
Wie bekomme ich das hin?
Hier ein kleiner Ausschnitt aus meinem Programm:
1
// Timer soll durchlaufen er löst keinen Int aus und wird nicht zurückgestellt
2
// Timer 1 einstellen - Timer wird als CTC genutzt
3
// Mode 4
4
// CLKi/o / 1 oder CLKi/o / 8
5
TCNT1=0;// Timer soll von 0 beginnen; dieser Befehl ist eigentlich nicht notwendig, da es egal ist, wo der Zähler beginnt, hier ist er nur zur Veranschaulichung
6
OCR1A=0xFFFF;// bis hier wird gezählt
7
TCCR1A=0;
8
#if (F_CPU <= 6553500)
9
TCCR1B=(1<<WGM12)|(1<<CS10);
10
#else
11
TCCR1B=(1<<WGM12)|(1<<CS11);
12
#endif
Da OCR1A auf 0xFFFF gestellt ist, würde hier der Interrupt ausgelöst
werden. Ich möchte aber den Interrupt früher auslösen und der Zähler
soll weiterlaufen bis 0xFFFF.
Danke und Gruß
Guido
wie wärst mit 2 isr routinen:
ISR(TIMER1_OVF_vect) //Interrupt bei Overflow Timer1
{
}
ISR (TIMER1_COMPA_vect) //Interruppt bei compare je nach OCR1A
{
}
Die letzte Variante, dass ich TCNT1 neu einstelle, wenn COMPA-Int
ausgelöst wird, geht zwar, ist aber nicht so sauber. Besonders in C habe
ich das Problem, dass schon viele Takte vergangen sind, bevor der erste
Befehl der ISR abgearbeitet wird. Bei Vorteiler 8 sind es immerhin 5
Zähler. Das kann ich kaum kompensieren.
Ich suche noch eine elegantere Lösung.
Was baust Du eigentlich, dass 5 Prozessortakte ein Problem sind?
Wenn die unterschiedlichen Zeiten nicht "parallel" sondern nacheinander
gebraucht werden hätte ich es mit dem Compare Interrupt gemacht und das
Compareregister in der ISR neu geschrieben. Ich hatte noch nie den Fall,
dass das ein Problem darstellt. Wenn es ohne Zeitverzug sein soll ist
das eher ein Fall für einen CPLD oder FPGA.
Gruß Matthias
Guido S. wrote:
> Gute Idee. Klappt aber leider nicht, da bei Erreichen von COMPA der> Timer TCNT1 auf 0x0000 gestellt wird
Seit wann?
Die Atmel Doku zum Mega16 scheint das noch nicht zu wissen.
Dort ist mit keinem Wort erwähnt, dass bei einem Compare Match
der Counter wieder auf 0 gesetzt wird.
(Was du meinst ist der CTC Modus. Der ist hier aber nicht gemeint.
Es spricht nichts dagegen, einen durchlaufenden Timer zu haben,
der mittels der Output Compare Unit bei einem beliebigen Zaehler-
stand einen Interrupt auslöst)
einfach das WGM12 (CTC1) nicht setzen (vgl. Tutorial):
"Wenn dieses Bit gesetzt ist, so wird nach einer Übereinstimmung des
Datenregisters TCNT1H/TCNT1L mit dem Vergleichswert in OCR1H/OCR1L das
Datenregister TCNT1H/TCNT1L auf 0 gesetzt."
Na Kollegen, ich stelle doch eine solche Frage nicht ohne Grund. Ich
habe Hilfe erwartet. Vielleicht bin ich zu dumm oder es ist mit dem
ATMega8 nicht realisierbar.
@Matthias Kölling
> Was baust Du eigentlich, dass 5 Prozessortakte ein Problem sind?
Ob 5 Takte ein Problem sind, kann ich noch nicht sagen. Die 5 Zähler des
Timers bei Vorteiler 8, was immerhin 40 Takte sind, können schon bei
einfachen Anwendungen ein Problem sein, wenn die CPU nur mit 1 MHz
getaktet wird.
Was ich hier mache, kann ich auch verraten. Es soll ein
Phasenabschnittsdimmer mit Infrarotfernbedienung werden. Mein Ehrgeiz
war es, nur einen Timer zu verbraten. Es sollen dann auch 2 Verbraucher
mit einem µC gedimmt werden. Ich glaube, ich werde die anderen Timer
auch mit einbeziehen und hoffentlich mehr Erfolg haben.
@Re Ho
> Wenn du den Timer richtig einstellst, wird er eben nicht gelöscht, wenn> OCR1A/OCR1B erreicht wird.
Das glaube ich. Aber ich benötige Hilfe, wie ich es einstellen kann.
@kbuchegg
> (Was du meinst ist der CTC Modus. Der ist hier aber nicht gemeint.> Es spricht nichts dagegen, einen durchlaufenden Timer zu haben,> der mittels der Output Compare Unit bei einem beliebigen Zaehler-> stand einen Interrupt auslöst)
Ja ich spreche von CTC. Jedenfalls habe ich MODE 4 eingestellt, wie du
aus meinem Programmausschnitt sehen kannst.
Aber mir dämmert, vielleicht sollte ich einen PWM-Modus wählen. Dort
habe ich dann aber das Problem, dass ich nicht die volle Distance bis
65536 zählen kann. Oder kann ich doch?
@Gast
> einfach das WGM12 (CTC1) nicht setzen
Wenn ich das mache, dann ist der Timer aus. Davon habe ich auch nichts.
Gruß
Guido
>Nun möchte ich erreichen, dass bei einem bestimmten Zählerstand ein>Interrupt ausgelöst wird.
A) Warum?
b) Warum?
c) Warum?
Anstatt aus der einen ISR rauszuspringen, nur um dann in eine andere ISR
reinzuspringen, lass doch in der einen Timer-ISR einen Zähler mitlaufen,
und wenn der abgelaufen ist, führe irgendwas zusätzlich aus. Ganz ohne
die ISR's zu wechseln. Das koste dich zwar in jedem ISR-Duchlauf ein
paar Takte für den Zähler un die Abfrage, aber wenn es schon daran
scheitert, hats du eh andere Probleme.
Oliver
Guido S. wrote:
> Die letzte Variante, dass ich TCNT1 neu einstelle, wenn COMPA-Int> ausgelöst wird, geht zwar, ist aber nicht so sauber. Besonders in C habe> ich das Problem, dass schon viele Takte vergangen sind, bevor der erste> Befehl der ISR abgearbeitet wird. Bei Vorteiler 8 sind es immerhin 5> Zähler. Das kann ich kaum kompensieren.
Mußt Du auch nicht, der Timer zählt ja weiter.
Einfach im Compareinterrupt den nächsten Comparewert setzen.
Guido S. wrote:
> Ja ich spreche von CTC.
Und ich frage mich, warum du da überhaupt irgendeinen
anderen Modus als den ganz normalen Zähler-zählt Modus nimmst?
> Aber mir dämmert, vielleicht sollte ich einen PWM-Modus wählen.
Wozu?
> @Gast>> einfach das WGM12 (CTC1) nicht setzen>> Wenn ich das mache, dann ist der Timer aus.
Quatsch. Der Timer zählt, sobald ein Vorteiler eingestellt ist.
Das WGM12 Bit hat damit nichts zu tun.
@kbuchegg
WGM12 habe ich jetzt nicht gesetzt. Und siehe da, kaum macht man es
richtig, schon funktioniert es. Jetzt läuft der Zähler durch, wie
gewünscht. Nun stimmt auch meine Zeitbasis.
Großen Dank!!!
Guido