Timer

Timer sind Hardware-Bausteine in einem Mikrocontroller, die unabhängig vom sonstigen Programmablauf von 0 bis zu einem Maximalwert zählen können. In einem AVR-Mikrocontroller gibt es 8-Bit-Timer, die von 0 bis 255 zählen können, und 16-Bit Timer, die von 0 bis 65.535 zählen können. Bei einem ATmega8 gibt es Timer1 als sehr mächtigen 16-Bit-Timer sowie Timer0 und Timer2 als 8-Bit-Timer. Timer können dafür benutzt werden, regelmäßig Aktionen auszuführen, Zeiten exakt zu messen, unterschiedliche Arten von Signalen zu erzeugen oder externe Impulse zu zählen. Im Datenblatt des jeweiligen Mikrocontrollers sind die Timer-Register und die Einstellungsmöglichkeiten im Detail beschrieben.

Timer im normalen Timer-Modus

Im normalen Timer-Modus zählt ein Timer von 0 bis 255 (beim 8-Bit-Timer0/-Timer2) bzw. bis 65.535 (beim 16-Bit-Timer1). Wenn der Maximalwert erreicht ist, springt der Wert des Timers auf 0, und der Timer fängt von vorne an zu zählen.

Beim Übergang vom Maximalwert zu 0 kann man einen Timer-Interrupt auslösen und infolgedessen eine Interrupt-Service-Routine anspringen lassen. Da es nicht immer passend ist, den Timer im Takt des Systemtaktes zählen zu lassen, kann man durch Vorschalten eines Vorteilers (Prescaler) den Prozessortakt des AVR fAVR in gewissen Stufen verlangsamen. Bei einem ATmega8 kann man den Systemtakt (= Prozessortakt) direkt oder um den Faktor 8, 64, 256, 1024 verlangsamt an den  Timer0 bzw. Timer1 geben. Für den Timer2 gibt es zusätzlich noch die Vorteiler-Werte 32 und 128. In Bild 1 ist dargestellt, wie der Systemtakt durch den Prescaler vorgeteilt wird, der Timer in diesem geteilten Takt fTimer immer wieder von 0 bis zum Maximalwert zählt und beim Sprung auf 0 jeweils ein Timer-Interrupt ausgelöst wird.

Timer mit Interrupt

Im folgenden Programm wird – unabhangig vom normalen  Programmablauf – durch den Timer ein Interrupt ausgelöst, in dessen Interrupt-Service-Routine zwei LEDs getoggelt, also ein- und ausgeschalten werden.

  1. /*
  2.  * Timer_Interrupt.c
  3.  * ATmega8 @ 16 MHz
  4.  *
  5.  * Created: 14.03.2014 22:21:27
  6.  * Author: Roman Trapp
  7.  */
  8.  
  9. #include <avr/io.h>
  10. #include <avr/interrupt.h>
  11.  
  12. volatile unsigned int count;
  13.  
  14. int main(void)
  15. {
  16. DDRD=0x60;
  17. PORTD=0x00;
  18.  
  19. TCCR1B |= (1<<CS12) | (1<<CS10); // Prescaler 1024
  20. TCNT1 = 49911; // Vorladewert fuer 1 Sekunde
  21. TIMSK |= (1<<TOIE1); // Timer Overflow Interrupt Enable
  22.  
  23. sei(); // Interrupt global einschalten
  24.  
  25. while(1)
  26. {
  27. //TODO:: Please write your application code
  28. }
  29. return 0;
  30. }
  31.  
  32. ISR(TIMER1_OVF_vect)
  33. {
  34. PORTD ^= 0x60; // Toggeln
  35. TCNT1 = 49911; // Der Vorladewert muss wieder fuer 1 Sekunde gesetzt werden!!!
  36. // Wichtig, sonst wird falsch gezaehlt!!!
  37. }
  38.  
  39. /* Anmerkung:
  40.   Mit einem Prescaler von 256 und einem Vorladewert von 3036 wird auch 1 Sekunde gezaehlt!
  41. /*
  42.  
  43.  

Timer mit Startwert – Sekundentakt

Durch die Wahl des Timers (8 Bit oder 16 Bit) und des Prescalers kann man einen Timer grob konfigurieren. Möchte man genaue Frequenzen bzw. Zeiten einstellen, dann kann man dies erreichen, indem man den Timer nicht von 0, sondern von einem Startwert zählen lässt, wie in Bild 2 zu sehen. Die Zeit zwischen den Timer-Interrupts wird dadurch verkürzt bzw. die Frequenz vergrößert.

Zum Toggeln einer LED im Sekundenrhythmus stellt man folgende Überlegungen an:

Die Systemfrequenz fAVR ist 16 MHz. Die Periodendauer TAVR beträgt 1 / 16 MHz = 62,5 ns. Der Prescaler wird auf 1024 gestellt, wodurch sich die Periodendauer, mit der der Timer getaktet wird, auf 64 μs verlängert. Alle 64 μs zählt also der Timer um 1 weiter. Anders gesagt: Ein „Tick“ des Timers dauert 64 μs. Die gewünschte Zeit ist 1 s = 1000000 μs. Es werden also 1000000 μs / 64 μs = 15625 Ticks benötigt und nicht die vollen 65.536 Ticks, die der Timer insgesamt bis zum Überlauf machen kann. Deshalb wird mit dem Zählen nicht bei 0 angefangen, sondern bei 65536 – 15625 = 49911. Der Timer zählt von 49911 bis 65535 und springt dann auf 0, wobei der Timer-Interrupt ausgelöst wird.

Timer im CTC-Modus

Man kann den Timer eines AVR-Mikrocontrollers so konfigurieren, dass er nicht bis zu seinem maximalen Wert zählt, sondern nur bis zu einem Vergleichswert, dem Compare-Wert (engl. CTC = clear timer on compare match). Dadurch wird die Zeit eines Durchlaufs entsprechend verkürzt, und es lassen sich unterschiedliche Frequenzen - z. B. zur Tonerzeugung - im Hintergrund erzeugen, ohne das Hauptprogramm durch Sprünge in eine Interrupt-Routine und Startwertzuweisungen unterbrechen zu müssen (Bild 1 und 2). Das Ausgabesignal am zugeordneten Ausgabepin behält seine Frequenz bei, bis ein neuer Compare-Wert zugewiesen wird.

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.