|
Timer
Wir wollen einen der Timer benutzen, die uns der Atmega8 zur Verfügung
stellt, um genau jede Sekunde
eine LED blinken zu lassen. Wenn wir einen Quarz benutzen würden, wäre
die Sekunde wirklich ganz exakt. Ohne Quarz, also mit dem internen
1MHz-Takt des Atmega8 ist die Sekunde aber auch schon relativ genau.
Man könnte durchaus einen Küchen-Kurzzeitwecker damit bauen.
Wir benutzen LED1 unseres Experimentierboards (oder ein Steckbrett und
verbinden die LED mit PD2).
Hier das Programm:
#include <avr/io.h>
#include <avr/interrupt.h>
// Interrupt Service Routine fuer Timer1
ISR(TIMER1_OVF_vect) {
TCNT1 = 49911;
//Zaehlregister mit Vorladewert V vorladen / Berechnung: siehe unten
PORTD ^= _BV(PD2); //LED toggeln
}
int main(void){
DDRD |= _BV(PD2) ; // PD2
ist LED Ausgang
sei(); //Interrupts ermoeglichen
// fuer Timer:
TIMSK |= (1<<TOIE1);
TCCR1B |= (1<<CS11) | (1<<CS10);
//Prescaler = 64
TCNT1 = 0xFFFF;
//Zaehlregister vorladen mit FFFF zum Sofortstart
while (1) { /* ich laufe ewig */ }
return(0);
}
Was macht das Programm?
Sicher hast Du schon erkannt, daß wir wieder mit Interrupt arbeiten.
Wenn der Timer einen Interrupt auslöst (also genau jede Sekunde), wird
diese Funktion:
ISR(TIMER1_OVF_vect)
{
TCNT1 = 49911;
PORTD ^= _BV(PD2);
}
angesprungen bzw ausgeführt.
Dort wird die LED an PD2 getoggelt, damit sie blinkt.
Und es wird der sogenannte Vorladewert
TCNT1 in den Timer geladen,
doch dazu später.
Wie funktioniert nun so ein Timer?
Wie ein Zähler, der es bemerkt, wenn er überläuft.
Wenn wir nichts weiteres unternehmen würden, machte der Timer in etwa
folgendes:
- er fängt bei Null an zu zählen
- jede Millionstel Sekunde (denn er arbeitet mit 1 MHz) zählt er
einen Schritt weiter
- wenn er seine größte zu zählende Zahl erreicht hat, läuft er über
- dabei wird in einem bestimmten Register das sogenannte
"Signal-overflow-bit" gesetzt) - und er beginnt wieder von vorn
Um die Geschwindigkeit des
Hochzählens zu verlangsamen, können wir die Quarzfrequenz "vor-teilen".
Die Zahl, die wir dazu benutzen nennt sich Prescaler (dt. Vorteiler).
z.B.:
TCCR1B =
_BV(CS11) | _BV(CS10);//Prescaler = 64
TCCR1B =
_BV(CS12)
//Prescaler = 256
Für genaue Zeiten muß der Wert
(Quarzfrequenz / Prescaler) ein ganzzahliges
Ergebnis liefern!
Ganzzahlige Werte:
1000000 / 64 = 15625 (1 MHz durch
Prescaler 64)
4000000 / 256 = 15625 (4 MHz durch Prescaler
256)
Die größte zu zählende Zahl, die ein 16-bit-Timer zählen kann, ist: 2
hoch 16 = 65536.
Es ist auch nicht notwendig, daß der Timer bei Null mit Zählen
beginnt.
Wir können mit einem Vorladewert
selbst bestimmen, bei welcher Zahl er
mit Zählen anfangen soll (und somit exakt eine Sekunde realisieren).
Der Vorladewert errechnet sich bei unserem 16-bit-Timer:
Vorladewert = 2^16
- (Wunschzeit * Quarzfrequenz / Prescaler)
2^16
- ( 1s
* 1000000 Hz
/
64 ) = 49911
Wir benutzen allerdings keinen Quarz, sondern die intern erzeugte
Frequenz von 1 Mhz, was jedoch nichts an der Formel ändert.
Der Vorladewert muß naturlich jedesmal nach Überlaufen des Timers neu
in ihn hineingeschrieben werden:
TCNT1 = 49911;
Hier gibt es den
Code-Ordner zum
Programmieren des Atmega8.
Näheres wie immer im Datenblatt.
Dies ist die
überabeitete Timer-Seite. Die alte Seite und der alte Code enthielt veraltete Befehle und
funktionierte nur mit alten Versionen der avr-libc.
|