Forum: Mikrocontroller und Digitale Elektronik AVR: 16-bit-Counter Verwendung so ok?


von Thomas (Gast)


Lesenswert?

Also ich möchte ein Interrupt in bestimmten Intervallen haben (z.B. alle 
60ms), dazu berechne ich mir (zur Laufzeit) welchen Prescaler ich 
brauche, und wie weit der 16-bit Counter laufen soll (mega16).
Den Wert wie weit der Counter laufen sol, lade ich in ein 
Compare-Register.
Soweit klappt das auch, nur kann ich beim mega16 wohl nicht sagen, er 
soll bei einem CompareMatch den Counter wieder auf 0 setzen, wohl weil 
es zwei Compare-Register gibt.

Da hab ich mir folgendes ausgedacht (C-Code, geht aber ums Prinzip):
1
uint16_t intervall = xxx; // interrupt immer wenn der counter xxx mal gezählt hat
2
3
void timer_init(/*...*/) {
4
    /* der ganze andere initalisierungskrempel */
5
    // set compare value
6
    OCR1A = 0;
7
}
8
9
ISR(TIMER1_COMPA_vect) {
10
    // wirte new comparevalue
11
    OCR1A += intervall;
12
}

Anstatt den Counter jedes mal auf 0 zu setzen, schreibe ich als einen 
neuen Compare-Wert.

Geht das so?

Gruß
Thomas

von Benedikt K. (benedikt)


Lesenswert?

Thomas wrote:
> Soweit klappt das auch, nur kann ich beim mega16 wohl nicht sagen, er
> soll bei einem CompareMatch den Counter wieder auf 0 setzen, wohl weil
> es zwei Compare-Register gibt.

Doch, das geht, und zwar mit OCR1A im CTC Modus.

von crazy horse (Gast)


Lesenswert?

geht so, aber es gibt den CTC-Mode, da brauchst du gar nichts nachladen. 
Beim Compare-Ereignis wird der Zähler per Hardware wieder auf 0 gesetzt. 
Empfiehlt sich eigentlich immer für solche Aufgaben, kleinere 
Interruptlaufzeit, keine Jitter, wenn der MC gerade mal in einer anderen 
ISR beschäftigt ist.

von Thomas (Gast)


Lesenswert?

Danke für den Tip, dachte zunächst das geht nicht, weil es kein eigenes 
Bit gibt, wo man das setzen kann, aber hab nun mal gesucht.

Kannst du mir bitte noch sagen ob das hier dann stimmt so:
TCCR1A = (1<<WGM12);

Er setzt dann den Counter wieder auf 0, wenn es ein Compare Match mit 
OCR1A oder OCR1B gibt - richtig? Muss ich dann OCR1B auf einen 
größeren Wert als OCR1A setzen? Könnte ich ja einfach auf 0xffff 
stellen.

Danke schonmal

von Karl H. (kbuchegg)


Lesenswert?

Thomas wrote:
> Er setzt dann den Counter wieder auf 0, wenn es ein Compare Match mit
> OCR1A oder OCR1B gibt - richtig?

falsch.

< Muss ich dann OCR1B auf einen
> größeren Wert als OCR1A setzen? Könnte ich ja einfach auf 0xffff
> stellen.

Bitte schau noch mal ins Datenblatt.
Dort gibt es eine Tabelle über die einzelnen Modi des Timers1.
In dieser Tabelle steht auch, welches Register (wenn überhaupt)
den Max-Wert des Timers liefert.

von AVRFan (Gast)


Lesenswert?

>Kannst du mir bitte noch sagen ob das hier dann stimmt so:
>TCCR1A = (1<<WGM12);

Ja, das ist der CTC Mode mit OCR1A als Match-Register.

>Er setzt dann den Counter wieder auf 0, wenn es ein Compare Match mit
>OCR1A oder OCR1B gibt - richtig?

Nein, nur OCR1A.  OCR1B hat im CTC Mode keine Bedeutung.

>Muss ich dann OCR1B auf einen größeren Wert als OCR1A setzen? Könnte ich ja 
>einfach auf 0xffff stellen.

Der Wert von OCR1B ist völlig egal, weil dieses Register im CTC Mode 
nicht ausgewertet wird.

All diese Informationen findest Du übrigens auch im Datenblatt.

von Thomas (Gast)


Lesenswert?

Ok Entschuldigung, dachte da gibts gar nicht viel Möglichkeiten und habe 
wirklich nicht nachgeschaut.

PS: Grund der anfänglichen Verwirrung war, dass in dem GCC-Tutorial mit 
CTC1 gearbeitet wird, und das nun wohl WGM13,WGM12,WGM11,WGM10 geht.

Gruß & Danke
Thomas

von AVRFan (Gast)


Lesenswert?

>dass in dem GCC-Tutorial mit
>CTC1 gearbeitet wird, und das nun wohl WGM13,WGM12,WGM11,WGM10 geht.

Ah, verstehe.  Ja, die Bit-Namen CTC1 sowie PWM11 und PWM10 sind 
veraltet, aber aus Kompatibilitätsgründen weiterhin definiert.  Für neue 
Anwendungen sollte man nur mit WGM13, WGM12, WGM11, WGM10 arbeiten.

von ren (Gast)


Lesenswert?

Um einen repetitiven timer interrupt zu bekommen kann man's einfacher 
haben. Nur den Timer mit Overflow-Zahl laden und den Overflow interrupt 
enablen, den Rest braucht man dazu nicht. siehe auch
http://www.ibrtses.com/embedded/avrasmuartint.html

von Karl H. (kbuchegg)


Lesenswert?

ren wrote:
> Um einen repetitiven timer interrupt zu bekommen kann man's einfacher
> haben.

Was ist an einem Timer Preload einfacher?
Ausser der ständigen Schererei, dass du nicht weist wieviele
Takte vom Auslösen des Interrupts bis zum Aufruf der ISR
vergangen sind; dass du ständig alle Takte vom Beginn der
ISR bis zum eigentlichen Reload zählen musst und im Reload
Wert berücksichtigen musst.

Alles Dinge, die im CTC Modus keinen Menschen interessieren
und auch nicht zu interessieren brauchen, weil die Hardware
das Rücksetzen des Timers ganz von alleine macht. Und zwar
auf den Takt genau!

Das einzige was anders ist: Es wird ein anderer Interrupt
aufgerufen, die Initialisierungssequenz ist ein klein
wenig anders und man muss nicht grossartig rumrechnen
um den Preload Wert zu kriegen. Ich will alle 200 Takte
einen Interrupt, also schreib ich diesen Wert (OK: 199)
in das OCR Register. Fertig!

von crazy horse (Gast)


Lesenswert?

Karl-Heinz, nicht aufregen. Es gibt immer welche, die das Rad neu 
erfinden :-)

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.