Die Timer/Counter des AVR
Die heutigen Microcontroller und insbesondere die RISC-AVR's sind für viele
Steuerungsaufgaben natürlich viel 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, die Taktfrequenz auf vernünftige Werte
herunter zu brechen. Selbstverständlich sollte die resultierende Frequenz dann
auch noch einigermassen genau und stabil sein.
Hier kommen die im AVR vorhandenen Timer/Counter zum Einsatz.
Ein anderes Anwendungsgebiet ist die Zählung von Signalen, welche über
einen I/O-Pin zugeführt werden können.
Die folgenden Ausführungen beziehen sich auch den AT90S2313. Für andere
Modelltypen müsst ihr euch die allenfalls notwendigen Anpassungen aus den
Datenblättern der entsprechenden Controller raus lesen.
Wir unterscheiden grundsätzlich zwischen 8-Bit Timern, welche eine
Auflösung von 256 aufweisen und 16-Bit Timern mit (logischerweise) einer
Auflösung von 65536.
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.
Beide Timer/Counter werden im Timerbetrieb über den gleichen Vorzähler
versorgt.
Der Vorzähler dient dazu, den CPU-Takt vorerst mal runter zu brechen auf eine
wählbare Teilung. Die so geteilte Frequenz wird den Eingängen der Timer
zugeführt.
Wenn wir mit einer einem CPU-Takt von 4 MHz arbeiten und den Vorteiler auf 1024
einstellen wird also der Timer mit einer Frequenz von 4 MHz / 1024, also mit ca.
4 kHz versorgt. Wenn also der Timer läuft, so wird das Daten- bzw.
Zählregister mit dieser Frequenz inkrementiert.
Alle AVR-Modelle weisen mindestens einen, teilweise sogar zwei 8-Bit Timer
auf.
Der 8-Bit Timer wird über folgende Register angesprochen:
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/1024-tel des CPU-Taktes zählen zu lassen schreiben wir die folgende
Befehlszeile:
outp ((1<<CS02) | (1<<CS00),
TCCR0);
Der Zähler zählt nun von 0 an aufwärts bis 255 um dann wieder
bei 0 zu beginnen. 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 Interrupt
ausgelöst.
Viele AVR-Modelle besitzen ausser den 8-Bit Timers auch einen oder sogar zwei
(einige ATMega-Modelle) 16-Bit Timer.
Die 16-Bit Timer/Counter sind wesentlich komplexer aufgebaut als die 8-Bit
Timer/Counter, bieten dafür aber auch viel mehr Möglichkeiten, als da sind:
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.
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 |
- |
- |
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 Vorzähler ein etwas anderes
Zählverhalten:
Wenn der Vorteiler auf 1 gestellt ist und C der jeweilige
Zählerwert 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 TO, fallende Flanke |
1 |
1 |
1 |
Externer Pin T0, steigende Flanke |
Wenn als Quelle der externe Pin T0 verwendet wird, so wird ein
Flankenwechsel auch erkannt, wenn der Pin T0 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 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.
|
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 mit Lesezugriff. Es
kann nicht beschrieben werden.
Wenn am Input Capture Pin ICP die gemäss 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 |
Schreiben: |
ICR1H -> ICR1L |
|
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äss 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


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.
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.
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. |
|
|
|
|