Timer Interrupt
Timer Interrupts werden verwendet, um in regelmäßigen Zeitabständen (Interruptfrequenz) Aktionen zu veranlassen.
(Hier geht's zum Timer Interrupt beim Attiny)
Die Timer des Atmega328P:
Der Atmega328P des Arduino Uno besitzt 3 Timer, die zum Teil in Arduino-Funktionen und/oder zum Teil in Libraries bereits in Verwendung sind. Ein Überschreiben von Timer-Register kann also zu Komplikationen führen und sollte mit Vorsicht angewendet werden.
- 8 Bit-Timer0: Verwendung für Funktionen millis(), micros(), delay() und für PWM bei Pin D5 und D6
- 16 Bit Timer1: Verwendung z.B. für der Servo-, VirtualWire- und TimerOne-Library und für PWM bei Pin D9 und D10
- 8 Bit Timer2: Verwendung für Funktion tone() und für PWM bei Pin D3 und D11
Verwendete Register:
Nachfolgend zeige ich am Beispiel des 16-Bit-Timer1 die Auslösung eines zeitgesteuerten Interrupts im "Clear Timer on Compare Mode" (CTC-Mode). Die Vorgangsweise kann prinzipiell auch auf die 8-Bit-Timer0 und Timer2 angewendet werden, Unterschiede zwischen den Timern sind dem Datenblatt des Atmega328 zu entnehmen, bzw. sind auch an folgendem Beispiel ersichtlich-> Servotest Variante3
Für den 16-Bit-Timer1 werden zur Auslösung eines zeitgesteuerten Interrupts folgende Register benötigt:
- Timer Counter Register 1: TCNT1
- Output Compare Register A: OCR1A
- Timer Counter Controll Register A: TCCR1A
- Timer Counter Controll Register B: TCCR1B
- Timer/Counter Interrupt Mask Register: TIMSK1
Für Timer0 und Timer2 stehen ebenfalls entsprechende Register (z.B. TCNT0 bzw. TCNT2, etc.) zur Verfügung.
Vorgangsweise:
Der Modus muss im TCCR1B-Register auf CTC-Mode (Clear Timer on Compare Mode) eingestellt werden.
Der Inhalt des 16-Bit TCNT1-Register wird mit dem - um den Faktor des Vorteilers (Prescaler) verminderten - Systemtakt erhöht und mit dem Inhalt des 16-Bit OCR1A-Registers verglichen.
Bei Übereinstimmung wird, sofern das entsprechende Maskier-Bit im TIMSK1-Register und das globale Interrupt-Enable-Bit gesetzt sind, ein Interrupt ausgelöst.
Vorteiler und Vergleichswert (Inhalt des OCR1A-Register) ermitteln:
Vorgaben:
- CPU-Frequenz Arduino Uno: 16.000.000 Hz
- Gewünschte Interruptfrequenz: z.B. 50 Hz (= 20 ms Periodendauer)
- Mögliche Vorteiler: 1, 8, 64, 256 oder 1024
Berechnung des Vergleichswertes:
Berechnungsbeispiel:
Z.B. mit Vorteiler = 1024:
Vergleichswert = (16.000.000 / (1024 * 50)) - 1 = 311,5
oder z.B. mit Vorteiler = 8:
Vergleichswert = (16.000.000 / (8 * 50)) - 1 = 39.999
Der errechnete Vergleichswert wird ins OCR1A-Register geschrieben.
Der Vorteiler muss im TCCR1B-Register gesetzt werden.
Achtung: Der errechnete Vergleichswert muss kleiner 65.536 (16-Bit) sein!!
Hier nun zusammengefasst, wie die Register gesetzt werden müssen:
cli(); //Lösche globales Interrupt-Enable-Bit
//CTC-Mode aktivieren
TCCR1A = 0; //Löschen des TCCR1A-Registers
TCCR1B = 0; //Löschen des TCCR1B-Registers
TCCR1B |= (1 << WGM12); //Setze CTC-Mode (Waveform Generation Mode)
TCCR1B - Timer/Counter1 Control Register B:
//Vorteiler (Prescaler) definieren (Vorteiler = 1024)
TCCR1B |= (1 << CS12) | (1 << CS10); //Setze CS10 und CS12 (Clock Select)
TCCR1B - Timer/Counter1 Control Register B:
Die Bitkombination für den gewünschten Vorteiler ist in nachfolgender Tabelle ersichtlich:
// Timer Counter Register und Output Compare Register setzen
TCNT1 = 0; //Timer Counter Register löschen
OCR1A = 312; //Setzen des ermittelten Vergleichswertes
// Timer/Counter Interrupt Mask Register setzen
TIMSK1 |= (1 << OCIE1A); //Bit Output Compare A Match Interrupt Enable setzen
TIMSK1-Timer/Counter1 Interrupt Mask Register
sei(); //Setze globales Interrupt-Enable-Bit
Wird nun ein Timer2-Interrupt ausgelöst, springt der Programmablauf eine zu erstellende Interrupt-Serviceroutine "ISR(TIMER1_COMPA_vect)".
Der Name der Interrupt-Serviceroutine ist vom System fix vorgegeben und darf nicht verändert werden!
Siehe: Beispiele für Timer1-Interrupt und für Timer2-Interrupt