Die heutigen Mikrocontroller und insbesondere die RISC-AVRs sind für viele Steuerungsaufgaben zu schnell. Wenn wir beispielsweise eine LED oder Lampe blinken lassen wollen, können wir selbstverständlich nicht die CPU-Frequenz verwenden, da ja dann nichts mehr vom Blinken zu bemerken wäre.
Wir brauchen also eine Möglichkeit, Vorgänge in Zeitabständen durchzuführen, die geringer als die Taktfrequenz des Controllers sind. Selbstverständlich sollte die resultierende Frequenz auch noch möglichst genau und stabil sein.
Hier kommen die im AVR vorhandenen Timer/Counter zum Einsatz.
Ein Timer ist ganz einfach ein bestimmtes Register im µC, das völlig ohne Zutun des Programms, also per Hardware, hochgezählt wird. Das alleine wäre noch nicht allzu nützlich, wenn nicht dieses Hardwareregister bei bestimmten Zählerständen einen Interrupt auslösen könnte.
Ein solches Ereignis ist der Overflow (Überlauf): Da die Bitbreite des Registers beschränkt ist, kommt es natürlich auch vor, dass der Zähler so hoch zählt, dass der nächste Zählerstand mit dieser Bitbreite nicht mehr darstellbar ist und der Zähler wieder auf 0 zurückgesetzt wird. Dieses Ereignis nennt man den Overflow und es ist möglich an dieses Ereignis einen Interrupt zu koppeln.
Ein anderes Anwendungsgebiet ist das Zählen von Impulsen, welche über einen I/O-Pin zugeführt werden.
Als Eingangstakt für die Timer/Counter kann entweder die CPU-Taktfrequenz, der Vorteiler-Ausgang oder ein an einen I/O-Pin angelegtes Signal verwendet werden. Wenn ein externes Signal verwendet wird, so darf dessen Frequenz nicht höher sein als die Hälfte des CPU-Taktes.
Die folgenden Ausführungen beziehen sich im Wesentlichen auf den AT90S2313. Für andere Modelltypen müsst ihr euch die allenfalls notwendigen Anpassungen aus den Datenblättern der entsprechenden Controller herauslesen.
[Bearbeiten] Der Vorteiler (Prescaler)
Der Vorteiler dient dazu, den CPU-Takt vorerst um einen einstellbaren Faktor zu reduzieren. Die so geteilte Frequenz wird den Eingängen der Timer zugeführt.
Wenn wir mit einem CPU-Takt von 4 MHz arbeiten und den Vorteiler auf 1024 einstellen, wird der Timer mit einer Frequenz von 4 MHz / 1024, also mit etwas weniger als 4 kHz versorgt. Wenn der Timer läuft, wird das Zählregister (TCNTx) mit dieser Frequenz inkrementiert.
[Bearbeiten] Timer-Bitzahlen verschiedener AVRs
Wir unterscheiden grundsätzlich zwischen 8-Bit Timern, welche eine Auflösung von 256 (2^8) aufweisen und 16-Bit Timern mit einer Auflösung von 65536 (2^16).
Alle AVR-Modelle verfügen über mindestens einen, teilweise sogar zwei, 8-Bit Timer.
| AVR-Typ | Timer/Counter0 | Timer/Counter1 | Timer/Counter2
|
| AT90S2313 | 8 | 16 | -
|
| ATtiny2313 | 8 | 16 | -
|
| ATmega8 | 8 | 16 | 8
|
| ATmega88 | 8 | 16 | 8
|
| ATmega16 | 8 | 16 | 8
|
| ATmega32 | 8 | 16 | 8
|
| ATmega644 | 8 | 16 | 8
|
[Bearbeiten] 8-Bit Timer/Counter
Der 8-Bit Timer wird z.B bei AT90S2313 über folgende Register angesprochen (bei anderen Typen weitestgehend analog):
| TCCR0
| Timer/Counter Control Register
Timer 0
In diesem Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.
Das Register ist wie folgt aufgebaut:
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
| Name
| - | - | - | - | - | CS02 | CS01 | CS00
|
| R/W
| R | R | R | R | R | R/W | R/W | R/W
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
CS02, CS01, CS00 (Clock Select Bits)
- Diese 3 Bits bestimmen die Quelle für den Timer/Counter:
| CS02 | CS01 | CS00 | Resultat
|
| 0
| 0
| 0
| Stopp, Der Timer/Counter wird angehalten.
|
| 0
| 0
| 1
| CPU-Takt
|
| 0
| 1
| 0
| CPU-Takt / 8
|
| 0
| 1
| 1
| CPU-Takt / 64
|
| 1
| 0
| 0
| CPU-Takt / 256
|
| 1
| 0
| 1
| CPU-Takt / 1024
|
| 1
| 1
| 0
| Externer Pin TO, fallende Flanke
|
| 1
| 1
| 1
| Externer Pin TO, steigende Flanke
|
- Wenn als Quelle der externe Pin TO verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin TO als Ausgang geschaltet ist.
|
| TCNT0
| Timer/Counter Daten Register Timer 0
Dieses ist als 8-Bit Aufwärtszähler mit Schreib- und Lesezugriff
realisiert. Wenn der Zähler den Wert 255 erreicht hat, beginnt er beim
nächsten Zyklus wieder bei 0.
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
| Name
| MSB | | | | | | | LSB
|
| R/W
| R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
|
Um nun also den Timer0 in Betrieb zu setzen und ihn mit einer Frequenz von 1/8-tel des CPU-Taktes zählen zu lassen, schreiben wir die folgende Befehlszeile:
Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen. Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf 0 wird das Timer Overflow Flag TOV0 im Timer Interrupt Flag TIFR-Register gesetzt und, falls so konfiguriert, ein entsprechender Timer-Overflow-Interrupt ausgelöst und die daran gebundene Interrupt-Service-Routine (ISR) abgearbeitet. Das TOV Flag
lässt sich durch das Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder zurücksetzen.
[Bearbeiten] Overflow Interrupt
Jedesmal wenn der Timer seinen höchsten Wert erreicht hat, erfolgt ein Overflow und der Timer beginnt wieder bei 0 zu zählen. An diesen Overflow kann eine Funktion, die sog. Overflow-ISR, gebunden werden. Damit hat man die Möglichkeit, bestimmte Funktionalitäten in regelmäßigen Zeitabständen ausführen zu lassen. Wie groß diese Zeitabstände sind, wird ausschließlich von der Zählfrequenz des Timers und der Bitbreite des Timers (also dem höchsten Wert, den der Timer erreichen kann) bestimmt. Die Zählfrequenz wiederrum hängt von Taktfrequenz des Controllers und dem eingestellten Vorteiler ab.
/* uC: AT90S2313 */
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
// Timer 0 konfigurieren
TCCR0 = (1<<CS01); // Prescaler 8
// Overflow Interrupt erlauben
TIMSK |= (1<<TOIE0);
// Global Interrupts aktivieren
sei();
while(1)
{
/* Sonstige Aktionen */
}
}
/*
Der Overflow Interrupt Handler
wird aufgerufen, wenn TCNT0 von
255 auf 0 wechselt (256 Schritte),
d.h. ca. alle 2 ms
*/
#ifndef TIMER0_OVF_vect
// Für ältere WinAVR Versionen z.B. WinAVR-20071221
#define TIMER0_OVF_vect TIMER0_OVF0_vect
#endif
ISR (TIMER0_OVF_vect)
{
/* Interrupt Aktion alle
(1000000/8)/256 Hz = 488,28125 Hz
bzw.
1/488,28125 s = 2,048 ms
*/
} |
Grundsätzlich kann man in einer ISR jeden beliebigen Code ausführen lassen. Allerdings sollte man sich an die Grundregeln der ISR Programmierung halten: Nur das tun was unbedingt notwendig ist. Eine ISR sollte (zeitlich gesehen) so kurz wie möglich aber so lang wie notwendig sein. Komplexe Ausgaben auf LCD oder gar auf die UART gehören nicht in eine ISR. Sie dauern einfach zu lange und blockieren so den Prozessor zu lange. Programme, die mehrere Dinge quasi gleichzeitig machen, werden so zu lange blockiert.
Die Taktfrequenz, mit der eine ISR aufgerufen wird, erscheint nach obigen Ausführungen recht starr, aber sie lässt sich feiner anpassen. Eine Möglichkeit bestünde darin, den Zählerstand des Registers TCNT0 nach einem Overflow auf einen Wert größer als 0 zu setzen. Somit blieben bis zum nächsten Overflow weniger Zähltakte, was die Frequenz erhöhen würde.
Modernere AVRs kennen allerdings einen eleganteren Weg zur Anpassung der Interrupt-Frequenz: den CTC Modus
[Bearbeiten] CTC Clear Timer on Compare Match (Auto Reload)
Im CTC Modus des Timers ist es möglich, anstelle der durch die Hardware bedingten Obergrenze des Timers, einen anderen Wert zu benutzen, an dem der Timer einen Interrupt auslöst und wieder bei 0 zu zählen anfängt. Neben dem Aktivieren des CTC Modus genügt es dazu, einfach den gewünschten Endwert in ein spezielles Register, das OCR0A, zu laden. Und natürlich hat auch die ISR dann einen anderen Namen. Weitere Anmerkungen und Erläuterungen finden sich im CTC-Kapitel der 16-Bit Timer.
/* uC: Attiny2313 */
#include <avr/io.h>
#include <avr/interrupt.h>
//Variablen für die Zeit
volatile unsigned int millisekunden;
volatile unsigned int sekunde;
volatile unsigned int minute;
volatile unsigned int stunde;
int main(void)
{
// Timer 0 konfigurieren
TCCR0A = (1<<WGM01); // CTC Modus
TCCR0B |= (1<<CS01); // Prescaler 8
// ((1000000/8)/1000) = 125
OCR0A = 125-1;
// Compare Interrupt erlauben
TIMSK |= (1<<OCIE0A);
// Global Interrupts aktivieren
sei();
while(1)
{
/*Hier kann die aktuelle Zeit
ausgeben werden*/
}
}
/*
Der Compare Interrupt Handler
wird aufgerufen, wenn
TCNT0 = OCR0A = 125-1
ist (125 Schritte), d.h. genau alle 1 ms
*/
ISR (TIMER0_COMPA_vect)
{
millisekunden++;
if(millisekunden == 1000)
{
sekunde++;
millisekunden = 0;
if(sekunde == 60)
{
minute++;
sekunde = 0;
}
if(minute == 60)
{
stunde++;
minute = 0;
}
if(stunde == 24)
{
stunde = 0;
}
}
} |
Anm.: In diesem Beispiel ist es egal, ob TCCR0B absolut gesetzt wird (TCCR0B = (1<<CS01)) oder der Prescaler-Wert zum alten Inhalt hinzugefügt wird (TCCR0B |= (1<<CS01)). Die anderen Bits in TCCR0B sind nach dem Reset 0 und sollen auch 0 bleiben. Wenn man sicher nur bestimmte Bits ändern will, ist das ODER (bzw. UND mit dem Kehrwert) sicherer. Näheres dazu im Artikel Bitmanipulation.
[Bearbeiten] 16-Bit Timer/Counter
Viele AVR-Modelle besitzen außer den 8-Bit Timern auch 16-Bit Timer. Die 16-Bit Timer/Counter sind etwas komplexer aufgebaut als die 8-Bit Timer/Counter, bieten dafür aber auch viel mehr Möglichkeiten, als da sind:
- Die PWM-Betriebsart zur Erzeugung eines pulsweitenmodulierten Ausgangssignals.
- Vergleichswert-Überprüfung mit Erzeugung eines Ausgangssignals (Output Compare Match).
- Einfangen eines Eingangssignals mit Speicherung des aktuellen Zählerwertes (Input Capturing), mit zuschaltbarer Rauschunterdrückung (Noise Filtering).
Folgende Register sind dem Timer/Counter 1 zugeordnet:
| TCCR1A
| Timer/Counter Control Register A Timer 1
In diesem und dem folgenden Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.
Das Register ist wie folgt aufgebaut:
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
| Name
| COM1A1 | COM1A0 | - | - | - | - | PWM11 | PWM10
|
| R/W
| R/W | R/W | R | R | R | R | R/W | R/W
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
COM1A1, COM1A0 (Compare Match Control Bits)
- Diese 2 Bits bestimmen die Aktion, welche am Output-Pin OC1 ausgeführt werden soll, wenn der Wert des Datenregisters des Timer/Counter 1 den Wert des Vergleichsregisters erreicht, also ein so genannter Compare Match auftritt.
- Der Pin OC1 (PB3 beim 2313) muss mit dem Datenrichtungsregister als Ausgang konfiguriert werden.
| COM1A1 | COM1A0 | Resultat
|
| 0
| 0
| Output-Pin OC1 wird nicht angesteuert.
|
| 0
| 1
| Das Signal am Pin OC1 wird invertiert (Toggle).
|
| 1
| 0
| Der Output Pin OC1 wird auf 0 gesetzt.
|
| 1
| 1
| Der Output Pin OC1 wird auf 1 gesetzt.
|
- In der PWM-Betriebsart haben diese Bits eine andere Funktion.
| COM1A1 | COM1A0 | Resultat
|
| 0
| 0
| Output-Pin OC1 wird nicht angesteuert.
|
| 0
| 1
| Output-Pin OC1 wird nicht angesteuert.
|
| 1
| 0
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin OC1 auf 0 gesetzt.
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 1 gesetzt.
Man nennt dies nicht invertierende PWM.
|
| 1
| 1
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin OC1 auf 1 gesetzt.
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 0 gesetzt.
Man nennt dies invertierende PWM.
|
PWM11, PWM10 (PWM Mode Select Bits)
- Mit diesen 2 Bits wird die PWM-Betriebsart des Timer/Counter 1 gesteuert.
- PWM10 PWM11 wurden umbenannt in WGM10 und WGM11
| PWM11 | PWM10 | Resultat
|
| 0
| 0
| Die PWM-Betriebsart ist nicht aktiviert. Timer/Counter 1 arbeitet als normaler Timer bzw. Zähler.
|
| 0
| 1
| 8-Bit PWM Betriebsart aktivieren.
|
| 1
| 0
| 9-Bit PWM Betriebsart aktivieren.
|
| 1
| 1
| 10-Bit PWM Betriebsart aktivieren.
|
|
| TCCR1B
| Timer/Counter Control Register B Timer 1
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
| Name
| ICNC1 | ICES1 | - | WGM13 | WGM12 (CTC1) | CS12 | CS11 | CS10
|
| R/W
| R/W | R/W | R | R | R/W | R/W | R/W | R/W
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
ICNC1 (Input Capture Noise Canceler (4 CKs) Timer/Counter 1
- oder auf Deutsch Rauschunterdrückung des Eingangssignals.
- Wenn dieses Bit gesetzt ist und mit dem Input Capture Signal gearbeitet wird so werden nach der Triggerung des Signals mit der entsprechenden Flanke (steigend oder fallend) am Input Capture Pin ICP jeweils 4 Messungen mit der CPU-Frequenz des Eingangssignals abgefragt. Nur dann, wenn alle 4 Messungen den gleichen Zustand aufweisen gilt das Signal als erkannt.
ICES1 (Input Capture Edge Select Timer/Counter 1)
- Mit diesem Bit wird bestimmt, ob die steigende (ICES1=1) oder fallende (ICES1=0) Flanke zur Auswertung des Input Capture Signals an Pin ICP heran gezogen wird.
CTC1 (Clear Timer/Counter on Compare Match Timer/Counter 1)
- 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.
- Da die Übereinstimmung im Takt nach dem Vergleich behandelt wird, ergibt sich je nach eingestelltem Vorteiler ein etwas anderes Zählverhalten:
- Wenn der Vorteiler auf 1 gestellt, und C der voreingestellte Vergleichswert ist, dann nimmt das Datenregister, im CPU-Takt betrachtet, folgende Werte an:
- ... | C-2 | C-1 | C | 0 | 1 |...
- Wenn der Vorteiler z. B. auf 8 eingestellt ist, dann nimmt das Datenregister folgende Werte an:
- ... | C-2, C-2, C-2, C-2, C-2, C-2, C-2, C-2 | C-1, C-1, C-1, C-1, C-1, C-1, C-1, C-1 | C, 0, 0, 0, 0, 0, 0, 0 |...
- In der PWM-Betriebsart hat dieses Bit keine Funktion.
CS12, CS11, CS10 (Clock Select Bits)
- Diese 3 Bits bestimmen die Quelle für den Timer/Counter:
| CS12 | CS11 | CS10 | Resultat
|
| 0
| 0
| 0
| Stopp, Der Timer/Counter wird angehalten.
|
| 0
| 0
| 1
| CPU-Takt
|
| 0
| 1
| 0
| CPU-Takt / 8
|
| 0
| 1
| 1
| CPU-Takt / 64
|
| 1
| 0
| 0
| CPU-Takt / 256
|
| 1
| 0
| 1
| CPU-Takt / 1024
|
| 1
| 1
| 0
| Externer Pin T1, fallende Flanke
|
| 1
| 1
| 1
| Externer Pin T1, steigende Flanke
|
- Wenn als Quelle der externe Pin T1 verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin T1 als Ausgang geschaltet ist.
|
TCNT1H TCNT1L
| Timer/Counter Daten Register Timer/Counter 1
Dieses ist als 16-Bit Aufwärtszähler mit Schreib- und Lesezugriff realisiert. Wenn der Zähler den Wert 65535 erreicht hat, beginnt er beim nächsten Zyklus wieder bei 0.
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
| Name
| MSB | | | | | | | | TCNT1H
|
| Name
| | | | | | | | LSB | TCNT1L
|
| R/W
| R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W |
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
In der PWM-Betriebsart wird das Register als Auf/Ab-Zähler verwendet, d.h. der Wert steigt zuerst von 0, bis er den Überlauf von 65535 auf 0 erreicht hat. Dann zählt das Register rückwärts wiederum bis 0.
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf OCR1 oder ICR1 zugegriffen wird.
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst TCNT1L und erst danach TCNT1H ausgelesen werden.
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrrupts gesperrt werden. Dann muss zuerst das TCNT1H-Register und erst danach das TCNT1L-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.
|
OCR1H OCR1L
| Timer/Counter Output Compare Register Timer/Counter 1
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
| Name
| MSB | | | | | | | | OCR1H
|
| Name
| | | | | | | | LSB | OCR1L
|
| R/W
| R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W |
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
Der Wert im Output Compare Register wird ständig mit dem aktuellen Wert im Datenregister TCNT1H/TCNT1L verglichen. Stimmen die beiden Werte überein, so wird ein sogenannter Output Compare Match ausgelöst. Die entsprechenden Aktionen werden über die Timer/Counter 1 Control und Status Register eingestellt.
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf TCNT1 oder ICR1 zugegriffen wird.
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt. Zudem muss zuerst OCR1L und erst danach OCR1H ausgelesen werden.
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrupts gesperrt werden. Dann muss zuerst das OCR1H-Register und erst danach das OCR1L-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.
|
ICR1H ICR1L
| Timer/Counter Input Capture Register Timer/Counter 1
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
| Name
| MSB | | | | | | | | ICR1H
|
| Name
| | | | | | | | LSB | ICR1L
|
| R/W
| R | R | R | R | R | R | R | R |
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
Das Input Capture Register ist ein 16-Bit Register. Bei einigen AVR Modellen kann es als TOP Value für bestimmte PWM Modes verwendet werden.
Wenn am Input Capture Pin ICP die gemäß Einstellungen im TCCR1B definierte Flanke erkannt wird, so wird der aktuelle Inhalt des Datenregisters TCNT1H/TCNT1L sofort in dieses Register kopiert und das Input Capture Flag ICF1 im Timer Interrupt Flag Register TIFR gesetzt.
Wie bereits oben erwähnt, müssen vor dem Zugriff auf dieses Register alle Interrupts gesperrt werden. Zudem müssen Low- und Highbyte des Registers in der richtigen Reihenfolge bearbeitet werden:
- Lesen:
- ICR1L → ICR1H
Bei Verwendung des Compilers wird der Zugriff in der korrekten Reihenfolge ausgeführt, wenn man das 16-Bit register ICR1 verwendet anstatt zwei Zugriffe auf 8-Bit Register.
|
[Bearbeiten] Die PWM-Betriebsart
Wenn der Timer/Counter 1 in der PWM-Betriebsart betrieben wird, so bilden das Datenregister TCNT1H/TCNT1L und das Vergleichsregister OCR1H/OCR1L einen 8-, 9- oder 10-Bit, frei laufenden PWM-Modulator, welcher als PWM-Signal am OC1-Pin (PB3 beim 2313) abgegriffen werden kann. Das Datenregister TCNT1H/TCNT1L wird dabei als Auf-/Ab-Zähler betrieben, welcher von 0 an aufwärts zählt bis zur Obergrenze und danach wieder zurück auf 0.
Die Obergrenze ergibt sich daraus, ob 8-, 9- oder 10-Bit PWM verwendet wird, und zwar gemäß folgender Tabelle:
| Auflösung | Obergrenze | Frequenz
|
| 8 | 255 | fTC1 / 510
|
| 9 | 511 | fTC1 / 1022
|
| 10 | 1023 | fTC1 / 2046
|
Wenn nun der Zählerwert im Datenregister den in OCR1H/OCR1L gespeicherten Wert erreicht, wird der Ausgabepin OC1 gesetzt bzw. gelöscht, je nach Einstellung von COM1A1 und COM1A0 im TCCR1A-Register.
Ich habe versucht, die entsprechenden Signale in der folgenden Grafik zusammenzufassen
[Bearbeiten] Vergleichswert-Überprüfung (Compare Match)
Hier wird in ein spezielles Vergleichswertregister (OCR1H/OCR1L) ein Wert eingeschrieben, welcher ständig mit dem aktuellen Zählerwert verglichen wird.
Erreicht der Zähler den in diesem Register eingetragenen Wert, so kann ein Signal (0 oder 1) am Pin OC1 erzeugt und/oder ein Interrupt ausgelöst werden.
Zu erwähnen ist in dem Zusammenhang, dass das zur Compare-Einheit gehörende Interrupt-Flag erst beim auf die Übereinstimmung der Werte folgenden Timertakt gesetzt wird. Das ist v.a. deshalb wichtig, da es sonst bei OCRnx = 0 einen undefinierten Zustand gäbe.
Möchte man ein Compare-Ereignis 100 Takte nach dem Timerüberlauf auslösen, dann muss in das betreffende Compare-Register eine 99 geschrieben werden.
[Bearbeiten] CTC-Betriebsart (Clear Timer on Compare Match)
Das sogenannte Compare Match-Ereignis kann auch dazu verwendet werden, um den Timer automatisch zurückzusetzen (d.h. das TCNT-Register wird zu Null gesetzt). Diese Betriebsart heißt "Clear Timer on Compare Match", also auf deutsch "Lösche Timer bei Vergleichsübereinstimmung".
Mit dieser Funktionalität ist es möglich, sehr präzise Taktsignale zu erzeugen, ohne dabei programmtechnisch eingreifen zu müssen. Diese Funktion ersetzt das bei anderen Controllern und Timern ohne Compare-Einheit erforderliche Timer Reload (also das Nachladen des Zählregisters mit "Überlaufwert minus gewünschte Taktzahl bis zum Überlauf", v.a. verbreitet bei 8051er-µCs).
Zur Erzeugung eines Taktes per Hardware muss lediglich eine der CTC-Betriebsarten ausgewählt werden und einer der OCnx-Pins so gesetzt werden, dass er bei Auftreten des Compare Match getoggelt wird (über die COM-Bits).
Die Frequenz des Taktes am entsprechenden Ausgang ist dann:
Umgeformt gilt für OCRnx:
Diese Betriebsart macht das Timer-Nachladen, das bei AVRs, die ja im Unterschied zu 8051-Derivaten keine Auto-Reload-Funktion haben, immer mit Ungenauigkeiten und programmtechnischen Klimmzügen verbunden ist, überflüssig. Ist das OCRnx einmal gesetzt, dann wird das Signal am Ausgang kontinuierlich ausgegeben, ohne dass die Anwendersoftware eingreifen muss (es sei denn, die Frequenz soll geändert werden).
Beim ATmega8 hat der 8-Bit-Timer 0 keine Compare-Einheit, so dass dort CTC und auch sonstige automatische Vergleichsoperationen nicht möglich sind. Bei Timer 1 und Timer 2 ist das jedoch möglich. Bei den neueren AVRs besitzen i.d.R. alle Timer eine oder mehrere Compare-Einheiten, so dass dort eine größere Flexibilität gegeben ist.
Im Unterschied zu den PWM-Betriebsarten wird die Registeraktualisierung bei CTC nicht automatisch synchronisiert. Schreibt man einen neuen Compare-Wert, dann wird dieser sofort übernommen, was zu Fehlfunktionen führen kann, wenn der neue Compare-Wert höher ist, als der aktuelle Stand von TCNTnx. In den PWM-Betriebsarten wird hingegen der TOP-Wert synchron bei Erreichen von TOP oder BOTTOM aktualisiert.
[Bearbeiten] Einfangen eines Eingangssignals (Input Capturing)
Bei dieser Betriebsart wird an den Input Capturing Pin (ICP) des Controllers eine Signalquelle angeschlossen.
Nun kann je nach Konfiguration entweder ein Signalwechsel von 0 nach 1 (steigende Flanke) oder von 1 nach 0 (fallende Flanke) erkannt werden und der zu diesem Zeitpunkt aktuelle Zählerstand in ein spezielles Register abgelegt werden. Gleichzeitig kann auch ein entsprechender Interrupt ausgelöst werden.
Wenn die Signalquelle ein starkes Rauschen beinhaltet, kann die Rauschunterdrückung eingeschaltet werden. Dann wird beim Erkennen der konfigurierten Flanke über 4 Taktzyklen das Signal überwacht und nur dann, wenn alle 4 Messungen gleich sind, wird die entsprechende Aktion ausgelöst.
[Bearbeiten] Gemeinsame Register
Verschiedene Register beinhalten Zustände und Einstellungen, welche sowohl
für den 8-Bit, als auch für den 16-Bit Timer/Counter in ein und demselben
Register zu finden sind.
| TIMSK
| Timer/Counter Interrupt Mask
Register
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
| Name
| TOIE1 | OCIE1A | - | - | TICIE | - | TOIE0 | -
|
| R/W
| R/W | R/W | R | R | R/W | R | R/W | R
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
TOIE1 (Timer/Counter Overflow Interrupt Enable Timer/Counter 1)
- Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 1 ein Timer Overflow 1 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.
OCIE1A (Output Compare Match Interrupt Enable Timer/Counter 1)
- Beim Timer/Counter 1 kann zusätzlich zum Überlauf ein Vergleichswert definiert werden.
- Wenn dieses Bit gesetzt ist, wird beim Erreichen des Vergleichswertes ein Compare Match Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.
TICIE (Timer/Counter Input Capture Interrupt Enable)
- Wenn dieses Bit gesetzt ist, wird ein Capture Event Interrupt ausgelöst, wenn ein entsprechendes Signalereignis am Pin PD6(ICP) auftritt. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein, wenn auch ein entsprechender Interrupt ausgelöst werden soll.
TOIE0 (Timer/Counter Overflow Interrupt Enable Timer/Counter 0)
- Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 0 ein Timer Overflow 0 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.
|
| TIFR
| Timer/Counter Interrupt Flag Register
| Bit
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
| Name
| TOV1 | OCF1A | - | - | ICF1 | - | TOV0 | -
|
| R/W
| R/W | R/W | R | R | R/W | R | R/W | R
|
| Initialwert
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
TOV1 (Timer/Counter Overflow Flag Timer/Counter 1)
- Dieses Bit wird vom Controller gesetzt, wenn beim Timer 1 ein Überlauf des Datenregisters stattfindet.
- In der PWM-Betriebsart wird das Bit gesetzt, wenn die Zählrichtung von auf- zu abwärts und umgekehrt geändert wird (Zählerwert = 0).
- Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.
OCF1A (Output Compare Flag Timer/Counter 1)
- Dieses Bit wird gesetzt, wenn der aktuelle Wert des Datenregisters von Timer/Counter 1 mit demjenigen im Vergleichsregister OCR1 übereinstimmt.
- Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.
ICF1 (Input Capture Flag Timer/Counter 1)
- Dieses Bit wird gesetzt, wenn ein Capture-Ereignis aufgetreten ist, welches anzeigt, dass der Wert des Datenregisters des Timer/Counter 1 in das Input Capture Register ICR1 übertragen wurde.
- Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.
TOV0 (Timer/Counter Overflow Flag Timer/Counter 0)
- Dieses Bit wird vom Controller gesetzt, wenn beim Timer 0 ein Überlauf des Datenregisters stattfindet.
- Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.
|