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