Hallo!
In diesem Beitrag möchte ich endlich auf die Timer/Counter eingehen. So ein Timer/Counter ist eine ziemlich nützliche Sache und der ATmega8 hat drei davon. Man kann damit Ereignisse zählen, genau getaktete Signale erzeugen und noch vieles mehr. Im weiteren Verlauf dieses und der nächsten Beiträge werde ich nur noch Timer statt Timer/Counter schreiben. Zur Erklärung: Als Timer zählt er den Systemtakt und als Counter zählt er externe Ereignisse.
Jetzt wirst du vielleicht fragen, warum man den Systemtakt zählen sollte. Die Sache ist ganz einfach. Ein Timer kann z.B. nach einer gewissen Anzahl an Ticks einen Interrupt auslösen. So hat man einen Interrupt, der immer im gleichen zeitlichen Abstand ausgelöst wird. So kann man einen Interrupt jede Sekunde auslösen lassen. Und dieser Sekundentakt ist dann so genau wie der an den µC angeschlossene Taktgeber (Quarz). Wenn man jede halbe Sekunde einen Interrupt auslösen lässt und bei jedem Interrupt einen Ausgangspin umschaltet (toggelt), dann hat man an diesem Pin eine Frequenz von genau 1 Hz anliegen. Lässt man den Timer öfter so einen Interrupt auslösen, dann wird die Frequenz höher. So können auch hohe Frequenzen bis in den MHz-Bereich (je nach angeschossenem Quarz) erzeugt werden.
Das Geniale dabei ist, so ein Timer funktioniert unabhängig von unserer Main-Loop. Der Timer zählt und zählt, egal ob unser Programm gerade voll im Stress ist oder auf einen Tastendruck wartet. Und das Umschalten von Pins oder das Erzeugen von "Pulsweiten-Modulation (PWM)"-Signalen passiert im Hintergrund. So kann man einen Schrittmotor oder einen Servo mit einer genauen Frequenz ansteuern, auch dann wenn unser Hauptprogramm gerade schläft oder voll im Stress ist.
Nicht jeder Timer kann alles. Timer0 ist der einfachste Timer. Mit ihm kann man eigentlich nur zählen. Timer1 ist der Mercedes unter den Timern. Mit ihm kann man alles machen. Timer2 ist ein Mittelding zwischen Timer0 und Timer1. Der hervorstechende Vorteil des Timer2 ist, dass er den Takt auch direkt von einem 32,768 kHz-Uhrenquarz abnehmen kann. Damit kann man mit dem ATmega8 eine ziemlich genau funktionierende Uhr aufbauen.
Timer0 kann von 0 bis 255 zählen. Timer0 ist ein 8 Bit-Timer. Timer1 kann von 0 bis 65535 zählen (16 Bit-Timer). Und Timer2 kann von 0 bis 255 zählen (8 Bit-Timer). Den Wert eines Timers kann man jederzeit auslesen und auch überschreiben. Auf den Wert des Timer0 greift man über das Register TCNT0 zu. Da der Timer1 ein 16 Bit Timer ist, steht dessen Wert in den zwei 8 Bit-Registern TCNT1H und TCNT1L. Das "H" steht für High und das "L" für Low. Bascom stellt für den einfacheren Zugriff das Pseudo-Register TCNT1 zur Verfügung. Liest man dieses Pseudoregister aus, wird ein WORD und kein BYTE zurück gegeben. Der Wert des Timer2 ist über das Register TCNT2 erreichbar. Als Aliase für TCNT0, TCNT1 und TCNT2 können die Timer-Namen verwendet werden. Diese sind TIMER0, TIMER1 und TIMER2.
Ein Counter kann Frequenzen bis zu Systemtakt / 2,5
zählen. Das ist die absolute Obergrenze. Bei 1 MHz Systemtakt, können Frequenzen bis 400 kHz gezählt werden. Bei einem Systemtakt von 16 MHz kann ein Counter Frequenzen bis zu 6,4 MHz zählen. Mehr geht nicht, da der Counter eine gewisse Zeit braucht um sich zu synchronisieren, die Signalflanke zu erkennen und den Wert des Zählers zu erhöhen.
Ein HIGH oder ein LOW an einem der Timer-Eingänge muss länger als die Dauer eines Systemtaktes sein, damit das Ereignis gezählt werden kann. Bei einem Systemtakt von 8 Mhz muss ein HIGH oder ein LOW an einem Timer-Eingang mindestens (1 / 8.000.000) 0,000000125 Sekunden (125 ns) lang sein.
Wer an die Grenzen eines Timers/Counters gehen will, sollte sich auf jeden Fall das entsprechende Kapitel im ATmega8-Datenblatt durchlesen, um keine unliebsamen Überaschungen zu erleben.
Ist ein Timer beim Zählen am Ende angekommen, dann läuft er über und beginnt wieder bei 0. Man kann den Timer so einstellen, dass bei so einem Überlauf (Overflow) ein Interrupt ausgelöst wird. Die Überlauf-Interrupts der Timer sind OVF0 (OVerFlow0), OVF1 (OVerFlow1) und OVF2 (OVerFlow2). Und wieder sind es die Namen der Timer, die man als Alias für die Interrupt-Namen verwenden kann (TIMER0, TIMER1 und TIMER2).
Man kann einen Prescaler vor einen Timer schalten. Ein Prescaler arbeitet als Vorteiler. Er lässt nur jedes X'te Signal durch. Ein Prescaler übernimmt das zu zählende Signal und gibt erst dann ein Signal weiter, wenn eine einstellbare Anzahl an Ticks vergangen ist. Der Prescaler dividiert also das zu zählende Signal. Mit so einem Prescaler kann man das Signal durch 8, 64, 256 und 1024 dividieren, noch bevor es zum Timer kommt.
Wenn der Prescaler auf 8 eingestellt wird, dann lässt dieser nur jedes achte Signal durch. Bei einem Systemtakt von 8 MHz und einem Prescaler von 8, kommt am Timer 1 MHz an. Der Timer bekommt somit weniger zu tun und man kann die gewünschten Zeitabstände genauer einstellen.
Was man noch wissen sollte: Der Prescaler kann nur im Timer-Modus verwendet werden. Kommt das Signal von extern, also wenn der Timer als Counter läuft, dann kann kein Prescaler zugeschaltet werden. Dann wird ausnahmslos jedes Signal gezählt. Eine Ausnahme stellt nur der Timer2 dar. Der hat seinen eigenen Prescaler um einen genauen Sekundentakt ermitteln zu können. Aber darauf werde ich im Beitrag über den Timer2 genauer eingehen.
Die verschiedenen Timer und deren Möglichkeiten werde ich in den nächsten Beiträgen ansprechen.
mfg Gerold :-)
Den zugehörigen Original-Beitrag findest du im Loetstelle-Forum.
Ich programmiere Progressive Web Applications, Mobile Apps, Desktop-Programme und noch vieles mehr. Falls es dich interessiert, findest du mehr Informationen darüber auf meiner Business-Website.