<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=2001%3AA60%3A13D1%3ACB01%3A352D%3A6309%3A9D08%3A7E1F</id>
	<title>Mikrocontroller.net - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=2001%3AA60%3A13D1%3ACB01%3A352D%3A6309%3A9D08%3A7E1F"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/2001:A60:13D1:CB01:352D:6309:9D08:7E1F"/>
	<updated>2026-04-21T14:28:58Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Uhr&amp;diff=87652</id>
		<title>AVR-Tutorial: Uhr</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Uhr&amp;diff=87652"/>
		<updated>2015-03-04T01:54:46Z</updated>

		<summary type="html">&lt;p&gt;2001:A60:13D1:CB01:352D:6309:9D08:7E1F: /* Das erste Programm */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Eine beliebte Übung für jeden Programmierer ist die Implementierung einer Uhr. Die meisten Uhren bestehen aus einem Taktgeber und einer Auswerte- und Anzeigevorrichtung. Wir wollen hier beides mittels eines Programmes in einem Mikrocontroller realisieren. Voraussetzung für diese Fallstudie ist das Verständnis der Kapitel über&lt;br /&gt;
&lt;br /&gt;
* [[AVR-Tutorial: LCD| Ansteuerung eines LC-Displays]]&lt;br /&gt;
* [[AVR-Tutorial: Timer| Timer]]&lt;br /&gt;
&lt;br /&gt;
== Aufbau und Funktion ==&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Taktgebers, der uns einen möglichst konstanten und genauen Takt liefert, übernimmt ein Timer. Der Timer ermöglicht einen einfachen Zugang zum Takt, den der AVR vom Quarz abgreift. Wie schon im Einführungskapitel über den [[AVR-Tutorial:_Timer|Timer]] beschrieben, wird dazu ein Timer Overflow Interrupt installiert, und in diesem Interrupt wird die eigentliche Uhr hochgezählt. Die Uhr besteht aus vier Registern. Drei davon repräsentieren die Sekunden, Minuten und Stunden unserer Uhr. Nach jeweils einer Sekunde wird das Sekundenregister um eins erhöht. Sind 60 Sekunden vergangen, wird das Sekundenregister wieder auf Null gesetzt und gleichzeitig das Minutenregister um eins erhöht. Dies ist ein Überlauf. Nach 60 Minuten werden die Minuten wieder auf Null gesetzt und für diese vergangenen 60 Minuten eine Stunde aufaddiert. Nach 24 Stunden schliesslich werden die Stunden wieder auf Null gesetzt, ein ganzer Tag ist vergangen.&lt;br /&gt;
&lt;br /&gt;
Aber wozu das vierte Register?&lt;br /&gt;
&lt;br /&gt;
Der Mikrocontroller wird mit 4 MHz betrieben. Bei einem Teiler von 1024 zählt der Timer also mit 4000000 / 1024 = 3906,25 Pulsen pro Sekunde. Der Timer muss einmal bis 256 zählen, bis er einen Überlauf auslöst. Es ereignen sich also 3906,25 / 256 = 15,2587 Überläufe pro Sekunde. Die Aufgabe des vierten Registers ist es nun, diese 15 Überläufe zu zählen. Bei Auftreten des 15. ist eine Sekunde vergangen. Dies stimmt jedoch nicht exakt, denn die Division weist ja auch Nachkommastellen auf, hat einen Rest, der hier im Moment der Einfachheit halber ignoriert wird. In einem späteren Abschnitt wird darauf noch eingegangen werden.&lt;br /&gt;
&lt;br /&gt;
Im Überlauf-Interrupt wird also diese Kette von Zählvorgängen auf den Sekunden, Minuten und Stunden durchgeführt und anschliessend zur Anzeige gebracht. Dazu werden die in einem vorhergehenden Kapitel entwickelten [[AVR-Tutorial:_LCD|LCD Funktionen]] benutzt.&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
.def temp2 = r17&lt;br /&gt;
.def temp3 = r18&lt;br /&gt;
.def flag  = r19&lt;br /&gt;
 &lt;br /&gt;
.def SubCount = r21&lt;br /&gt;
.def Sekunden = r22&lt;br /&gt;
.def Minuten  = r23&lt;br /&gt;
.def Stunden  = r24&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
        rjmp    main                ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
        rjmp    timer0_overflow     ; Timer Overflow Handler&lt;br /&gt;
&lt;br /&gt;
.include &amp;quot;lcd-routines.asm&amp;quot;&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp1&lt;br /&gt;
        ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
        out     SPL, temp1&lt;br /&gt;
&lt;br /&gt;
        ldi temp1, 0xFF    ; Port D = Ausgang&lt;br /&gt;
        out DDRD, temp1 &lt;br /&gt;
    &lt;br /&gt;
        rcall   lcd_init&lt;br /&gt;
        rcall   lcd_clear&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
        ldi     temp1, (1&amp;lt;&amp;lt;CS02) | (1&amp;lt;&amp;lt;CS00)   ; Teiler 1024&lt;br /&gt;
        out     TCCR0, temp1&lt;br /&gt;
 &lt;br /&gt;
        ldi     temp1, 1&amp;lt;&amp;lt;TOIE0     ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp1&lt;br /&gt;
 &lt;br /&gt;
        clr     Minuten             ; Die Uhr auf 0 setzen&lt;br /&gt;
        clr     Sekunden&lt;br /&gt;
        clr     Stunden&lt;br /&gt;
        clr     SubCount&lt;br /&gt;
        clr     Flag                ; Merker löschen&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
 &lt;br /&gt;
loop:&lt;br /&gt;
        cpi     flag,0&lt;br /&gt;
        breq    loop                ; Flag im Interrupt gesetzt?&lt;br /&gt;
        ldi     flag,0              ; flag löschen&lt;br /&gt;
  &lt;br /&gt;
        rcall   lcd_clear           ; das LCD löschen&lt;br /&gt;
        mov     temp1, Stunden      ; und die Stunden ausgeben&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
        ldi     temp1, &#039;:&#039;          ; zwischen Stunden und Minuten einen &#039;:&#039;&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
        mov     temp1, Minuten      ; dann die Minuten ausgeben&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
        ldi     temp1, &#039;:&#039;          ; und noch ein &#039;:&#039;&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
        mov     temp1, Sekunden     ; und die Sekunden&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
&lt;br /&gt;
        rjmp    loop&lt;br /&gt;
 &lt;br /&gt;
timer0_overflow:                    ; Timer 0 Overflow Handler&lt;br /&gt;
&lt;br /&gt;
        push    temp1               ; temp 1 sichern&lt;br /&gt;
        in      temp1,sreg          ; SREG sichern&lt;br /&gt;
        push    temp1&lt;br /&gt;
&lt;br /&gt;
        inc     SubCount            ; Wenn dies nicht der 15. Interrupt&lt;br /&gt;
        cpi     SubCount, 15        ; ist, dann passiert gar nichts&lt;br /&gt;
        brne    end_isr&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     SubCount            ; SubCount rücksetzen&lt;br /&gt;
        inc     Sekunden            ; plus 1 Sekunde&lt;br /&gt;
        cpi     Sekunden, 60        ; sind 60 Sekunden vergangen?&lt;br /&gt;
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon&lt;br /&gt;
                                    ; gemacht werden&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Sekunden            ; Sekunden wieder auf 0 und dafür&lt;br /&gt;
        inc     Minuten             ; plus 1 Minute&lt;br /&gt;
        cpi     Minuten, 60         ; sind 60 Minuten vergangen ?&lt;br /&gt;
        brne    Ausgabe             ; wenn nicht, -&amp;gt; Ausgabe&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Minuten             ; Minuten zurücksetzen und dafür&lt;br /&gt;
        inc     Stunden             ; plus 1 Stunde&lt;br /&gt;
        cpi     Stunden, 24         ; nach 24 Stunden, die Stundenanzeige&lt;br /&gt;
        brne    Ausgabe             ; wieder zurücksetzen&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Stunden             ; Stunden rücksetzen&lt;br /&gt;
&lt;br /&gt;
Ausgabe:&lt;br /&gt;
        ldi     flag,1              ; Flag setzen, LCD updaten&lt;br /&gt;
&lt;br /&gt;
end_isr:&lt;br /&gt;
&lt;br /&gt;
        pop     temp1&lt;br /&gt;
        out     sreg,temp1          ; sreg wieder herstellen&lt;br /&gt;
        pop     temp1&lt;br /&gt;
        reti                        ; das wars. Interrupt ist fertig&lt;br /&gt;
&lt;br /&gt;
; Eine Zahl aus dem Register temp1 ausgeben&lt;br /&gt;
&lt;br /&gt;
lcd_number:&lt;br /&gt;
        push    temp2               ; register sichern,&lt;br /&gt;
                                    ; wird für Zwsichenergebnisse gebraucht     &lt;br /&gt;
        ldi     temp2, &#039;0&#039;         &lt;br /&gt;
lcd_number_10:                &lt;br /&gt;
        subi    temp1, 10           ; abzählen wieviele Zehner in&lt;br /&gt;
        brcs    lcd_number_1        ; der Zahl enthalten sind&lt;br /&gt;
        inc     temp2&lt;br /&gt;
        rjmp    lcd_number_10&lt;br /&gt;
lcd_number_1:&lt;br /&gt;
        push    temp1               ; den Rest sichern (http://www.mikrocontroller.net/topic/172026)&lt;br /&gt;
        mov     temp1,temp2         ; &lt;br /&gt;
        rcall   lcd_data            ; die Zehnerstelle ausgeben&lt;br /&gt;
        pop     temp1               ; den Rest wiederherstellen&lt;br /&gt;
        subi    temp1, -10          ; 10 wieder dazuzählen, da die&lt;br /&gt;
                                    ; vorhergehende Schleife 10 zuviel&lt;br /&gt;
                                    ; abgezogen hat&lt;br /&gt;
                                    ; das Subtrahieren von -10&lt;br /&gt;
                                    ; = Addition von +10 ist ein Trick&lt;br /&gt;
                                    ; da kein addi Befehl existiert&lt;br /&gt;
        ldi     temp2, &#039;0&#039;          ; die übrig gebliebenen Einer&lt;br /&gt;
        add     temp1, temp2        ; noch ausgeben&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
&lt;br /&gt;
        pop     temp2               ; Register wieder herstellen&lt;br /&gt;
        ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der ISR wird nur die Zeit in den Registern neu berechnet, die Ausgabe auf das LCD erfolgt in der Hauptschleife. Das ist notwendig, da die LCD-Ausgabe bisweilen sehr lange dauern kann. Wenn sie länger als ~2/15 Sekunden dauert werden Timerinterrupts &amp;quot;verschluckt&amp;quot; und unsere Uhr geht noch mehr falsch. Dadurch, dass aber die Ausgabe in der Hauptschleife durchgeführt wird, welche jederzeit durch einen Timerinterrupt unterbrochen werden kann, werden keine Timerinterrupts verschluckt. Das ist vor allem wichtig, wenn mit höheren Interruptfrequenzen gearbeitet wird, z.&amp;amp;nbsp;B. 1/100s im Beispiel weiter unten. Auch wenn in diesem einfachen Beispiel die Ausgabe bei weitem nicht 2/15 Sekunden dauert, sollte man sich diesen Programmierstil allgemein angewöhnen. Siehe auch [[Interrupt]].&lt;br /&gt;
&lt;br /&gt;
Eine weitere Besonderheit ist das Register &#039;&#039;&#039;flag&#039;&#039;&#039; (=r19). Dieses Register fungiert als Anzeiger, wie eine Flagge, daher auch der Name. In der ISR wird dieses Register auf 1 gesetzt. Die Hauptschleife, also alles zwischen &#039;&#039;loop&#039;&#039; und &#039;&#039;rjmp loop&#039;&#039;, prüft dieses Flag und nur dann, wenn das Flag auf 1 steht, wird die LCD Ausgabe gemacht und das Flag wieder auf 0 zurückgesetzt. Auf diese Art wird nur dann Rechenzeit für die LCD Ausgabe verbraucht, wenn dies tatsächlich notwendig ist. Die ISR teilt mit dem Flag der Hauptschleife mit, dass eine bestimmte Aufgabe, nämlich der Update der Anzeige gemacht werden muss und die Hauptschleife reagiert darauf bei nächster Gelegenheit, indem sie diese Aufgabe ausführt und setzt das Flag zurück. Solche Flags werden daher auch &#039;&#039;&#039;Job-Flags&#039;&#039;&#039; genannt, weil durch ihr setzten das Abarbeiten eines Jobs (einer Aufgabe) angestoßen wird. Auch hier gilt wieder: Im Grunde würde man in diesem speziellen Beispiel kein Job-Flag benötigen, weil es in der Hauptschleife nur einen einzigen möglichen Job, die Neuausgabe der Uhrzeit, gibt. Sobald aber Programme komplizierter werden und mehrere Jobs möglich sind, sind Job-Flags eine gute Möglichkeit, ein Programm so zu organsieren, dass bestimmte Dinge nur dann gemacht werden, wenn sie notwendig sind.&lt;br /&gt;
&lt;br /&gt;
Im Moment gibt es keine Möglichkeit, die Uhr auf eine bestimmte Uhrzeit einzustellen. Um dies tun zu können, müssten noch zusätzlich Taster an den Mikrocontroller angeschlossen werden, mit deren Hilfe die Sekunden, Minuten und Stunden händisch vergrößert bzw. verkleinert werden können. Studieren Sie mal die Bedienungsanleitung einer käuflichen Digitaluhr und versuchen sie zu beschreiben, wie dieser Stellvorgang bei dieser Uhr vor sich geht. Sicherlich werden Sie daraus eine Idee entwickeln können, wie ein derartiges Stellen mit der hier vorgestellten Digitaluhr funktionieren könnte. Als Zwischenlösung kann man im Programm die Uhr beim Start anstelle von 00:00:00 z.&amp;amp;nbsp;B. auch auf 20:00:00 stellen und exakt mit dem Start der Tagesschau starten. Wobei der Start der Tagesschau verzögert bei uns ankommt, je nach Übertragung können das mehrere Sekunden sein.&lt;br /&gt;
&lt;br /&gt;
== Ganggenauigkeit ==&lt;br /&gt;
&lt;br /&gt;
Wird die Uhr mit einer gekauften Uhr verglichen, so stellt man schnell fest, dass sie ganz schön ungenau geht. Sie geht vor! Woran liegt das? Die Berechnung sieht so aus:&lt;br /&gt;
* Frequenz des Quarzes: 4.0 MHz&lt;br /&gt;
* Vorteiler des Timers: 1024&lt;br /&gt;
* Überlauf alle 256 Timertakte&lt;br /&gt;
&lt;br /&gt;
Daraus errechnet sich, dass in einer Sekunde 4000000 / 1024 / 256 = 15.258789 Overflow Interrupts auftreten. Im Programm wird aber bereits nach 15 Overflows eine Sekunde weitergeschaltet, daher geht die Uhr vor. Rechnen wir etwas:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F_r = (\frac {15}{15,258789}-1) \cdot 100% = -1,69%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So wie bisher läuft die Uhr also rund 1.7 % zu schnell. In einer Minute ist das immerhin etwas mehr als eine Sekunde. Im Grunde ist das ein ähnliches Problem wie mit unserer Jahreslänge. Ein Jahr dauert nicht exakt 365 Tage, sondern in etwa einen viertel Tag länger. Die Lösung, die im Kalender dafür gemacht wurde - der Schalttag -, könnte man fast direkt übernehmen. Nach 3 Stück 15er Overflow Sekunden folgt eine Sekunde für die 16 Overflows ablaufen müssen. Wie sieht die Rechnung bei einem 15, 15, 15, 16 Schema aus? Für 4 Sekunden werden exakt 15.258789 * 4 = 61,035156 Overflow Interrupts benötigt. Mit einem 15, 15, 15, 16 Schema werden in 4 Sekunden genau 61 Overflow Interrupts durchgeführt. Der relative Fehler beträgt dann&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F_r = (\frac {61}{61,035156}-1) \cdot 100% = -0,0575%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit diesem Schema ist der Fehler beträchtlich gesunken. Nur noch 0.06%. Bei dieser Rate muss die Uhr immerhin etwas länger als 0,5 Stunden laufen, bis der Fehler auf eine Sekunde angewachsen ist. Das sind aber immer noch 48 Sekunden pro Tag bzw. 1488 Sekunden (=24,8 Minuten) pro Monat. So schlecht sind nicht mal billige mechanische Uhren!&lt;br /&gt;
&lt;br /&gt;
Jetzt könnte man natürlich noch weiter gehen und immer kompliziertere &amp;quot;Schalt-Overflow&amp;quot;-Schemata austüfteln und damit die Genauigkeit näher an 100% bringen. Aber gibt es noch andere Möglichkeiten?&lt;br /&gt;
&lt;br /&gt;
Im ersten Ansatz wurde ein Vorteiler von 1024 eingesetzt. Was passiert bei einem anderen Vorteiler? Nehmen wir mal einen Vorteiler von 64. Das heißt, es müssen ( 4000000 / 64 ) / 256 = 244.140625 Overflows auflaufen, bis 1 Sekunde vergangen ist. Wenn also 244 Overflows gezählt werden, dann beläuft sich der Fehler auf&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F_r = (\frac {244}{244,140625}-1) \cdot 100% = -0,0576%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nicht schlecht. Nur durch Verändern von 2 Zahlenwerten im Programm (Teilerfaktor und Anzahl der Overflow Interrupts bis zu einer Sekunden) kann die Genauigkeit gegenüber dem ursprünglichen Overflow-Schema beträchtlich gesteigert werden. Aber geht das noch besser? Ja das geht. Allerdings nicht mit dem Overflow Interrupt.&lt;br /&gt;
&lt;br /&gt;
== Der CTC-Modus des Timers ==&lt;br /&gt;
&lt;br /&gt;
Worin liegt denn das eigentliche Problem, mit dem die Uhr zu kämpfen hat? Das Problem liegt darin, dass jedesmal ein kompletter Timerzyklus bis zum Overflow abgewartet werden muss, um darauf zu reagieren. Da aber nur jeweils ganzzahlige Overflowzyklen abgezählt werden können, heißt das auch, dass im ersten Fall nur in Vielfachen von 1024 * 256 = 262144 Takten operiert werden kann, während im letzten Fall immerhin schon eine Granulierung von 64 * 256 = 16384 Takten erreicht wird. Aber offensichtlich ist das nicht genau genug. Bei 4 MHz entsprechen 262144 Takte bereits einem Zeitraum von 65,5ms, während 16384 Takte einem Zeitbedarf von 4,096ms entsprechen. Beide Zahlen teilen aber 1000ms nicht ganzzahlig. Und daraus entsteht der Fehler. Angestrebt wird ein Timer, der seinen &amp;lt;i&amp;gt;Overflow&amp;lt;/i&amp;gt; so erreicht, dass sich ein ganzzahliger Teiler von 1 Sekunde einstellt. Dazu müsste man dem Timer aber vorschreiben können, bei welchem Zählerstand der &amp;lt;i&amp;gt;Overflow&amp;lt;/i&amp;gt; erfolgen soll. Und genau dies ist im &#039;&#039;&#039;CTC&#039;&#039;&#039;-Modus, allerdings nur beim Timer 1, möglich. &#039;&#039;&#039;CTC&#039;&#039;&#039; bedeutet &amp;quot;&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;imer on &#039;&#039;&#039;C&#039;&#039;&#039;ompare match&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Timer 1, ein 16-Bit-Timer, wird mit einem Vorteiler von 1 betrieben. Dadurch wird erreicht, dass der Timer mit höchster Zeitauflösung arbeiten kann. Bei jedem Ticken des Systemtaktes von 4 MHz wird auch der Timer um 1 erhöht. Zusätzlich wird noch das WGM12-Bit bei der Konfiguration gesetzt. Dadurch wird der Timer in den &#039;&#039;&#039;CTC&#039;&#039;&#039;-Modus gesetzt. Dabei wird der Inhalt des Timers hardwaremäßig mit dem Inhalt des &#039;&#039;&#039;OCR1A&#039;&#039;&#039;-Registers verglichen. Stimmen beide überein, so wird der Timer auf 0 zurückgesetzt und im nächsten Taktzyklus ein &#039;&#039;&#039;OCIE1A&#039;&#039;&#039;-Interrupt ausgelöst. Dadurch ist es möglich, exakt die Anzahl an Taktzyklen festzulegen, die von einem Interrupt zum nächsten vergehen sollen. Das Compare Register &#039;&#039;&#039;OCR1A&#039;&#039;&#039; wird mit dem Wert 39999 vorbelegt. Dadurch vergehen exakt 40000 Taktzyklen von einem Compare-Interrupt zum nächsten. &amp;quot;Zufällig&amp;quot; ist dieser Wert so gewählt, dass bei einem Systemtakt von 4 MHz von einem Interrupt zum nächsten genau 1/100 Sekunde vergeht, denn 40000 / 4000000 = 0.01. Bei einem möglichen Umbau der Uhr zu einer Stoppuhr könnte sich das als nützlich erweisen. Im Interrupt wird das Hilfsregister SubCount bis 100 hochgezählt und nach 100 Interrupts kommt wieder die Sekundenweiterschaltung wie oben in Gang.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
.def temp2 = r17&lt;br /&gt;
.def temp3 = r18&lt;br /&gt;
.def Flag  = r19&lt;br /&gt;
 &lt;br /&gt;
.def SubCount = r21&lt;br /&gt;
.def Sekunden = r22&lt;br /&gt;
.def Minuten  = r23&lt;br /&gt;
.def Stunden  = r24&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
           rjmp    main             ; Reset Handler&lt;br /&gt;
.org OC1Aaddr&lt;br /&gt;
           rjmp    timer1_compare   ; Timer Compare Handler&lt;br /&gt;
&lt;br /&gt;
.include &amp;quot;lcd-routines.asm&amp;quot;&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp1&lt;br /&gt;
        ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
        out     SPL, temp1&lt;br /&gt;
&lt;br /&gt;
        ldi temp1, 0xFF    ; Port D = Ausgang&lt;br /&gt;
        out DDRD, temp1     &lt;br /&gt;
&lt;br /&gt;
        rcall   lcd_init&lt;br /&gt;
        rcall   lcd_clear&lt;br /&gt;
 &lt;br /&gt;
                                    ; Vergleichswert &lt;br /&gt;
        ldi     temp1, high( 40000 - 1 )&lt;br /&gt;
        out     OCR1AH, temp1&lt;br /&gt;
        ldi     temp1, low( 40000 - 1 )&lt;br /&gt;
        out     OCR1AL, temp1&lt;br /&gt;
                                    ; CTC Modus einschalten&lt;br /&gt;
                                    ; Vorteiler auf 1&lt;br /&gt;
        ldi     temp1, ( 1 &amp;lt;&amp;lt; WGM12 ) | ( 1 &amp;lt;&amp;lt; CS10 )&lt;br /&gt;
        out     TCCR1B, temp1&lt;br /&gt;
 &lt;br /&gt;
        ldi     temp1, 1 &amp;lt;&amp;lt; OCIE1A  ; OCIE1A: Interrupt bei Timer Compare&lt;br /&gt;
        out     TIMSK, temp1&lt;br /&gt;
 &lt;br /&gt;
        clr     Minuten             ; Die Uhr auf 0 setzen&lt;br /&gt;
        clr     Sekunden&lt;br /&gt;
        clr     Stunden&lt;br /&gt;
        clr     SubCount&lt;br /&gt;
        clr     Flag                ; Flag löschen&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
loop:&lt;br /&gt;
        cpi     flag,0&lt;br /&gt;
        breq    loop                ; Flag im Interrupt gesetzt?&lt;br /&gt;
        ldi     flag,0              ; Flag löschen&lt;br /&gt;
  &lt;br /&gt;
        rcall   lcd_clear           ; das LCD löschen&lt;br /&gt;
        mov     temp1, Stunden      ; und die Stunden ausgeben&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
        ldi     temp1, &#039;:&#039;          ; zwischen Stunden und Minuten einen &#039;:&#039;&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
        mov     temp1, Minuten      ; dann die Minuten ausgeben&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
        ldi     temp1, &#039;:&#039;          ; und noch ein &#039;:&#039;&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
        mov     temp1, Sekunden     ; und die Sekunden&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
&lt;br /&gt;
        rjmp    loop&lt;br /&gt;
 &lt;br /&gt;
timer1_compare:                     ; Timer 1 Output Compare Handler&lt;br /&gt;
&lt;br /&gt;
        push    temp1               ; temp 1 sichern&lt;br /&gt;
        in      temp1,sreg          ; SREG sichern&lt;br /&gt;
&lt;br /&gt;
        inc     SubCount            ; Wenn dies nicht der 100. Interrupt&lt;br /&gt;
        cpi     SubCount, 100       ; ist, dann passiert gar nichts&lt;br /&gt;
        brne    end_isr&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     SubCount            ; SubCount rücksetzen&lt;br /&gt;
        inc     Sekunden            ; plus 1 Sekunde&lt;br /&gt;
        cpi     Sekunden, 60        ; sind 60 Sekunden vergangen?&lt;br /&gt;
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon&lt;br /&gt;
                                    ; gemacht werden&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Sekunden            ; Sekunden wieder auf 0 und dafür&lt;br /&gt;
        inc     Minuten             ; plus 1 Minute&lt;br /&gt;
        cpi     Minuten, 60         ; sind 60 Minuten vergangen ?&lt;br /&gt;
        brne    Ausgabe             ; wenn nicht, -&amp;gt; Ausgabe&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Minuten             ; Minuten zurücksetzen und dafür&lt;br /&gt;
        inc     Stunden             ; plus 1 Stunde&lt;br /&gt;
        cpi     Stunden, 24         ; nach 24 Stunden, die Stundenanzeige&lt;br /&gt;
        brne    Ausgabe             ; wieder zurücksetzen&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Stunden             ; Stunden rücksetzen&lt;br /&gt;
&lt;br /&gt;
Ausgabe:&lt;br /&gt;
        ldi     flag,1              ; Flag setzen, LCD updaten&lt;br /&gt;
&lt;br /&gt;
end_isr:&lt;br /&gt;
&lt;br /&gt;
        out     sreg,temp1          ; sreg wieder herstellen&lt;br /&gt;
        pop     temp1&lt;br /&gt;
        reti                        ; das wars. Interrupt ist fertig&lt;br /&gt;
&lt;br /&gt;
; Eine Zahl aus dem Register temp1 ausgeben&lt;br /&gt;
&lt;br /&gt;
lcd_number:&lt;br /&gt;
        push    temp2               ; register sichern,&lt;br /&gt;
                                    ; wird für Zwsichenergebnisse gebraucht     &lt;br /&gt;
        ldi     temp2, &#039;0&#039;         &lt;br /&gt;
lcd_number_10:                &lt;br /&gt;
        subi    temp1, 10           ; abzählen wieviele Zehner in&lt;br /&gt;
        brcs    lcd_number_1        ; der Zahl enthalten sind&lt;br /&gt;
        inc     temp2&lt;br /&gt;
        rjmp    lcd_number_10&lt;br /&gt;
lcd_number_1:&lt;br /&gt;
        push    temp1               ; den Rest sichern (http://www.mikrocontroller.net/topic/172026)&lt;br /&gt;
        mov     temp1,temp2         ; &lt;br /&gt;
        rcall   lcd_data            ; die Zehnerstelle ausgeben&lt;br /&gt;
        pop     temp1               ; den Rest wieder holen&lt;br /&gt;
        subi    temp1, -10          ; 10 wieder dazuzählen, da die&lt;br /&gt;
                                    ; vorhergehende Schleife 10 zuviel&lt;br /&gt;
                                    ; abgezogen hat&lt;br /&gt;
                                    ; das Subtrahieren von -10&lt;br /&gt;
                                    ; = Addition von +10 ist ein Trick&lt;br /&gt;
                                    ; da kein addi Befehl existiert&lt;br /&gt;
        ldi     temp2, &#039;0&#039;          ; die übrig gebliebenen Einer&lt;br /&gt;
        add     temp1, temp2        ; noch ausgeben&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
&lt;br /&gt;
        pop     temp2               ; Register wieder herstellen&lt;br /&gt;
        ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Interrupt-Routine werden wieder, genauso wie vorher, die Anzahl der Interrupt-Aufrufe gezählt. Beim 100. Aufruf sind daher 40.000 * 100 = 4.000.000 Takte vergangen und da der Quarz mit 4.000.000 Schwingungen in der Sekunde arbeitet, ist daher eine Sekunde vergangen. Sie wird genauso wie vorher registriert und die Uhr entsprechend hochgezählt. Wird jetzt die Uhr mit einer kommerziellen verglichen, dann fällt nach einiger Zeit auf ... Sie geht immer noch falsch! Was ist jetzt die Ursache? Die Ursache liegt in einem Problem, das nicht direkt behebbar ist. Am Quarz! Auch wenn auf dem Quarz drauf steht, dass er eine Frequenz von 4MHz hat, so stimmt das nicht exakt. Auch Quarze haben Fertigungstoleranzen und verändern ihre Frequenz mit der Temperatur. Typisch liegt die Fertigungstoleranz bei +/- 100ppm = 0,01% (&#039;&#039;&#039;p&#039;&#039;&#039;arts &#039;&#039;&#039;p&#039;&#039;&#039;er &#039;&#039;&#039;m&#039;&#039;&#039;illion, Millionstel Teile), die Temperaturdrift zwischen -40 Grad und 85 Grad liegt je nach Typ in der selben Größenordnung. Das bedeutet, dass die Uhr pro Monat um bis zu 268 Sekunden (~4 1/2 Minuten) falsch gehen kann. Diese Einflüsse auf die Quarzfrequenz sind aber messbar und per Hardware oder Software behebbar. In Uhren kommen normalerweise genauer gefertigte Uhrenquarze zum Einsatz, die vom Uhrmacher auch noch auf die exakte Frequenz abgeglichen werden (mittels Kondensatoren und Frequenzzähler). Ein Profi verwendet einen sehr genauen Frequenzzähler, womit er innerhalb weniger Sekunden die Frequenz sehr genau messen kann. Als Hobbybastler kann man die Uhr eine zeitlang (Tage, Wochen) laufen lassen und die Abweichung feststellen (z.&amp;amp;nbsp;B. exakt 20:00 Uhr zum Start der Tagsschau). Aus dieser Abweichung lässt sich dann errechnen, wie schnell der Quarz wirklich schwingt. Und da dank CTC die Messperiode taktgenau eingestellt werden kann, ist es möglich, diesen Frequenzfehler auszugleichen. Der genaue Vorgang ist in dem Wikiartikel [[AVR - Die genaue Sekunde / RTC]] beschrieben. &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Timer|&lt;br /&gt;
zurücklink=AVR-Tutorial: Timer|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=ADC|&lt;br /&gt;
vorlink=AVR-Tutorial: ADC}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Uhr]]&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;/div&gt;</summary>
		<author><name>2001:A60:13D1:CB01:352D:6309:9D08:7E1F</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Uhr&amp;diff=87651</id>
		<title>AVR-Tutorial: Uhr</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Uhr&amp;diff=87651"/>
		<updated>2015-03-04T01:53:59Z</updated>

		<summary type="html">&lt;p&gt;2001:A60:13D1:CB01:352D:6309:9D08:7E1F: /* Der CTC-Modus des Timers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Eine beliebte Übung für jeden Programmierer ist die Implementierung einer Uhr. Die meisten Uhren bestehen aus einem Taktgeber und einer Auswerte- und Anzeigevorrichtung. Wir wollen hier beides mittels eines Programmes in einem Mikrocontroller realisieren. Voraussetzung für diese Fallstudie ist das Verständnis der Kapitel über&lt;br /&gt;
&lt;br /&gt;
* [[AVR-Tutorial: LCD| Ansteuerung eines LC-Displays]]&lt;br /&gt;
* [[AVR-Tutorial: Timer| Timer]]&lt;br /&gt;
&lt;br /&gt;
== Aufbau und Funktion ==&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Taktgebers, der uns einen möglichst konstanten und genauen Takt liefert, übernimmt ein Timer. Der Timer ermöglicht einen einfachen Zugang zum Takt, den der AVR vom Quarz abgreift. Wie schon im Einführungskapitel über den [[AVR-Tutorial:_Timer|Timer]] beschrieben, wird dazu ein Timer Overflow Interrupt installiert, und in diesem Interrupt wird die eigentliche Uhr hochgezählt. Die Uhr besteht aus vier Registern. Drei davon repräsentieren die Sekunden, Minuten und Stunden unserer Uhr. Nach jeweils einer Sekunde wird das Sekundenregister um eins erhöht. Sind 60 Sekunden vergangen, wird das Sekundenregister wieder auf Null gesetzt und gleichzeitig das Minutenregister um eins erhöht. Dies ist ein Überlauf. Nach 60 Minuten werden die Minuten wieder auf Null gesetzt und für diese vergangenen 60 Minuten eine Stunde aufaddiert. Nach 24 Stunden schliesslich werden die Stunden wieder auf Null gesetzt, ein ganzer Tag ist vergangen.&lt;br /&gt;
&lt;br /&gt;
Aber wozu das vierte Register?&lt;br /&gt;
&lt;br /&gt;
Der Mikrocontroller wird mit 4 MHz betrieben. Bei einem Teiler von 1024 zählt der Timer also mit 4000000 / 1024 = 3906,25 Pulsen pro Sekunde. Der Timer muss einmal bis 256 zählen, bis er einen Überlauf auslöst. Es ereignen sich also 3906,25 / 256 = 15,2587 Überläufe pro Sekunde. Die Aufgabe des vierten Registers ist es nun, diese 15 Überläufe zu zählen. Bei Auftreten des 15. ist eine Sekunde vergangen. Dies stimmt jedoch nicht exakt, denn die Division weist ja auch Nachkommastellen auf, hat einen Rest, der hier im Moment der Einfachheit halber ignoriert wird. In einem späteren Abschnitt wird darauf noch eingegangen werden.&lt;br /&gt;
&lt;br /&gt;
Im Überlauf-Interrupt wird also diese Kette von Zählvorgängen auf den Sekunden, Minuten und Stunden durchgeführt und anschliessend zur Anzeige gebracht. Dazu werden die in einem vorhergehenden Kapitel entwickelten [[AVR-Tutorial:_LCD|LCD Funktionen]] benutzt.&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
.def temp2 = r17&lt;br /&gt;
.def temp3 = r18&lt;br /&gt;
.def flag  = r19&lt;br /&gt;
 &lt;br /&gt;
.def SubCount = r21&lt;br /&gt;
.def Sekunden = r22&lt;br /&gt;
.def Minuten  = r23&lt;br /&gt;
.def Stunden  = r24&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
        rjmp    main                ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
        rjmp    timer0_overflow     ; Timer Overflow Handler&lt;br /&gt;
&lt;br /&gt;
.include &amp;quot;lcd-routines.asm&amp;quot;&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp1&lt;br /&gt;
        ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
        out     SPL, temp1&lt;br /&gt;
    &lt;br /&gt;
        rcall   lcd_init&lt;br /&gt;
        rcall   lcd_clear&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
        ldi     temp1, (1&amp;lt;&amp;lt;CS02) | (1&amp;lt;&amp;lt;CS00)   ; Teiler 1024&lt;br /&gt;
        out     TCCR0, temp1&lt;br /&gt;
 &lt;br /&gt;
        ldi     temp1, 1&amp;lt;&amp;lt;TOIE0     ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp1&lt;br /&gt;
 &lt;br /&gt;
        clr     Minuten             ; Die Uhr auf 0 setzen&lt;br /&gt;
        clr     Sekunden&lt;br /&gt;
        clr     Stunden&lt;br /&gt;
        clr     SubCount&lt;br /&gt;
        clr     Flag                ; Merker löschen&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
 &lt;br /&gt;
loop:&lt;br /&gt;
        cpi     flag,0&lt;br /&gt;
        breq    loop                ; Flag im Interrupt gesetzt?&lt;br /&gt;
        ldi     flag,0              ; flag löschen&lt;br /&gt;
  &lt;br /&gt;
        rcall   lcd_clear           ; das LCD löschen&lt;br /&gt;
        mov     temp1, Stunden      ; und die Stunden ausgeben&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
        ldi     temp1, &#039;:&#039;          ; zwischen Stunden und Minuten einen &#039;:&#039;&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
        mov     temp1, Minuten      ; dann die Minuten ausgeben&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
        ldi     temp1, &#039;:&#039;          ; und noch ein &#039;:&#039;&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
        mov     temp1, Sekunden     ; und die Sekunden&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
&lt;br /&gt;
        rjmp    loop&lt;br /&gt;
 &lt;br /&gt;
timer0_overflow:                    ; Timer 0 Overflow Handler&lt;br /&gt;
&lt;br /&gt;
        push    temp1               ; temp 1 sichern&lt;br /&gt;
        in      temp1,sreg          ; SREG sichern&lt;br /&gt;
        push    temp1&lt;br /&gt;
&lt;br /&gt;
        inc     SubCount            ; Wenn dies nicht der 15. Interrupt&lt;br /&gt;
        cpi     SubCount, 15        ; ist, dann passiert gar nichts&lt;br /&gt;
        brne    end_isr&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     SubCount            ; SubCount rücksetzen&lt;br /&gt;
        inc     Sekunden            ; plus 1 Sekunde&lt;br /&gt;
        cpi     Sekunden, 60        ; sind 60 Sekunden vergangen?&lt;br /&gt;
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon&lt;br /&gt;
                                    ; gemacht werden&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Sekunden            ; Sekunden wieder auf 0 und dafür&lt;br /&gt;
        inc     Minuten             ; plus 1 Minute&lt;br /&gt;
        cpi     Minuten, 60         ; sind 60 Minuten vergangen ?&lt;br /&gt;
        brne    Ausgabe             ; wenn nicht, -&amp;gt; Ausgabe&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Minuten             ; Minuten zurücksetzen und dafür&lt;br /&gt;
        inc     Stunden             ; plus 1 Stunde&lt;br /&gt;
        cpi     Stunden, 24         ; nach 24 Stunden, die Stundenanzeige&lt;br /&gt;
        brne    Ausgabe             ; wieder zurücksetzen&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Stunden             ; Stunden rücksetzen&lt;br /&gt;
&lt;br /&gt;
Ausgabe:&lt;br /&gt;
        ldi     flag,1              ; Flag setzen, LCD updaten&lt;br /&gt;
&lt;br /&gt;
end_isr:&lt;br /&gt;
&lt;br /&gt;
        pop     temp1&lt;br /&gt;
        out     sreg,temp1          ; sreg wieder herstellen&lt;br /&gt;
        pop     temp1&lt;br /&gt;
        reti                        ; das wars. Interrupt ist fertig&lt;br /&gt;
&lt;br /&gt;
; Eine Zahl aus dem Register temp1 ausgeben&lt;br /&gt;
&lt;br /&gt;
lcd_number:&lt;br /&gt;
        push    temp2               ; register sichern,&lt;br /&gt;
                                    ; wird für Zwsichenergebnisse gebraucht     &lt;br /&gt;
        ldi     temp2, &#039;0&#039;         &lt;br /&gt;
lcd_number_10:                &lt;br /&gt;
        subi    temp1, 10           ; abzählen wieviele Zehner in&lt;br /&gt;
        brcs    lcd_number_1        ; der Zahl enthalten sind&lt;br /&gt;
        inc     temp2&lt;br /&gt;
        rjmp    lcd_number_10&lt;br /&gt;
lcd_number_1:&lt;br /&gt;
        push    temp1               ; den Rest sichern (http://www.mikrocontroller.net/topic/172026)&lt;br /&gt;
        mov     temp1,temp2         ; &lt;br /&gt;
        rcall   lcd_data            ; die Zehnerstelle ausgeben&lt;br /&gt;
        pop     temp1               ; den Rest wiederherstellen&lt;br /&gt;
        subi    temp1, -10          ; 10 wieder dazuzählen, da die&lt;br /&gt;
                                    ; vorhergehende Schleife 10 zuviel&lt;br /&gt;
                                    ; abgezogen hat&lt;br /&gt;
                                    ; das Subtrahieren von -10&lt;br /&gt;
                                    ; = Addition von +10 ist ein Trick&lt;br /&gt;
                                    ; da kein addi Befehl existiert&lt;br /&gt;
        ldi     temp2, &#039;0&#039;          ; die übrig gebliebenen Einer&lt;br /&gt;
        add     temp1, temp2        ; noch ausgeben&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
&lt;br /&gt;
        pop     temp2               ; Register wieder herstellen&lt;br /&gt;
        ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der ISR wird nur die Zeit in den Registern neu berechnet, die Ausgabe auf das LCD erfolgt in der Hauptschleife. Das ist notwendig, da die LCD-Ausgabe bisweilen sehr lange dauern kann. Wenn sie länger als ~2/15 Sekunden dauert werden Timerinterrupts &amp;quot;verschluckt&amp;quot; und unsere Uhr geht noch mehr falsch. Dadurch, dass aber die Ausgabe in der Hauptschleife durchgeführt wird, welche jederzeit durch einen Timerinterrupt unterbrochen werden kann, werden keine Timerinterrupts verschluckt. Das ist vor allem wichtig, wenn mit höheren Interruptfrequenzen gearbeitet wird, z.&amp;amp;nbsp;B. 1/100s im Beispiel weiter unten. Auch wenn in diesem einfachen Beispiel die Ausgabe bei weitem nicht 2/15 Sekunden dauert, sollte man sich diesen Programmierstil allgemein angewöhnen. Siehe auch [[Interrupt]].&lt;br /&gt;
&lt;br /&gt;
Eine weitere Besonderheit ist das Register &#039;&#039;&#039;flag&#039;&#039;&#039; (=r19). Dieses Register fungiert als Anzeiger, wie eine Flagge, daher auch der Name. In der ISR wird dieses Register auf 1 gesetzt. Die Hauptschleife, also alles zwischen &#039;&#039;loop&#039;&#039; und &#039;&#039;rjmp loop&#039;&#039;, prüft dieses Flag und nur dann, wenn das Flag auf 1 steht, wird die LCD Ausgabe gemacht und das Flag wieder auf 0 zurückgesetzt. Auf diese Art wird nur dann Rechenzeit für die LCD Ausgabe verbraucht, wenn dies tatsächlich notwendig ist. Die ISR teilt mit dem Flag der Hauptschleife mit, dass eine bestimmte Aufgabe, nämlich der Update der Anzeige gemacht werden muss und die Hauptschleife reagiert darauf bei nächster Gelegenheit, indem sie diese Aufgabe ausführt und setzt das Flag zurück. Solche Flags werden daher auch &#039;&#039;&#039;Job-Flags&#039;&#039;&#039; genannt, weil durch ihr setzten das Abarbeiten eines Jobs (einer Aufgabe) angestoßen wird. Auch hier gilt wieder: Im Grunde würde man in diesem speziellen Beispiel kein Job-Flag benötigen, weil es in der Hauptschleife nur einen einzigen möglichen Job, die Neuausgabe der Uhrzeit, gibt. Sobald aber Programme komplizierter werden und mehrere Jobs möglich sind, sind Job-Flags eine gute Möglichkeit, ein Programm so zu organsieren, dass bestimmte Dinge nur dann gemacht werden, wenn sie notwendig sind.&lt;br /&gt;
&lt;br /&gt;
Im Moment gibt es keine Möglichkeit, die Uhr auf eine bestimmte Uhrzeit einzustellen. Um dies tun zu können, müssten noch zusätzlich Taster an den Mikrocontroller angeschlossen werden, mit deren Hilfe die Sekunden, Minuten und Stunden händisch vergrößert bzw. verkleinert werden können. Studieren Sie mal die Bedienungsanleitung einer käuflichen Digitaluhr und versuchen sie zu beschreiben, wie dieser Stellvorgang bei dieser Uhr vor sich geht. Sicherlich werden Sie daraus eine Idee entwickeln können, wie ein derartiges Stellen mit der hier vorgestellten Digitaluhr funktionieren könnte. Als Zwischenlösung kann man im Programm die Uhr beim Start anstelle von 00:00:00 z.&amp;amp;nbsp;B. auch auf 20:00:00 stellen und exakt mit dem Start der Tagesschau starten. Wobei der Start der Tagesschau verzögert bei uns ankommt, je nach Übertragung können das mehrere Sekunden sein.&lt;br /&gt;
&lt;br /&gt;
== Ganggenauigkeit ==&lt;br /&gt;
&lt;br /&gt;
Wird die Uhr mit einer gekauften Uhr verglichen, so stellt man schnell fest, dass sie ganz schön ungenau geht. Sie geht vor! Woran liegt das? Die Berechnung sieht so aus:&lt;br /&gt;
* Frequenz des Quarzes: 4.0 MHz&lt;br /&gt;
* Vorteiler des Timers: 1024&lt;br /&gt;
* Überlauf alle 256 Timertakte&lt;br /&gt;
&lt;br /&gt;
Daraus errechnet sich, dass in einer Sekunde 4000000 / 1024 / 256 = 15.258789 Overflow Interrupts auftreten. Im Programm wird aber bereits nach 15 Overflows eine Sekunde weitergeschaltet, daher geht die Uhr vor. Rechnen wir etwas:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F_r = (\frac {15}{15,258789}-1) \cdot 100% = -1,69%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So wie bisher läuft die Uhr also rund 1.7 % zu schnell. In einer Minute ist das immerhin etwas mehr als eine Sekunde. Im Grunde ist das ein ähnliches Problem wie mit unserer Jahreslänge. Ein Jahr dauert nicht exakt 365 Tage, sondern in etwa einen viertel Tag länger. Die Lösung, die im Kalender dafür gemacht wurde - der Schalttag -, könnte man fast direkt übernehmen. Nach 3 Stück 15er Overflow Sekunden folgt eine Sekunde für die 16 Overflows ablaufen müssen. Wie sieht die Rechnung bei einem 15, 15, 15, 16 Schema aus? Für 4 Sekunden werden exakt 15.258789 * 4 = 61,035156 Overflow Interrupts benötigt. Mit einem 15, 15, 15, 16 Schema werden in 4 Sekunden genau 61 Overflow Interrupts durchgeführt. Der relative Fehler beträgt dann&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F_r = (\frac {61}{61,035156}-1) \cdot 100% = -0,0575%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit diesem Schema ist der Fehler beträchtlich gesunken. Nur noch 0.06%. Bei dieser Rate muss die Uhr immerhin etwas länger als 0,5 Stunden laufen, bis der Fehler auf eine Sekunde angewachsen ist. Das sind aber immer noch 48 Sekunden pro Tag bzw. 1488 Sekunden (=24,8 Minuten) pro Monat. So schlecht sind nicht mal billige mechanische Uhren!&lt;br /&gt;
&lt;br /&gt;
Jetzt könnte man natürlich noch weiter gehen und immer kompliziertere &amp;quot;Schalt-Overflow&amp;quot;-Schemata austüfteln und damit die Genauigkeit näher an 100% bringen. Aber gibt es noch andere Möglichkeiten?&lt;br /&gt;
&lt;br /&gt;
Im ersten Ansatz wurde ein Vorteiler von 1024 eingesetzt. Was passiert bei einem anderen Vorteiler? Nehmen wir mal einen Vorteiler von 64. Das heißt, es müssen ( 4000000 / 64 ) / 256 = 244.140625 Overflows auflaufen, bis 1 Sekunde vergangen ist. Wenn also 244 Overflows gezählt werden, dann beläuft sich der Fehler auf&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F_r = (\frac {244}{244,140625}-1) \cdot 100% = -0,0576%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nicht schlecht. Nur durch Verändern von 2 Zahlenwerten im Programm (Teilerfaktor und Anzahl der Overflow Interrupts bis zu einer Sekunden) kann die Genauigkeit gegenüber dem ursprünglichen Overflow-Schema beträchtlich gesteigert werden. Aber geht das noch besser? Ja das geht. Allerdings nicht mit dem Overflow Interrupt.&lt;br /&gt;
&lt;br /&gt;
== Der CTC-Modus des Timers ==&lt;br /&gt;
&lt;br /&gt;
Worin liegt denn das eigentliche Problem, mit dem die Uhr zu kämpfen hat? Das Problem liegt darin, dass jedesmal ein kompletter Timerzyklus bis zum Overflow abgewartet werden muss, um darauf zu reagieren. Da aber nur jeweils ganzzahlige Overflowzyklen abgezählt werden können, heißt das auch, dass im ersten Fall nur in Vielfachen von 1024 * 256 = 262144 Takten operiert werden kann, während im letzten Fall immerhin schon eine Granulierung von 64 * 256 = 16384 Takten erreicht wird. Aber offensichtlich ist das nicht genau genug. Bei 4 MHz entsprechen 262144 Takte bereits einem Zeitraum von 65,5ms, während 16384 Takte einem Zeitbedarf von 4,096ms entsprechen. Beide Zahlen teilen aber 1000ms nicht ganzzahlig. Und daraus entsteht der Fehler. Angestrebt wird ein Timer, der seinen &amp;lt;i&amp;gt;Overflow&amp;lt;/i&amp;gt; so erreicht, dass sich ein ganzzahliger Teiler von 1 Sekunde einstellt. Dazu müsste man dem Timer aber vorschreiben können, bei welchem Zählerstand der &amp;lt;i&amp;gt;Overflow&amp;lt;/i&amp;gt; erfolgen soll. Und genau dies ist im &#039;&#039;&#039;CTC&#039;&#039;&#039;-Modus, allerdings nur beim Timer 1, möglich. &#039;&#039;&#039;CTC&#039;&#039;&#039; bedeutet &amp;quot;&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;imer on &#039;&#039;&#039;C&#039;&#039;&#039;ompare match&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Timer 1, ein 16-Bit-Timer, wird mit einem Vorteiler von 1 betrieben. Dadurch wird erreicht, dass der Timer mit höchster Zeitauflösung arbeiten kann. Bei jedem Ticken des Systemtaktes von 4 MHz wird auch der Timer um 1 erhöht. Zusätzlich wird noch das WGM12-Bit bei der Konfiguration gesetzt. Dadurch wird der Timer in den &#039;&#039;&#039;CTC&#039;&#039;&#039;-Modus gesetzt. Dabei wird der Inhalt des Timers hardwaremäßig mit dem Inhalt des &#039;&#039;&#039;OCR1A&#039;&#039;&#039;-Registers verglichen. Stimmen beide überein, so wird der Timer auf 0 zurückgesetzt und im nächsten Taktzyklus ein &#039;&#039;&#039;OCIE1A&#039;&#039;&#039;-Interrupt ausgelöst. Dadurch ist es möglich, exakt die Anzahl an Taktzyklen festzulegen, die von einem Interrupt zum nächsten vergehen sollen. Das Compare Register &#039;&#039;&#039;OCR1A&#039;&#039;&#039; wird mit dem Wert 39999 vorbelegt. Dadurch vergehen exakt 40000 Taktzyklen von einem Compare-Interrupt zum nächsten. &amp;quot;Zufällig&amp;quot; ist dieser Wert so gewählt, dass bei einem Systemtakt von 4 MHz von einem Interrupt zum nächsten genau 1/100 Sekunde vergeht, denn 40000 / 4000000 = 0.01. Bei einem möglichen Umbau der Uhr zu einer Stoppuhr könnte sich das als nützlich erweisen. Im Interrupt wird das Hilfsregister SubCount bis 100 hochgezählt und nach 100 Interrupts kommt wieder die Sekundenweiterschaltung wie oben in Gang.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
.def temp2 = r17&lt;br /&gt;
.def temp3 = r18&lt;br /&gt;
.def Flag  = r19&lt;br /&gt;
 &lt;br /&gt;
.def SubCount = r21&lt;br /&gt;
.def Sekunden = r22&lt;br /&gt;
.def Minuten  = r23&lt;br /&gt;
.def Stunden  = r24&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
           rjmp    main             ; Reset Handler&lt;br /&gt;
.org OC1Aaddr&lt;br /&gt;
           rjmp    timer1_compare   ; Timer Compare Handler&lt;br /&gt;
&lt;br /&gt;
.include &amp;quot;lcd-routines.asm&amp;quot;&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp1&lt;br /&gt;
        ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
        out     SPL, temp1&lt;br /&gt;
&lt;br /&gt;
        ldi temp1, 0xFF    ; Port D = Ausgang&lt;br /&gt;
        out DDRD, temp1     &lt;br /&gt;
&lt;br /&gt;
        rcall   lcd_init&lt;br /&gt;
        rcall   lcd_clear&lt;br /&gt;
 &lt;br /&gt;
                                    ; Vergleichswert &lt;br /&gt;
        ldi     temp1, high( 40000 - 1 )&lt;br /&gt;
        out     OCR1AH, temp1&lt;br /&gt;
        ldi     temp1, low( 40000 - 1 )&lt;br /&gt;
        out     OCR1AL, temp1&lt;br /&gt;
                                    ; CTC Modus einschalten&lt;br /&gt;
                                    ; Vorteiler auf 1&lt;br /&gt;
        ldi     temp1, ( 1 &amp;lt;&amp;lt; WGM12 ) | ( 1 &amp;lt;&amp;lt; CS10 )&lt;br /&gt;
        out     TCCR1B, temp1&lt;br /&gt;
 &lt;br /&gt;
        ldi     temp1, 1 &amp;lt;&amp;lt; OCIE1A  ; OCIE1A: Interrupt bei Timer Compare&lt;br /&gt;
        out     TIMSK, temp1&lt;br /&gt;
 &lt;br /&gt;
        clr     Minuten             ; Die Uhr auf 0 setzen&lt;br /&gt;
        clr     Sekunden&lt;br /&gt;
        clr     Stunden&lt;br /&gt;
        clr     SubCount&lt;br /&gt;
        clr     Flag                ; Flag löschen&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
loop:&lt;br /&gt;
        cpi     flag,0&lt;br /&gt;
        breq    loop                ; Flag im Interrupt gesetzt?&lt;br /&gt;
        ldi     flag,0              ; Flag löschen&lt;br /&gt;
  &lt;br /&gt;
        rcall   lcd_clear           ; das LCD löschen&lt;br /&gt;
        mov     temp1, Stunden      ; und die Stunden ausgeben&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
        ldi     temp1, &#039;:&#039;          ; zwischen Stunden und Minuten einen &#039;:&#039;&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
        mov     temp1, Minuten      ; dann die Minuten ausgeben&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
        ldi     temp1, &#039;:&#039;          ; und noch ein &#039;:&#039;&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
        mov     temp1, Sekunden     ; und die Sekunden&lt;br /&gt;
        rcall   lcd_number&lt;br /&gt;
&lt;br /&gt;
        rjmp    loop&lt;br /&gt;
 &lt;br /&gt;
timer1_compare:                     ; Timer 1 Output Compare Handler&lt;br /&gt;
&lt;br /&gt;
        push    temp1               ; temp 1 sichern&lt;br /&gt;
        in      temp1,sreg          ; SREG sichern&lt;br /&gt;
&lt;br /&gt;
        inc     SubCount            ; Wenn dies nicht der 100. Interrupt&lt;br /&gt;
        cpi     SubCount, 100       ; ist, dann passiert gar nichts&lt;br /&gt;
        brne    end_isr&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     SubCount            ; SubCount rücksetzen&lt;br /&gt;
        inc     Sekunden            ; plus 1 Sekunde&lt;br /&gt;
        cpi     Sekunden, 60        ; sind 60 Sekunden vergangen?&lt;br /&gt;
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon&lt;br /&gt;
                                    ; gemacht werden&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Sekunden            ; Sekunden wieder auf 0 und dafür&lt;br /&gt;
        inc     Minuten             ; plus 1 Minute&lt;br /&gt;
        cpi     Minuten, 60         ; sind 60 Minuten vergangen ?&lt;br /&gt;
        brne    Ausgabe             ; wenn nicht, -&amp;gt; Ausgabe&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Minuten             ; Minuten zurücksetzen und dafür&lt;br /&gt;
        inc     Stunden             ; plus 1 Stunde&lt;br /&gt;
        cpi     Stunden, 24         ; nach 24 Stunden, die Stundenanzeige&lt;br /&gt;
        brne    Ausgabe             ; wieder zurücksetzen&lt;br /&gt;
&lt;br /&gt;
                                    ; Überlauf&lt;br /&gt;
        clr     Stunden             ; Stunden rücksetzen&lt;br /&gt;
&lt;br /&gt;
Ausgabe:&lt;br /&gt;
        ldi     flag,1              ; Flag setzen, LCD updaten&lt;br /&gt;
&lt;br /&gt;
end_isr:&lt;br /&gt;
&lt;br /&gt;
        out     sreg,temp1          ; sreg wieder herstellen&lt;br /&gt;
        pop     temp1&lt;br /&gt;
        reti                        ; das wars. Interrupt ist fertig&lt;br /&gt;
&lt;br /&gt;
; Eine Zahl aus dem Register temp1 ausgeben&lt;br /&gt;
&lt;br /&gt;
lcd_number:&lt;br /&gt;
        push    temp2               ; register sichern,&lt;br /&gt;
                                    ; wird für Zwsichenergebnisse gebraucht     &lt;br /&gt;
        ldi     temp2, &#039;0&#039;         &lt;br /&gt;
lcd_number_10:                &lt;br /&gt;
        subi    temp1, 10           ; abzählen wieviele Zehner in&lt;br /&gt;
        brcs    lcd_number_1        ; der Zahl enthalten sind&lt;br /&gt;
        inc     temp2&lt;br /&gt;
        rjmp    lcd_number_10&lt;br /&gt;
lcd_number_1:&lt;br /&gt;
        push    temp1               ; den Rest sichern (http://www.mikrocontroller.net/topic/172026)&lt;br /&gt;
        mov     temp1,temp2         ; &lt;br /&gt;
        rcall   lcd_data            ; die Zehnerstelle ausgeben&lt;br /&gt;
        pop     temp1               ; den Rest wieder holen&lt;br /&gt;
        subi    temp1, -10          ; 10 wieder dazuzählen, da die&lt;br /&gt;
                                    ; vorhergehende Schleife 10 zuviel&lt;br /&gt;
                                    ; abgezogen hat&lt;br /&gt;
                                    ; das Subtrahieren von -10&lt;br /&gt;
                                    ; = Addition von +10 ist ein Trick&lt;br /&gt;
                                    ; da kein addi Befehl existiert&lt;br /&gt;
        ldi     temp2, &#039;0&#039;          ; die übrig gebliebenen Einer&lt;br /&gt;
        add     temp1, temp2        ; noch ausgeben&lt;br /&gt;
        rcall   lcd_data&lt;br /&gt;
&lt;br /&gt;
        pop     temp2               ; Register wieder herstellen&lt;br /&gt;
        ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Interrupt-Routine werden wieder, genauso wie vorher, die Anzahl der Interrupt-Aufrufe gezählt. Beim 100. Aufruf sind daher 40.000 * 100 = 4.000.000 Takte vergangen und da der Quarz mit 4.000.000 Schwingungen in der Sekunde arbeitet, ist daher eine Sekunde vergangen. Sie wird genauso wie vorher registriert und die Uhr entsprechend hochgezählt. Wird jetzt die Uhr mit einer kommerziellen verglichen, dann fällt nach einiger Zeit auf ... Sie geht immer noch falsch! Was ist jetzt die Ursache? Die Ursache liegt in einem Problem, das nicht direkt behebbar ist. Am Quarz! Auch wenn auf dem Quarz drauf steht, dass er eine Frequenz von 4MHz hat, so stimmt das nicht exakt. Auch Quarze haben Fertigungstoleranzen und verändern ihre Frequenz mit der Temperatur. Typisch liegt die Fertigungstoleranz bei +/- 100ppm = 0,01% (&#039;&#039;&#039;p&#039;&#039;&#039;arts &#039;&#039;&#039;p&#039;&#039;&#039;er &#039;&#039;&#039;m&#039;&#039;&#039;illion, Millionstel Teile), die Temperaturdrift zwischen -40 Grad und 85 Grad liegt je nach Typ in der selben Größenordnung. Das bedeutet, dass die Uhr pro Monat um bis zu 268 Sekunden (~4 1/2 Minuten) falsch gehen kann. Diese Einflüsse auf die Quarzfrequenz sind aber messbar und per Hardware oder Software behebbar. In Uhren kommen normalerweise genauer gefertigte Uhrenquarze zum Einsatz, die vom Uhrmacher auch noch auf die exakte Frequenz abgeglichen werden (mittels Kondensatoren und Frequenzzähler). Ein Profi verwendet einen sehr genauen Frequenzzähler, womit er innerhalb weniger Sekunden die Frequenz sehr genau messen kann. Als Hobbybastler kann man die Uhr eine zeitlang (Tage, Wochen) laufen lassen und die Abweichung feststellen (z.&amp;amp;nbsp;B. exakt 20:00 Uhr zum Start der Tagsschau). Aus dieser Abweichung lässt sich dann errechnen, wie schnell der Quarz wirklich schwingt. Und da dank CTC die Messperiode taktgenau eingestellt werden kann, ist es möglich, diesen Frequenzfehler auszugleichen. Der genaue Vorgang ist in dem Wikiartikel [[AVR - Die genaue Sekunde / RTC]] beschrieben. &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Timer|&lt;br /&gt;
zurücklink=AVR-Tutorial: Timer|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=ADC|&lt;br /&gt;
vorlink=AVR-Tutorial: ADC}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Uhr]]&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;/div&gt;</summary>
		<author><name>2001:A60:13D1:CB01:352D:6309:9D08:7E1F</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=PLL&amp;diff=87650</id>
		<title>PLL</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=PLL&amp;diff=87650"/>
		<updated>2015-03-04T00:37:46Z</updated>

		<summary type="html">&lt;p&gt;2001:A60:13D1:CB01:352D:6309:9D08:7E1F: /* Hardware */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Eine &#039;&#039;&#039;PLL&#039;&#039;&#039; (engl.: phase locked loop) ist ein Regelkreis in Hardware oder Software, der sich auf einen Eingangstakt synchronisieren kann.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
PLLs sind als analoge Schaltkreise aufgebaut, die einen Eingangstakt hoch multiplizieren und wieder herunter dividieren und somit als nichtganzzahliger [[Taktteiler]] fungieren. Ferner wird in der Regel die Phase verschoben, dass ein gewünschtes Verhältnis eingestellt wird. Durch einen sog. feedback loop wird erreicht, dass sich die Phase auf dem hohen Frequenzniveau stabil verhält und dem [[Jitter]] des Eingangstaktes nur langsam folgt. Zur Stabilisierung des hochfrequenten Zwischentaktes werden rückgekoppelte Filter benutzt, die genau in dem Frequenzbereich stabil sind. Bei FPGAs sind diese Filter oft parametier- und umschaltbar.&lt;br /&gt;
&lt;br /&gt;
Die Einstellung erfolgt voll analog, also nicht zeitdiskret.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
Solche Regelkreise lassen sich in SW nachbilden, wenn sich ein [[Mikrocontroller]] auf einen eingehenden seriellen Takt einstellt bzw ein [[FPGA]] einen Eingangstakt ausmisst und sich in die Mitte stellt, um parallele Daten zu verarbeiten. (siehe [[SERDES]], [[GTP]]).&lt;br /&gt;
&lt;br /&gt;
Die Verarbeitung erfolgt dann voll digital, also diskret mit dem Systemtakt des FPGAs / des Controllers.&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
In dieser Tabelle werden die durch ganzzahlige Teiler und Multiplizierer erreichbaren Frequenzverhältnisse aufgelistet:&lt;br /&gt;
[[Settings for Multiplier and Divider]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;br /&gt;
[[Category:Grundlagen]]&lt;/div&gt;</summary>
		<author><name>2001:A60:13D1:CB01:352D:6309:9D08:7E1F</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87649</id>
		<title>AVR-Tutorial: Timer</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87649"/>
		<updated>2015-03-04T00:31:17Z</updated>

		<summary type="html">&lt;p&gt;2001:A60:13D1:CB01:352D:6309:9D08:7E1F: /* TIMS - Timer/Counter Interrupt Mask Register */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timer sind eines der Hauptarbeitspferde in unserem Mikrocontroller. Mit ihrer Hilfe ist es möglich, in regelmäßigen Zeitabständen Aktionen zu veranlassen. Aber Timer können noch mehr!&lt;br /&gt;
* Timer können mit einem externen Pin hochgezählt werden&lt;br /&gt;
* Es gibt Möglichkeiten, bei bestimmten Zählerständen einen Interrupt auslösen zu lassen&lt;br /&gt;
* Timer können aber auch völlig selbstständig Signale an einem Ausgabepin erzeugen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Aber der Reihe nach und kurz zur Erinnerung: Die Beispiele passen zu einem ATmega8 und ggf. einer Reihe anderer AVR, können bei einigen Typen aber abweichen. &lt;br /&gt;
&lt;br /&gt;
==Was ist ein Timer?==&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist im Grunde nichts anderes als ein bestimmtes Register im Mikrocontroller, das hardwaregesteuert fortlaufend um 1 erhöht (oder verringert) wird (statt &amp;lt;i&amp;gt;um 1 erhöhen&amp;lt;/i&amp;gt; sagt man auch &#039;&#039;&#039;inkrementieren&#039;&#039;&#039;, und das Gegenstück, &#039;&#039;&#039;dekrementieren&#039;&#039;&#039;, bedeutet &amp;lt;i&amp;gt;um 1 verringern&amp;lt;/i&amp;gt;). Anstatt also Befehle im Programm vorzusehen, die regelmäßig ausgeführt werden und ein Register inkrementieren, erledigt dies der Mikrocontroller ganz von alleine. Dazu ist es möglich, den Timer mit dem Systemtakt zu verbinden und so die Genauigkeit des Quarzes auszunutzen, um ein Register regelmäßig und vor allen Dingen unabhängig vom restlichen Programmfluss (!) hochzählen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Davon alleine hätte man aber noch keinen großen Gewinn. Nützlich wird das Ganze erst dann, wenn man bei bestimmten Zählerständen eine Aktion ausführen lassen kann. Einer der &#039;bestimmten Zählerstände&#039; ist zum Beispiel der &#039;&#039;&#039;Overflow&#039;&#039;&#039;. Das Zählregister eines Timers kann natürlich nicht beliebig lange inkrementiert werden – z. B. ist der höchste Zählerstand, den ein 8-Bit-Timer erreichen kann, 2&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; – 1 = 255. Beim nächsten Inkrementierschritt tritt ein Überlauf (engl. Overflow) auf, der den Timerstand wieder zu 0 werden lässt. Und hier liegt der springende Punkt. Wir können uns nämlich an diesen Overflow &amp;quot;anhängen&amp;quot; und den Controller so konfigurieren, dass beim Auftreten des Timer-Overflows ein Interrupt ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die kann auch alles nochmal im Datenblatt von Atmel zu einigen ATMega Datenblättern nachgelesen werden: http://www.atmel.com/Images/doc8161.pdf&lt;br /&gt;
&lt;br /&gt;
==Der Vorteiler (Prescaler)==&lt;br /&gt;
&lt;br /&gt;
Wenn also der Quarzoszillator mit 4 MHz schwingt, dann würde auch der Timer 4 Millionen mal in der Sekunde erhöht werden. Da der Timer jedes Mal von 0 bis 255 zählt, bevor ein Overflow auftritt, heißt das auch, dass in einer Sekunde 4000000 / 256 = 15625 Overflows vorkommen. Ganz schön schnell! Nur: Oft ist das nicht sinnvoll. Um diese Raten zu verzögern, gibt es den Vorteiler, oder auf Englisch, Prescaler. Er kann z.B. auf die Werte 1, 8, 64, 256 oder 1024 eingestellt werden, je nach Timer (Bitte Datenblatt konsultieren!). Seine Aufgabe ist es, den Systemtakt um den angegebenen Faktor zu teilen. Steht der Vorteiler also auf 1024, so wird nur bei jedem 1024-ten Impuls vom Systemtakt das Timerregister um 1 erhöht. Entsprechend weniger häufig kommen dann natürlich die Overflows. Der Systemtakt sei wieder 4000000. Dann wird der Timer in 1 Sekunde 4000000 / 1024 = 3906.25 mal erhöht. Da der Timer wieder jedesmal bis 255 zählen muss bis ein Overflow auftritt, bedeutet dies, dass in 1 Sekunde 3906.25 / 256 = 15.25 Overflows auftreten.&lt;br /&gt;
&lt;br /&gt;
Systemtakt: 4Mhz&lt;br /&gt;
&lt;br /&gt;
  Vorteiler    Overflows/Sekunde      Zeit zwischen&lt;br /&gt;
                                      2 Overflows [s]&lt;br /&gt;
&lt;br /&gt;
      1            15625                0.000064&lt;br /&gt;
      8             1953.125            0.000512&lt;br /&gt;
     64              244.1406           0.004096&lt;br /&gt;
    256               61.0351           0.016384&lt;br /&gt;
   1024               15.2587           0.065536&lt;br /&gt;
&lt;br /&gt;
Die Zeit (in Sekunden) zwischen 2 Overflows lässt sich sehr leicht berechnen:&lt;br /&gt;
&amp;lt;math&amp;gt;t=\frac{2^\text{Bit des Timers} \cdot \text{Vorteiler}}{\text{Systemtakt in Hz}}&amp;lt;/math&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
==Erste Tests==&lt;br /&gt;
&lt;br /&gt;
Ein Programm, das einen Timer Overflow in Aktion zeigt, könnte z.&amp;amp;nbsp;B. so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp = r16&lt;br /&gt;
.def leds = r17&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
        rjmp    main                  ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
        rjmp    timer0_overflow       ; Timer Overflow Handler&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ; Stackpointer initialisieren&lt;br /&gt;
        ldi     temp, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp&lt;br /&gt;
        ldi     temp, LOW(RAMEND)     &lt;br /&gt;
        out     SPL, temp&lt;br /&gt;
	&lt;br /&gt;
        ldi     temp, 0xFF            ; Port B auf Ausgang&lt;br /&gt;
        out     DDRB, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     leds, 0xFF&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;CS00)       ; CS00 setzen: Teiler 1&lt;br /&gt;
        out     TCCR0, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;TOIE0)      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
&lt;br /&gt;
loop:   rjmp    loop&lt;br /&gt;
&lt;br /&gt;
timer0_overflow:                      ; Timer 0 Overflow Handler&lt;br /&gt;
        out     PORTB, leds&lt;br /&gt;
        com     leds&lt;br /&gt;
        reti&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Programm beginnt mit der [[AVR-Tutorial:_Interrupts|Interrupt-Vektoren-Tabelle]]. Dort ist an der Adresse &amp;lt;i&amp;gt;OVF0Addr&amp;lt;/i&amp;gt; ein Sprung zur Marke &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; eingetragen. Wenn also ein Overflow Interrupt vom Timer 0 auftritt, so wird dieser Interrupt durch den &#039;&#039;&#039;rjmp&#039;&#039;&#039; weitergeleitet an die Stelle &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm beginnt ganz normal mit der Belegung des Stackpointers. Danach wird der Port B auf Ausgang geschaltet, wir wollen hier wieder die LED anschliessen.&lt;br /&gt;
&lt;br /&gt;
Durch Beschreiben von TCCR0 mit dem Bitmuster 0b00000001, hier ausgedrückt durch (1&amp;lt;&amp;lt;CS00), wird der Vorteiler auf 1 gesetzt. Für die ersten Versuche empfiehlt es sich, das Programm mit dem AVR-Studio zunächst zu simulieren. Würden wir einen größeren Vorteiler benutzen, so müsste man ziemlich oft mittels F11 einen simulierten Schritt ausführen, um eine Änderung im Timerregister zu erreichen.&lt;br /&gt;
&lt;br /&gt;
Die nächsten Anweisungen setzen im TIMSK Register das TOIE0 Bit. Sinn der Sache ist es, dem Timer zu erlauben, bei Erreichen eines Overflow einen Interrupt auszulösen.&lt;br /&gt;
&lt;br /&gt;
Zum Schluss noch die Interrupts generell mittels &#039;&#039;&#039;sei&#039;&#039;&#039; freigeben. Dieser Schritt ist obligatorisch. Im Mikrocontroller können viele Quellen einen Interrupt auslösen. Daraus folgt: Für jede mögliche Quelle muss festgelegt werden, ob sie einen Interrupt erzeugen darf oder nicht. Die Oberhoheit hat aber das globale Interrupt Flag. Mit ihm können alle Interrupts, egal von welcher Quelle sie kommen, unterdrückt werden.&lt;br /&gt;
&lt;br /&gt;
Damit ist die Initialisierung beendet und das Hauptprogramm kann sich schlafen legen. Die &#039;&#039;&#039;loop: rjmp loop&#039;&#039;&#039; Schleife macht genau dieses.&lt;br /&gt;
&lt;br /&gt;
Tritt nun ein Overflow am Timer auf, so wird über den Umweg über die Interrupt Vektor Tabelle der Programmteil &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; angesprungen. Dieser gibt einfach nur den Inhalt des Registers leds am Port B aus. Danach wird das leds Register mit einer &#039;&#039;&#039;com&#039;&#039;&#039; Operation negiert, so dass aus allen 0 Bits eine 1 wird und umgekehrt. Die Overflow Behandlung ist damit beendet und mittels &#039;&#039;&#039;reti&#039;&#039;&#039; wird der Interrupt Handler wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
==Simulation im AVR-Studio==&lt;br /&gt;
&lt;br /&gt;
Es lohnt sich, den ganzen Vorgang im AVR-Studio simulieren zu lassen. Dazu am besten in der linken I/O View Ansicht die Einträge für PORTB und TIMER_COUNTER_0 öffnen. Wird mittels F11 durch das Programm gegangen, so sieht man, dass ab dem Moment, ab dem der Vorteiler auf 1 gesetzt wird, der Timer 0 im TCNT0 Register zu zählen anfängt. Mit jedem Druck auf F11 erhöht sich der Zählerstand. Irgendwann ist dann die Endlosschleife loop erreicht. Drücken Sie weiterhin F11 und beobachten sie, wie TCNT0 immer höher zählt, bis der Overflow erreicht wird. In dem Moment, in dem der Overflow erreicht wird, wird der Interrupt ausgelöst (hierfür muss für das Debuggen im AVR-Studio &amp;quot;Mask interrupts while stepping&amp;quot; deaktiviert sein, zu finden in Tools -&amp;gt; Options). Mit dem nächsten F11 landen sie in der Interrupt Vektor Tabelle und von dort geht es weiter zu timer_0_overflow. Weitere Tastendrücke von F11 erledigen dann die Ausgabe auf den Port B, das Invertieren des Registers r17 und der Interrupt ist damit behandelt. Nach dem &#039;&#039;&#039;reti&#039;&#039;&#039; macht der Microcontroller genau an der Stelle weiter, an der er vom Interrupt unterbrochen wurde. Und der Timer 0 hat in der Zwischenzeit weitergezählt! Nach exakt weiteren 256 Schritten, vom Auftreten des ersten Overflows an gerechnet, wird der nächste Overflow ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==Wie schnell schaltet denn jetzt der Port?==&lt;br /&gt;
&lt;br /&gt;
Eine berechtigte Frage. Dazu müssen wir etwas rechnen. Keine Angst, es ist nicht schwer, und wer das Prinzip bisher verstanden hat, der sollte keine Schwierigkeiten haben, die Berechnung nachzuvollziehen.&lt;br /&gt;
&lt;br /&gt;
Der Quarzoszillator schwingt mit 4 MHz. Das heißt, in 1 Sekunde werden 4000000 Taktzyklen generiert. Durch die Wahl des Vorteilers von 1 bedeutet das auch, dass der Timer 4000000 mal in der Sekunde erhöht wird. Von einem Overflow zum nächsten muss der Timer 256 Zählvorgänge ausführen. Also werden in 1 Sekunde 4000000 / 256 = 15625 Overflows generiert. Bei jedem Overflow schalten wir die LEDs jeweils in den anderen Zustand. D.h die LEDs blinken mit einer Frequenz von 7812.5 Hz. Das ist zuviel als dass wir es noch sehen könnten.&lt;br /&gt;
&lt;br /&gt;
Was können wir also tun, um diese Blinkfrequenz zu verringern? Im Moment ist unsere einzige Einflussgröße der Vorteiler. Wie sieht die Rechnung aus, wenn wir einen Vorteiler von 1024 wählen?&lt;br /&gt;
&lt;br /&gt;
Wiederrum: Der Systemtakt sei 4 Mhz. Durch den Vorteiler von 1024 werden daraus 4000000 / 1024 = 3906.25 Pulse pro Sekunde für den Timer. Der zählt wiederum 256 Zustände von einem Overflow zum nächsten. 3906.25 / 256 = 15.2587. Und wiederum: Im Overflow werden die LEDs ja abwechselnd ein und ausgeschaltet, also dividieren wir noch durch 2: 15.2587 / 2 = 7.629. Also knapp 7 Hz. Diese Frequenz müsste man schon mit freiem Auge sehen. Die LEDs werden ziemlich schnell vor sich hin blinken.&lt;br /&gt;
&lt;br /&gt;
Reicht diese Verzögerung noch immer nicht, dann haben wir 2 Möglichkeiten:&lt;br /&gt;
* Entweder wir benutzen einen anderen Timer. Timer 1 beispielsweise ist ein 16 Bit Timer. Der Timer zählt also nicht von 0 bis 255 sondern von 0 bis 65535. Bei entsprechender Umarbeitung des Programms und einem Vorteiler von 1024 bedeutet das, dass die LEDs einen Ein/Aus Zyklus in 33 Sekunden absolvieren.&lt;br /&gt;
* Oder wir schalten die LEDs nicht bei jedem Timer Overflow um. Man könnte zum Beispiel in einem Register bis 7 zählen und nur dann, wenn dieses Register 7 erreicht hat, wird&lt;br /&gt;
** das Register wieder auf 0 gesetzt und&lt;br /&gt;
** die LEDs umgeschaltet.&lt;br /&gt;
&lt;br /&gt;
==Timer 0==&lt;br /&gt;
&lt;br /&gt;
Timer 0 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
&lt;br /&gt;
===TCCR0===&lt;br /&gt;
====TCCR - Timer/Counter Control Register====&lt;br /&gt;
{{Byte |TCCR0 |      |      |      |      |      | CS02 | CS01 | CS00 }}&lt;br /&gt;
&lt;br /&gt;
====CS02/CS00 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS02 || CS01 || CS00 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===TIMSK===&lt;br /&gt;
====TIMSK - Timer/Counter Interrupt Mask Register====&lt;br /&gt;
&lt;br /&gt;
{{Byte|TIMSK|      |      |      |      |      |      | OCIE0 | TOIE0 }}&lt;br /&gt;
&lt;br /&gt;
====TOIE0 - Timer 0 Overflow Interrupt Enable====&lt;br /&gt;
Ist dieses Bit gesetzt, so wird beim Auftreten eines Overflows am Timer ein Interrupt ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Anstatt der Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
ist es besser, die Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 1 &amp;lt;&amp;lt; TOIE0&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
zu wählen, da hier unmittelbar aus dem Ladekommando hervorgeht, welche Bedeutung das gesetzte Bit hat. Die vorher inkludierte m8def.inc definiert dazu alles Notwendige.&lt;br /&gt;
&lt;br /&gt;
==Timer 1==&lt;br /&gt;
&lt;br /&gt;
Timer 1 ist ein 16 Bit Timer&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Input Capture&lt;br /&gt;
* 2 Compare Einheiten&lt;br /&gt;
* div. PWM Modi&lt;br /&gt;
&lt;br /&gt;
===TCCR1B===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1B| ICNC1| ICES1|      | WGM13| WGM12| CS12 | CS11 | CS10 }}&lt;br /&gt;
&lt;br /&gt;
====CS12/CS10 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS12 || CS11 || CS10 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====ICES1 - Input Capture Edge Select====&lt;br /&gt;
ICES1 = 0 , falling edge&lt;br /&gt;
ICES1 = 1 , rising edge&lt;br /&gt;
&lt;br /&gt;
====ICNC1 - Input Capture Noise Canceler====&lt;br /&gt;
&lt;br /&gt;
===TCCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1A|COM1A1|COM1A0|COM1B1|COM1B0|FOC1A |FOC1B |WGM11 |WGM10 }}&lt;br /&gt;
&lt;br /&gt;
===OCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===OCR1B===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===ICR1===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK1===&lt;br /&gt;
{{Byte|TIMSK|      |      |TICIE1|OCIE1A|OCIE1B|TOIE1 |      |}}&lt;br /&gt;
&lt;br /&gt;
====TICIE1 - Timer 1 Input Capture Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1A - Timer 1 Output Compare A Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1B - Timer 1 Output Compare B Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====TOIE1 - Timer 1 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Timer 2==&lt;br /&gt;
Timer 2 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Compare Match Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Phasen korrekte PWM&lt;br /&gt;
&lt;br /&gt;
===TCCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR2| FOC2 | WGM20| COM21| COM20| WGM21| CS22 | CS21 | CS20 }}&lt;br /&gt;
&lt;br /&gt;
====WGM21 - Waveform Generator Mode====&lt;br /&gt;
&lt;br /&gt;
Ist diese Option Aktiviert dann wird das Zählregister des Timers (TCNT2) wieder auf 0 gesetzt,&lt;br /&gt;
sobal das Register as Output Compare Register (OCR2) und TCNT2 übereinstimmen.&lt;br /&gt;
Zu beachten ist dabei das wenn das Register kleiner als 255 gestellt ist, wird&lt;br /&gt;
der Timer nicht mehr überschritten und der Interrupt für den Overflow (TIMER2_OVF_vect) nicht mehr ausgelöst.&lt;br /&gt;
Stattdessen gibt es den Interrupt für Compare Match (TIMER2_COMP_vect)&lt;br /&gt;
Die Frequenz für die Interruptauslösung lässt sich dann wie folgt berechnen:&lt;br /&gt;
ISR_Freq = F_CPU : ( Prescaler * ORC2 )&lt;br /&gt;
&lt;br /&gt;
====CS22/CS20 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS22 || CS21 || CS20 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 128&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===OCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK2===&lt;br /&gt;
{{Byte|TIMSK| OCIE2| TOIE2|      |      |      |      |      |      }}&lt;br /&gt;
&lt;br /&gt;
====OCIE2 - Timer 2 Output Compare Interrupt Enable====&lt;br /&gt;
====TOIE2   Timer 2 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Was geht noch mit einem Timer?==&lt;br /&gt;
&lt;br /&gt;
Timer sind sehr universelle Microcontroller Bestandteile. Für weitergehende Studien ist es daher unerlässlich, das entsprechende Datenblatt des Microcontrollers zu studieren. Oft ist es z.&amp;amp;nbsp;B. möglich, dass der Timer bei erreichen von bestimmten Zählerständen einen Ausgabepin von sich aus ein-/aus-/umschaltet. Er erledigt dann das, was wir oben noch mit einem Interrupt gemacht haben, eigenständig komplett in Hardware. Bei einigen Timern ist es möglich, damit eine [[PWM]] (Pulsweiten-Modulation) aufzubauen.&lt;br /&gt;
&lt;br /&gt;
Ein paar der Timermodule lassen sich auch als Counter verwenden. Damit kann man z.&amp;amp;nbsp;B. die Anzahl externer Ereignisse wie Schaltvorgänge eines Inkrementalgebers bestimmen.&lt;br /&gt;
&lt;br /&gt;
Andere bieten die Möglichkeit, über einen externen Uhrenquarz getaktet zu werden (Anwendung z.&amp;amp;nbsp;B. eine &amp;quot;Echtzeituhr&amp;quot; oder als &amp;quot;Weckfunktion&amp;quot; aus einem Standby/Powerdownmodus).&lt;br /&gt;
&lt;br /&gt;
Durch geschickte Umprogrammierung in Echtzeit, lässt sich mit einem Timer eine [[PLL]] aufbauen, die sich fortwährend auf einen Eingangstakt synchronisiert. Damit wird vermieden, dass der Controller ein Signal ständig abpollen muss, sondern das Signale wird per Timer-Interrupt verarbeitet. Massgeblich ist die Messung der aktuellen- und Schätzung der kommenden Flanke mithilfe eines einstellbaren [[Taktteiler]]-verhältnisses.&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.uni-koblenz.de/~physik/informatik/MCU/Timer.pdf Timer/Counter und PWM beim ATMega16 Mikrocontroller] Proseminar von Marcel Jakobs, September 2006 (PDF)&lt;br /&gt;
* [http://frank.circleofcurrent.com/cache/avrtimercalc.htm AVR Timer Calculator]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Speicher|&lt;br /&gt;
zurücklink=AVR-Tutorial: Speicher|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Uhr|&lt;br /&gt;
vorlink=AVR-Tutorial: Uhr}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Timer]]&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;/div&gt;</summary>
		<author><name>2001:A60:13D1:CB01:352D:6309:9D08:7E1F</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87648</id>
		<title>AVR-Tutorial: Timer</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87648"/>
		<updated>2015-03-04T00:30:43Z</updated>

		<summary type="html">&lt;p&gt;2001:A60:13D1:CB01:352D:6309:9D08:7E1F: /* TIMSK - Timer/Counter Interrupt Mask Register */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timer sind eines der Hauptarbeitspferde in unserem Mikrocontroller. Mit ihrer Hilfe ist es möglich, in regelmäßigen Zeitabständen Aktionen zu veranlassen. Aber Timer können noch mehr!&lt;br /&gt;
* Timer können mit einem externen Pin hochgezählt werden&lt;br /&gt;
* Es gibt Möglichkeiten, bei bestimmten Zählerständen einen Interrupt auslösen zu lassen&lt;br /&gt;
* Timer können aber auch völlig selbstständig Signale an einem Ausgabepin erzeugen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Aber der Reihe nach und kurz zur Erinnerung: Die Beispiele passen zu einem ATmega8 und ggf. einer Reihe anderer AVR, können bei einigen Typen aber abweichen. &lt;br /&gt;
&lt;br /&gt;
==Was ist ein Timer?==&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist im Grunde nichts anderes als ein bestimmtes Register im Mikrocontroller, das hardwaregesteuert fortlaufend um 1 erhöht (oder verringert) wird (statt &amp;lt;i&amp;gt;um 1 erhöhen&amp;lt;/i&amp;gt; sagt man auch &#039;&#039;&#039;inkrementieren&#039;&#039;&#039;, und das Gegenstück, &#039;&#039;&#039;dekrementieren&#039;&#039;&#039;, bedeutet &amp;lt;i&amp;gt;um 1 verringern&amp;lt;/i&amp;gt;). Anstatt also Befehle im Programm vorzusehen, die regelmäßig ausgeführt werden und ein Register inkrementieren, erledigt dies der Mikrocontroller ganz von alleine. Dazu ist es möglich, den Timer mit dem Systemtakt zu verbinden und so die Genauigkeit des Quarzes auszunutzen, um ein Register regelmäßig und vor allen Dingen unabhängig vom restlichen Programmfluss (!) hochzählen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Davon alleine hätte man aber noch keinen großen Gewinn. Nützlich wird das Ganze erst dann, wenn man bei bestimmten Zählerständen eine Aktion ausführen lassen kann. Einer der &#039;bestimmten Zählerstände&#039; ist zum Beispiel der &#039;&#039;&#039;Overflow&#039;&#039;&#039;. Das Zählregister eines Timers kann natürlich nicht beliebig lange inkrementiert werden – z. B. ist der höchste Zählerstand, den ein 8-Bit-Timer erreichen kann, 2&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; – 1 = 255. Beim nächsten Inkrementierschritt tritt ein Überlauf (engl. Overflow) auf, der den Timerstand wieder zu 0 werden lässt. Und hier liegt der springende Punkt. Wir können uns nämlich an diesen Overflow &amp;quot;anhängen&amp;quot; und den Controller so konfigurieren, dass beim Auftreten des Timer-Overflows ein Interrupt ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die kann auch alles nochmal im Datenblatt von Atmel zu einigen ATMega Datenblättern nachgelesen werden: http://www.atmel.com/Images/doc8161.pdf&lt;br /&gt;
&lt;br /&gt;
==Der Vorteiler (Prescaler)==&lt;br /&gt;
&lt;br /&gt;
Wenn also der Quarzoszillator mit 4 MHz schwingt, dann würde auch der Timer 4 Millionen mal in der Sekunde erhöht werden. Da der Timer jedes Mal von 0 bis 255 zählt, bevor ein Overflow auftritt, heißt das auch, dass in einer Sekunde 4000000 / 256 = 15625 Overflows vorkommen. Ganz schön schnell! Nur: Oft ist das nicht sinnvoll. Um diese Raten zu verzögern, gibt es den Vorteiler, oder auf Englisch, Prescaler. Er kann z.B. auf die Werte 1, 8, 64, 256 oder 1024 eingestellt werden, je nach Timer (Bitte Datenblatt konsultieren!). Seine Aufgabe ist es, den Systemtakt um den angegebenen Faktor zu teilen. Steht der Vorteiler also auf 1024, so wird nur bei jedem 1024-ten Impuls vom Systemtakt das Timerregister um 1 erhöht. Entsprechend weniger häufig kommen dann natürlich die Overflows. Der Systemtakt sei wieder 4000000. Dann wird der Timer in 1 Sekunde 4000000 / 1024 = 3906.25 mal erhöht. Da der Timer wieder jedesmal bis 255 zählen muss bis ein Overflow auftritt, bedeutet dies, dass in 1 Sekunde 3906.25 / 256 = 15.25 Overflows auftreten.&lt;br /&gt;
&lt;br /&gt;
Systemtakt: 4Mhz&lt;br /&gt;
&lt;br /&gt;
  Vorteiler    Overflows/Sekunde      Zeit zwischen&lt;br /&gt;
                                      2 Overflows [s]&lt;br /&gt;
&lt;br /&gt;
      1            15625                0.000064&lt;br /&gt;
      8             1953.125            0.000512&lt;br /&gt;
     64              244.1406           0.004096&lt;br /&gt;
    256               61.0351           0.016384&lt;br /&gt;
   1024               15.2587           0.065536&lt;br /&gt;
&lt;br /&gt;
Die Zeit (in Sekunden) zwischen 2 Overflows lässt sich sehr leicht berechnen:&lt;br /&gt;
&amp;lt;math&amp;gt;t=\frac{2^\text{Bit des Timers} \cdot \text{Vorteiler}}{\text{Systemtakt in Hz}}&amp;lt;/math&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
==Erste Tests==&lt;br /&gt;
&lt;br /&gt;
Ein Programm, das einen Timer Overflow in Aktion zeigt, könnte z.&amp;amp;nbsp;B. so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp = r16&lt;br /&gt;
.def leds = r17&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
        rjmp    main                  ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
        rjmp    timer0_overflow       ; Timer Overflow Handler&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ; Stackpointer initialisieren&lt;br /&gt;
        ldi     temp, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp&lt;br /&gt;
        ldi     temp, LOW(RAMEND)     &lt;br /&gt;
        out     SPL, temp&lt;br /&gt;
	&lt;br /&gt;
        ldi     temp, 0xFF            ; Port B auf Ausgang&lt;br /&gt;
        out     DDRB, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     leds, 0xFF&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;CS00)       ; CS00 setzen: Teiler 1&lt;br /&gt;
        out     TCCR0, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;TOIE0)      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
&lt;br /&gt;
loop:   rjmp    loop&lt;br /&gt;
&lt;br /&gt;
timer0_overflow:                      ; Timer 0 Overflow Handler&lt;br /&gt;
        out     PORTB, leds&lt;br /&gt;
        com     leds&lt;br /&gt;
        reti&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Programm beginnt mit der [[AVR-Tutorial:_Interrupts|Interrupt-Vektoren-Tabelle]]. Dort ist an der Adresse &amp;lt;i&amp;gt;OVF0Addr&amp;lt;/i&amp;gt; ein Sprung zur Marke &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; eingetragen. Wenn also ein Overflow Interrupt vom Timer 0 auftritt, so wird dieser Interrupt durch den &#039;&#039;&#039;rjmp&#039;&#039;&#039; weitergeleitet an die Stelle &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm beginnt ganz normal mit der Belegung des Stackpointers. Danach wird der Port B auf Ausgang geschaltet, wir wollen hier wieder die LED anschliessen.&lt;br /&gt;
&lt;br /&gt;
Durch Beschreiben von TCCR0 mit dem Bitmuster 0b00000001, hier ausgedrückt durch (1&amp;lt;&amp;lt;CS00), wird der Vorteiler auf 1 gesetzt. Für die ersten Versuche empfiehlt es sich, das Programm mit dem AVR-Studio zunächst zu simulieren. Würden wir einen größeren Vorteiler benutzen, so müsste man ziemlich oft mittels F11 einen simulierten Schritt ausführen, um eine Änderung im Timerregister zu erreichen.&lt;br /&gt;
&lt;br /&gt;
Die nächsten Anweisungen setzen im TIMSK Register das TOIE0 Bit. Sinn der Sache ist es, dem Timer zu erlauben, bei Erreichen eines Overflow einen Interrupt auszulösen.&lt;br /&gt;
&lt;br /&gt;
Zum Schluss noch die Interrupts generell mittels &#039;&#039;&#039;sei&#039;&#039;&#039; freigeben. Dieser Schritt ist obligatorisch. Im Mikrocontroller können viele Quellen einen Interrupt auslösen. Daraus folgt: Für jede mögliche Quelle muss festgelegt werden, ob sie einen Interrupt erzeugen darf oder nicht. Die Oberhoheit hat aber das globale Interrupt Flag. Mit ihm können alle Interrupts, egal von welcher Quelle sie kommen, unterdrückt werden.&lt;br /&gt;
&lt;br /&gt;
Damit ist die Initialisierung beendet und das Hauptprogramm kann sich schlafen legen. Die &#039;&#039;&#039;loop: rjmp loop&#039;&#039;&#039; Schleife macht genau dieses.&lt;br /&gt;
&lt;br /&gt;
Tritt nun ein Overflow am Timer auf, so wird über den Umweg über die Interrupt Vektor Tabelle der Programmteil &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; angesprungen. Dieser gibt einfach nur den Inhalt des Registers leds am Port B aus. Danach wird das leds Register mit einer &#039;&#039;&#039;com&#039;&#039;&#039; Operation negiert, so dass aus allen 0 Bits eine 1 wird und umgekehrt. Die Overflow Behandlung ist damit beendet und mittels &#039;&#039;&#039;reti&#039;&#039;&#039; wird der Interrupt Handler wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
==Simulation im AVR-Studio==&lt;br /&gt;
&lt;br /&gt;
Es lohnt sich, den ganzen Vorgang im AVR-Studio simulieren zu lassen. Dazu am besten in der linken I/O View Ansicht die Einträge für PORTB und TIMER_COUNTER_0 öffnen. Wird mittels F11 durch das Programm gegangen, so sieht man, dass ab dem Moment, ab dem der Vorteiler auf 1 gesetzt wird, der Timer 0 im TCNT0 Register zu zählen anfängt. Mit jedem Druck auf F11 erhöht sich der Zählerstand. Irgendwann ist dann die Endlosschleife loop erreicht. Drücken Sie weiterhin F11 und beobachten sie, wie TCNT0 immer höher zählt, bis der Overflow erreicht wird. In dem Moment, in dem der Overflow erreicht wird, wird der Interrupt ausgelöst (hierfür muss für das Debuggen im AVR-Studio &amp;quot;Mask interrupts while stepping&amp;quot; deaktiviert sein, zu finden in Tools -&amp;gt; Options). Mit dem nächsten F11 landen sie in der Interrupt Vektor Tabelle und von dort geht es weiter zu timer_0_overflow. Weitere Tastendrücke von F11 erledigen dann die Ausgabe auf den Port B, das Invertieren des Registers r17 und der Interrupt ist damit behandelt. Nach dem &#039;&#039;&#039;reti&#039;&#039;&#039; macht der Microcontroller genau an der Stelle weiter, an der er vom Interrupt unterbrochen wurde. Und der Timer 0 hat in der Zwischenzeit weitergezählt! Nach exakt weiteren 256 Schritten, vom Auftreten des ersten Overflows an gerechnet, wird der nächste Overflow ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==Wie schnell schaltet denn jetzt der Port?==&lt;br /&gt;
&lt;br /&gt;
Eine berechtigte Frage. Dazu müssen wir etwas rechnen. Keine Angst, es ist nicht schwer, und wer das Prinzip bisher verstanden hat, der sollte keine Schwierigkeiten haben, die Berechnung nachzuvollziehen.&lt;br /&gt;
&lt;br /&gt;
Der Quarzoszillator schwingt mit 4 MHz. Das heißt, in 1 Sekunde werden 4000000 Taktzyklen generiert. Durch die Wahl des Vorteilers von 1 bedeutet das auch, dass der Timer 4000000 mal in der Sekunde erhöht wird. Von einem Overflow zum nächsten muss der Timer 256 Zählvorgänge ausführen. Also werden in 1 Sekunde 4000000 / 256 = 15625 Overflows generiert. Bei jedem Overflow schalten wir die LEDs jeweils in den anderen Zustand. D.h die LEDs blinken mit einer Frequenz von 7812.5 Hz. Das ist zuviel als dass wir es noch sehen könnten.&lt;br /&gt;
&lt;br /&gt;
Was können wir also tun, um diese Blinkfrequenz zu verringern? Im Moment ist unsere einzige Einflussgröße der Vorteiler. Wie sieht die Rechnung aus, wenn wir einen Vorteiler von 1024 wählen?&lt;br /&gt;
&lt;br /&gt;
Wiederrum: Der Systemtakt sei 4 Mhz. Durch den Vorteiler von 1024 werden daraus 4000000 / 1024 = 3906.25 Pulse pro Sekunde für den Timer. Der zählt wiederum 256 Zustände von einem Overflow zum nächsten. 3906.25 / 256 = 15.2587. Und wiederum: Im Overflow werden die LEDs ja abwechselnd ein und ausgeschaltet, also dividieren wir noch durch 2: 15.2587 / 2 = 7.629. Also knapp 7 Hz. Diese Frequenz müsste man schon mit freiem Auge sehen. Die LEDs werden ziemlich schnell vor sich hin blinken.&lt;br /&gt;
&lt;br /&gt;
Reicht diese Verzögerung noch immer nicht, dann haben wir 2 Möglichkeiten:&lt;br /&gt;
* Entweder wir benutzen einen anderen Timer. Timer 1 beispielsweise ist ein 16 Bit Timer. Der Timer zählt also nicht von 0 bis 255 sondern von 0 bis 65535. Bei entsprechender Umarbeitung des Programms und einem Vorteiler von 1024 bedeutet das, dass die LEDs einen Ein/Aus Zyklus in 33 Sekunden absolvieren.&lt;br /&gt;
* Oder wir schalten die LEDs nicht bei jedem Timer Overflow um. Man könnte zum Beispiel in einem Register bis 7 zählen und nur dann, wenn dieses Register 7 erreicht hat, wird&lt;br /&gt;
** das Register wieder auf 0 gesetzt und&lt;br /&gt;
** die LEDs umgeschaltet.&lt;br /&gt;
&lt;br /&gt;
==Timer 0==&lt;br /&gt;
&lt;br /&gt;
Timer 0 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
&lt;br /&gt;
===TCCR0===&lt;br /&gt;
====TCCR - Timer/Counter Control Register====&lt;br /&gt;
{{Byte |TCCR0 |      |      |      |      |      | CS02 | CS01 | CS00 }}&lt;br /&gt;
&lt;br /&gt;
====CS02/CS00 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS02 || CS01 || CS00 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===TIMSK===&lt;br /&gt;
====TIMS - Timer/Counter Interrupt Mask Register====&lt;br /&gt;
&lt;br /&gt;
{{Byte|TIMSK|      |      |      |      |      |      | OCIE0 | TOIE0 }}&lt;br /&gt;
&lt;br /&gt;
====TOIE0 - Timer 0 Overflow Interrupt Enable====&lt;br /&gt;
Ist dieses Bit gesetzt, so wird beim Auftreten eines Overflows am Timer ein Interrupt ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Anstatt der Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
ist es besser, die Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 1 &amp;lt;&amp;lt; TOIE0&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
zu wählen, da hier unmittelbar aus dem Ladekommando hervorgeht, welche Bedeutung das gesetzte Bit hat. Die vorher inkludierte m8def.inc definiert dazu alles Notwendige.&lt;br /&gt;
&lt;br /&gt;
==Timer 1==&lt;br /&gt;
&lt;br /&gt;
Timer 1 ist ein 16 Bit Timer&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Input Capture&lt;br /&gt;
* 2 Compare Einheiten&lt;br /&gt;
* div. PWM Modi&lt;br /&gt;
&lt;br /&gt;
===TCCR1B===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1B| ICNC1| ICES1|      | WGM13| WGM12| CS12 | CS11 | CS10 }}&lt;br /&gt;
&lt;br /&gt;
====CS12/CS10 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS12 || CS11 || CS10 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====ICES1 - Input Capture Edge Select====&lt;br /&gt;
ICES1 = 0 , falling edge&lt;br /&gt;
ICES1 = 1 , rising edge&lt;br /&gt;
&lt;br /&gt;
====ICNC1 - Input Capture Noise Canceler====&lt;br /&gt;
&lt;br /&gt;
===TCCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1A|COM1A1|COM1A0|COM1B1|COM1B0|FOC1A |FOC1B |WGM11 |WGM10 }}&lt;br /&gt;
&lt;br /&gt;
===OCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===OCR1B===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===ICR1===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK1===&lt;br /&gt;
{{Byte|TIMSK|      |      |TICIE1|OCIE1A|OCIE1B|TOIE1 |      |}}&lt;br /&gt;
&lt;br /&gt;
====TICIE1 - Timer 1 Input Capture Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1A - Timer 1 Output Compare A Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1B - Timer 1 Output Compare B Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====TOIE1 - Timer 1 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Timer 2==&lt;br /&gt;
Timer 2 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Compare Match Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Phasen korrekte PWM&lt;br /&gt;
&lt;br /&gt;
===TCCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR2| FOC2 | WGM20| COM21| COM20| WGM21| CS22 | CS21 | CS20 }}&lt;br /&gt;
&lt;br /&gt;
====WGM21 - Waveform Generator Mode====&lt;br /&gt;
&lt;br /&gt;
Ist diese Option Aktiviert dann wird das Zählregister des Timers (TCNT2) wieder auf 0 gesetzt,&lt;br /&gt;
sobal das Register as Output Compare Register (OCR2) und TCNT2 übereinstimmen.&lt;br /&gt;
Zu beachten ist dabei das wenn das Register kleiner als 255 gestellt ist, wird&lt;br /&gt;
der Timer nicht mehr überschritten und der Interrupt für den Overflow (TIMER2_OVF_vect) nicht mehr ausgelöst.&lt;br /&gt;
Stattdessen gibt es den Interrupt für Compare Match (TIMER2_COMP_vect)&lt;br /&gt;
Die Frequenz für die Interruptauslösung lässt sich dann wie folgt berechnen:&lt;br /&gt;
ISR_Freq = F_CPU : ( Prescaler * ORC2 )&lt;br /&gt;
&lt;br /&gt;
====CS22/CS20 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS22 || CS21 || CS20 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 128&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===OCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK2===&lt;br /&gt;
{{Byte|TIMSK| OCIE2| TOIE2|      |      |      |      |      |      }}&lt;br /&gt;
&lt;br /&gt;
====OCIE2 - Timer 2 Output Compare Interrupt Enable====&lt;br /&gt;
====TOIE2   Timer 2 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Was geht noch mit einem Timer?==&lt;br /&gt;
&lt;br /&gt;
Timer sind sehr universelle Microcontroller Bestandteile. Für weitergehende Studien ist es daher unerlässlich, das entsprechende Datenblatt des Microcontrollers zu studieren. Oft ist es z.&amp;amp;nbsp;B. möglich, dass der Timer bei erreichen von bestimmten Zählerständen einen Ausgabepin von sich aus ein-/aus-/umschaltet. Er erledigt dann das, was wir oben noch mit einem Interrupt gemacht haben, eigenständig komplett in Hardware. Bei einigen Timern ist es möglich, damit eine [[PWM]] (Pulsweiten-Modulation) aufzubauen.&lt;br /&gt;
&lt;br /&gt;
Ein paar der Timermodule lassen sich auch als Counter verwenden. Damit kann man z.&amp;amp;nbsp;B. die Anzahl externer Ereignisse wie Schaltvorgänge eines Inkrementalgebers bestimmen.&lt;br /&gt;
&lt;br /&gt;
Andere bieten die Möglichkeit, über einen externen Uhrenquarz getaktet zu werden (Anwendung z.&amp;amp;nbsp;B. eine &amp;quot;Echtzeituhr&amp;quot; oder als &amp;quot;Weckfunktion&amp;quot; aus einem Standby/Powerdownmodus).&lt;br /&gt;
&lt;br /&gt;
Durch geschickte Umprogrammierung in Echtzeit, lässt sich mit einem Timer eine [[PLL]] aufbauen, die sich fortwährend auf einen Eingangstakt synchronisiert. Damit wird vermieden, dass der Controller ein Signal ständig abpollen muss, sondern das Signale wird per Timer-Interrupt verarbeitet. Massgeblich ist die Messung der aktuellen- und Schätzung der kommenden Flanke mithilfe eines einstellbaren [[Taktteiler]]-verhältnisses.&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.uni-koblenz.de/~physik/informatik/MCU/Timer.pdf Timer/Counter und PWM beim ATMega16 Mikrocontroller] Proseminar von Marcel Jakobs, September 2006 (PDF)&lt;br /&gt;
* [http://frank.circleofcurrent.com/cache/avrtimercalc.htm AVR Timer Calculator]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Speicher|&lt;br /&gt;
zurücklink=AVR-Tutorial: Speicher|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Uhr|&lt;br /&gt;
vorlink=AVR-Tutorial: Uhr}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Timer]]&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;/div&gt;</summary>
		<author><name>2001:A60:13D1:CB01:352D:6309:9D08:7E1F</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87647</id>
		<title>AVR-Tutorial: Timer</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87647"/>
		<updated>2015-03-04T00:29:22Z</updated>

		<summary type="html">&lt;p&gt;2001:A60:13D1:CB01:352D:6309:9D08:7E1F: /* CS02/CS00 - Clock Select */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timer sind eines der Hauptarbeitspferde in unserem Mikrocontroller. Mit ihrer Hilfe ist es möglich, in regelmäßigen Zeitabständen Aktionen zu veranlassen. Aber Timer können noch mehr!&lt;br /&gt;
* Timer können mit einem externen Pin hochgezählt werden&lt;br /&gt;
* Es gibt Möglichkeiten, bei bestimmten Zählerständen einen Interrupt auslösen zu lassen&lt;br /&gt;
* Timer können aber auch völlig selbstständig Signale an einem Ausgabepin erzeugen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Aber der Reihe nach und kurz zur Erinnerung: Die Beispiele passen zu einem ATmega8 und ggf. einer Reihe anderer AVR, können bei einigen Typen aber abweichen. &lt;br /&gt;
&lt;br /&gt;
==Was ist ein Timer?==&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist im Grunde nichts anderes als ein bestimmtes Register im Mikrocontroller, das hardwaregesteuert fortlaufend um 1 erhöht (oder verringert) wird (statt &amp;lt;i&amp;gt;um 1 erhöhen&amp;lt;/i&amp;gt; sagt man auch &#039;&#039;&#039;inkrementieren&#039;&#039;&#039;, und das Gegenstück, &#039;&#039;&#039;dekrementieren&#039;&#039;&#039;, bedeutet &amp;lt;i&amp;gt;um 1 verringern&amp;lt;/i&amp;gt;). Anstatt also Befehle im Programm vorzusehen, die regelmäßig ausgeführt werden und ein Register inkrementieren, erledigt dies der Mikrocontroller ganz von alleine. Dazu ist es möglich, den Timer mit dem Systemtakt zu verbinden und so die Genauigkeit des Quarzes auszunutzen, um ein Register regelmäßig und vor allen Dingen unabhängig vom restlichen Programmfluss (!) hochzählen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Davon alleine hätte man aber noch keinen großen Gewinn. Nützlich wird das Ganze erst dann, wenn man bei bestimmten Zählerständen eine Aktion ausführen lassen kann. Einer der &#039;bestimmten Zählerstände&#039; ist zum Beispiel der &#039;&#039;&#039;Overflow&#039;&#039;&#039;. Das Zählregister eines Timers kann natürlich nicht beliebig lange inkrementiert werden – z. B. ist der höchste Zählerstand, den ein 8-Bit-Timer erreichen kann, 2&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; – 1 = 255. Beim nächsten Inkrementierschritt tritt ein Überlauf (engl. Overflow) auf, der den Timerstand wieder zu 0 werden lässt. Und hier liegt der springende Punkt. Wir können uns nämlich an diesen Overflow &amp;quot;anhängen&amp;quot; und den Controller so konfigurieren, dass beim Auftreten des Timer-Overflows ein Interrupt ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die kann auch alles nochmal im Datenblatt von Atmel zu einigen ATMega Datenblättern nachgelesen werden: http://www.atmel.com/Images/doc8161.pdf&lt;br /&gt;
&lt;br /&gt;
==Der Vorteiler (Prescaler)==&lt;br /&gt;
&lt;br /&gt;
Wenn also der Quarzoszillator mit 4 MHz schwingt, dann würde auch der Timer 4 Millionen mal in der Sekunde erhöht werden. Da der Timer jedes Mal von 0 bis 255 zählt, bevor ein Overflow auftritt, heißt das auch, dass in einer Sekunde 4000000 / 256 = 15625 Overflows vorkommen. Ganz schön schnell! Nur: Oft ist das nicht sinnvoll. Um diese Raten zu verzögern, gibt es den Vorteiler, oder auf Englisch, Prescaler. Er kann z.B. auf die Werte 1, 8, 64, 256 oder 1024 eingestellt werden, je nach Timer (Bitte Datenblatt konsultieren!). Seine Aufgabe ist es, den Systemtakt um den angegebenen Faktor zu teilen. Steht der Vorteiler also auf 1024, so wird nur bei jedem 1024-ten Impuls vom Systemtakt das Timerregister um 1 erhöht. Entsprechend weniger häufig kommen dann natürlich die Overflows. Der Systemtakt sei wieder 4000000. Dann wird der Timer in 1 Sekunde 4000000 / 1024 = 3906.25 mal erhöht. Da der Timer wieder jedesmal bis 255 zählen muss bis ein Overflow auftritt, bedeutet dies, dass in 1 Sekunde 3906.25 / 256 = 15.25 Overflows auftreten.&lt;br /&gt;
&lt;br /&gt;
Systemtakt: 4Mhz&lt;br /&gt;
&lt;br /&gt;
  Vorteiler    Overflows/Sekunde      Zeit zwischen&lt;br /&gt;
                                      2 Overflows [s]&lt;br /&gt;
&lt;br /&gt;
      1            15625                0.000064&lt;br /&gt;
      8             1953.125            0.000512&lt;br /&gt;
     64              244.1406           0.004096&lt;br /&gt;
    256               61.0351           0.016384&lt;br /&gt;
   1024               15.2587           0.065536&lt;br /&gt;
&lt;br /&gt;
Die Zeit (in Sekunden) zwischen 2 Overflows lässt sich sehr leicht berechnen:&lt;br /&gt;
&amp;lt;math&amp;gt;t=\frac{2^\text{Bit des Timers} \cdot \text{Vorteiler}}{\text{Systemtakt in Hz}}&amp;lt;/math&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
==Erste Tests==&lt;br /&gt;
&lt;br /&gt;
Ein Programm, das einen Timer Overflow in Aktion zeigt, könnte z.&amp;amp;nbsp;B. so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp = r16&lt;br /&gt;
.def leds = r17&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
        rjmp    main                  ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
        rjmp    timer0_overflow       ; Timer Overflow Handler&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ; Stackpointer initialisieren&lt;br /&gt;
        ldi     temp, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp&lt;br /&gt;
        ldi     temp, LOW(RAMEND)     &lt;br /&gt;
        out     SPL, temp&lt;br /&gt;
	&lt;br /&gt;
        ldi     temp, 0xFF            ; Port B auf Ausgang&lt;br /&gt;
        out     DDRB, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     leds, 0xFF&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;CS00)       ; CS00 setzen: Teiler 1&lt;br /&gt;
        out     TCCR0, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;TOIE0)      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
&lt;br /&gt;
loop:   rjmp    loop&lt;br /&gt;
&lt;br /&gt;
timer0_overflow:                      ; Timer 0 Overflow Handler&lt;br /&gt;
        out     PORTB, leds&lt;br /&gt;
        com     leds&lt;br /&gt;
        reti&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Programm beginnt mit der [[AVR-Tutorial:_Interrupts|Interrupt-Vektoren-Tabelle]]. Dort ist an der Adresse &amp;lt;i&amp;gt;OVF0Addr&amp;lt;/i&amp;gt; ein Sprung zur Marke &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; eingetragen. Wenn also ein Overflow Interrupt vom Timer 0 auftritt, so wird dieser Interrupt durch den &#039;&#039;&#039;rjmp&#039;&#039;&#039; weitergeleitet an die Stelle &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm beginnt ganz normal mit der Belegung des Stackpointers. Danach wird der Port B auf Ausgang geschaltet, wir wollen hier wieder die LED anschliessen.&lt;br /&gt;
&lt;br /&gt;
Durch Beschreiben von TCCR0 mit dem Bitmuster 0b00000001, hier ausgedrückt durch (1&amp;lt;&amp;lt;CS00), wird der Vorteiler auf 1 gesetzt. Für die ersten Versuche empfiehlt es sich, das Programm mit dem AVR-Studio zunächst zu simulieren. Würden wir einen größeren Vorteiler benutzen, so müsste man ziemlich oft mittels F11 einen simulierten Schritt ausführen, um eine Änderung im Timerregister zu erreichen.&lt;br /&gt;
&lt;br /&gt;
Die nächsten Anweisungen setzen im TIMSK Register das TOIE0 Bit. Sinn der Sache ist es, dem Timer zu erlauben, bei Erreichen eines Overflow einen Interrupt auszulösen.&lt;br /&gt;
&lt;br /&gt;
Zum Schluss noch die Interrupts generell mittels &#039;&#039;&#039;sei&#039;&#039;&#039; freigeben. Dieser Schritt ist obligatorisch. Im Mikrocontroller können viele Quellen einen Interrupt auslösen. Daraus folgt: Für jede mögliche Quelle muss festgelegt werden, ob sie einen Interrupt erzeugen darf oder nicht. Die Oberhoheit hat aber das globale Interrupt Flag. Mit ihm können alle Interrupts, egal von welcher Quelle sie kommen, unterdrückt werden.&lt;br /&gt;
&lt;br /&gt;
Damit ist die Initialisierung beendet und das Hauptprogramm kann sich schlafen legen. Die &#039;&#039;&#039;loop: rjmp loop&#039;&#039;&#039; Schleife macht genau dieses.&lt;br /&gt;
&lt;br /&gt;
Tritt nun ein Overflow am Timer auf, so wird über den Umweg über die Interrupt Vektor Tabelle der Programmteil &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; angesprungen. Dieser gibt einfach nur den Inhalt des Registers leds am Port B aus. Danach wird das leds Register mit einer &#039;&#039;&#039;com&#039;&#039;&#039; Operation negiert, so dass aus allen 0 Bits eine 1 wird und umgekehrt. Die Overflow Behandlung ist damit beendet und mittels &#039;&#039;&#039;reti&#039;&#039;&#039; wird der Interrupt Handler wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
==Simulation im AVR-Studio==&lt;br /&gt;
&lt;br /&gt;
Es lohnt sich, den ganzen Vorgang im AVR-Studio simulieren zu lassen. Dazu am besten in der linken I/O View Ansicht die Einträge für PORTB und TIMER_COUNTER_0 öffnen. Wird mittels F11 durch das Programm gegangen, so sieht man, dass ab dem Moment, ab dem der Vorteiler auf 1 gesetzt wird, der Timer 0 im TCNT0 Register zu zählen anfängt. Mit jedem Druck auf F11 erhöht sich der Zählerstand. Irgendwann ist dann die Endlosschleife loop erreicht. Drücken Sie weiterhin F11 und beobachten sie, wie TCNT0 immer höher zählt, bis der Overflow erreicht wird. In dem Moment, in dem der Overflow erreicht wird, wird der Interrupt ausgelöst (hierfür muss für das Debuggen im AVR-Studio &amp;quot;Mask interrupts while stepping&amp;quot; deaktiviert sein, zu finden in Tools -&amp;gt; Options). Mit dem nächsten F11 landen sie in der Interrupt Vektor Tabelle und von dort geht es weiter zu timer_0_overflow. Weitere Tastendrücke von F11 erledigen dann die Ausgabe auf den Port B, das Invertieren des Registers r17 und der Interrupt ist damit behandelt. Nach dem &#039;&#039;&#039;reti&#039;&#039;&#039; macht der Microcontroller genau an der Stelle weiter, an der er vom Interrupt unterbrochen wurde. Und der Timer 0 hat in der Zwischenzeit weitergezählt! Nach exakt weiteren 256 Schritten, vom Auftreten des ersten Overflows an gerechnet, wird der nächste Overflow ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==Wie schnell schaltet denn jetzt der Port?==&lt;br /&gt;
&lt;br /&gt;
Eine berechtigte Frage. Dazu müssen wir etwas rechnen. Keine Angst, es ist nicht schwer, und wer das Prinzip bisher verstanden hat, der sollte keine Schwierigkeiten haben, die Berechnung nachzuvollziehen.&lt;br /&gt;
&lt;br /&gt;
Der Quarzoszillator schwingt mit 4 MHz. Das heißt, in 1 Sekunde werden 4000000 Taktzyklen generiert. Durch die Wahl des Vorteilers von 1 bedeutet das auch, dass der Timer 4000000 mal in der Sekunde erhöht wird. Von einem Overflow zum nächsten muss der Timer 256 Zählvorgänge ausführen. Also werden in 1 Sekunde 4000000 / 256 = 15625 Overflows generiert. Bei jedem Overflow schalten wir die LEDs jeweils in den anderen Zustand. D.h die LEDs blinken mit einer Frequenz von 7812.5 Hz. Das ist zuviel als dass wir es noch sehen könnten.&lt;br /&gt;
&lt;br /&gt;
Was können wir also tun, um diese Blinkfrequenz zu verringern? Im Moment ist unsere einzige Einflussgröße der Vorteiler. Wie sieht die Rechnung aus, wenn wir einen Vorteiler von 1024 wählen?&lt;br /&gt;
&lt;br /&gt;
Wiederrum: Der Systemtakt sei 4 Mhz. Durch den Vorteiler von 1024 werden daraus 4000000 / 1024 = 3906.25 Pulse pro Sekunde für den Timer. Der zählt wiederum 256 Zustände von einem Overflow zum nächsten. 3906.25 / 256 = 15.2587. Und wiederum: Im Overflow werden die LEDs ja abwechselnd ein und ausgeschaltet, also dividieren wir noch durch 2: 15.2587 / 2 = 7.629. Also knapp 7 Hz. Diese Frequenz müsste man schon mit freiem Auge sehen. Die LEDs werden ziemlich schnell vor sich hin blinken.&lt;br /&gt;
&lt;br /&gt;
Reicht diese Verzögerung noch immer nicht, dann haben wir 2 Möglichkeiten:&lt;br /&gt;
* Entweder wir benutzen einen anderen Timer. Timer 1 beispielsweise ist ein 16 Bit Timer. Der Timer zählt also nicht von 0 bis 255 sondern von 0 bis 65535. Bei entsprechender Umarbeitung des Programms und einem Vorteiler von 1024 bedeutet das, dass die LEDs einen Ein/Aus Zyklus in 33 Sekunden absolvieren.&lt;br /&gt;
* Oder wir schalten die LEDs nicht bei jedem Timer Overflow um. Man könnte zum Beispiel in einem Register bis 7 zählen und nur dann, wenn dieses Register 7 erreicht hat, wird&lt;br /&gt;
** das Register wieder auf 0 gesetzt und&lt;br /&gt;
** die LEDs umgeschaltet.&lt;br /&gt;
&lt;br /&gt;
==Timer 0==&lt;br /&gt;
&lt;br /&gt;
Timer 0 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
&lt;br /&gt;
===TCCR0===&lt;br /&gt;
====TCCR - Timer/Counter Control Register====&lt;br /&gt;
{{Byte |TCCR0 |      |      |      |      |      | CS02 | CS01 | CS00 }}&lt;br /&gt;
&lt;br /&gt;
====CS02/CS00 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS02 || CS01 || CS00 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===TIMSK - Timer/Counter Interrupt Mask Register===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TIMSK|      |      |      |      |      |      | OCIE0 | TOIE0 }}&lt;br /&gt;
&lt;br /&gt;
====TOIE0 - Timer 0 Overflow Interrupt Enable====&lt;br /&gt;
Ist dieses Bit gesetzt, so wird beim Auftreten eines Overflows am Timer ein Interrupt ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Anstatt der Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
ist es besser, die Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 1 &amp;lt;&amp;lt; TOIE0&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
zu wählen, da hier unmittelbar aus dem Ladekommando hervorgeht, welche Bedeutung das gesetzte Bit hat. Die vorher inkludierte m8def.inc definiert dazu alles Notwendige.&lt;br /&gt;
&lt;br /&gt;
==Timer 1==&lt;br /&gt;
&lt;br /&gt;
Timer 1 ist ein 16 Bit Timer&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Input Capture&lt;br /&gt;
* 2 Compare Einheiten&lt;br /&gt;
* div. PWM Modi&lt;br /&gt;
&lt;br /&gt;
===TCCR1B===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1B| ICNC1| ICES1|      | WGM13| WGM12| CS12 | CS11 | CS10 }}&lt;br /&gt;
&lt;br /&gt;
====CS12/CS10 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS12 || CS11 || CS10 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====ICES1 - Input Capture Edge Select====&lt;br /&gt;
ICES1 = 0 , falling edge&lt;br /&gt;
ICES1 = 1 , rising edge&lt;br /&gt;
&lt;br /&gt;
====ICNC1 - Input Capture Noise Canceler====&lt;br /&gt;
&lt;br /&gt;
===TCCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1A|COM1A1|COM1A0|COM1B1|COM1B0|FOC1A |FOC1B |WGM11 |WGM10 }}&lt;br /&gt;
&lt;br /&gt;
===OCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===OCR1B===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===ICR1===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK1===&lt;br /&gt;
{{Byte|TIMSK|      |      |TICIE1|OCIE1A|OCIE1B|TOIE1 |      |}}&lt;br /&gt;
&lt;br /&gt;
====TICIE1 - Timer 1 Input Capture Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1A - Timer 1 Output Compare A Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1B - Timer 1 Output Compare B Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====TOIE1 - Timer 1 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Timer 2==&lt;br /&gt;
Timer 2 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Compare Match Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Phasen korrekte PWM&lt;br /&gt;
&lt;br /&gt;
===TCCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR2| FOC2 | WGM20| COM21| COM20| WGM21| CS22 | CS21 | CS20 }}&lt;br /&gt;
&lt;br /&gt;
====WGM21 - Waveform Generator Mode====&lt;br /&gt;
&lt;br /&gt;
Ist diese Option Aktiviert dann wird das Zählregister des Timers (TCNT2) wieder auf 0 gesetzt,&lt;br /&gt;
sobal das Register as Output Compare Register (OCR2) und TCNT2 übereinstimmen.&lt;br /&gt;
Zu beachten ist dabei das wenn das Register kleiner als 255 gestellt ist, wird&lt;br /&gt;
der Timer nicht mehr überschritten und der Interrupt für den Overflow (TIMER2_OVF_vect) nicht mehr ausgelöst.&lt;br /&gt;
Stattdessen gibt es den Interrupt für Compare Match (TIMER2_COMP_vect)&lt;br /&gt;
Die Frequenz für die Interruptauslösung lässt sich dann wie folgt berechnen:&lt;br /&gt;
ISR_Freq = F_CPU : ( Prescaler * ORC2 )&lt;br /&gt;
&lt;br /&gt;
====CS22/CS20 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS22 || CS21 || CS20 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 128&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===OCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK2===&lt;br /&gt;
{{Byte|TIMSK| OCIE2| TOIE2|      |      |      |      |      |      }}&lt;br /&gt;
&lt;br /&gt;
====OCIE2 - Timer 2 Output Compare Interrupt Enable====&lt;br /&gt;
====TOIE2   Timer 2 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Was geht noch mit einem Timer?==&lt;br /&gt;
&lt;br /&gt;
Timer sind sehr universelle Microcontroller Bestandteile. Für weitergehende Studien ist es daher unerlässlich, das entsprechende Datenblatt des Microcontrollers zu studieren. Oft ist es z.&amp;amp;nbsp;B. möglich, dass der Timer bei erreichen von bestimmten Zählerständen einen Ausgabepin von sich aus ein-/aus-/umschaltet. Er erledigt dann das, was wir oben noch mit einem Interrupt gemacht haben, eigenständig komplett in Hardware. Bei einigen Timern ist es möglich, damit eine [[PWM]] (Pulsweiten-Modulation) aufzubauen.&lt;br /&gt;
&lt;br /&gt;
Ein paar der Timermodule lassen sich auch als Counter verwenden. Damit kann man z.&amp;amp;nbsp;B. die Anzahl externer Ereignisse wie Schaltvorgänge eines Inkrementalgebers bestimmen.&lt;br /&gt;
&lt;br /&gt;
Andere bieten die Möglichkeit, über einen externen Uhrenquarz getaktet zu werden (Anwendung z.&amp;amp;nbsp;B. eine &amp;quot;Echtzeituhr&amp;quot; oder als &amp;quot;Weckfunktion&amp;quot; aus einem Standby/Powerdownmodus).&lt;br /&gt;
&lt;br /&gt;
Durch geschickte Umprogrammierung in Echtzeit, lässt sich mit einem Timer eine [[PLL]] aufbauen, die sich fortwährend auf einen Eingangstakt synchronisiert. Damit wird vermieden, dass der Controller ein Signal ständig abpollen muss, sondern das Signale wird per Timer-Interrupt verarbeitet. Massgeblich ist die Messung der aktuellen- und Schätzung der kommenden Flanke mithilfe eines einstellbaren [[Taktteiler]]-verhältnisses.&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.uni-koblenz.de/~physik/informatik/MCU/Timer.pdf Timer/Counter und PWM beim ATMega16 Mikrocontroller] Proseminar von Marcel Jakobs, September 2006 (PDF)&lt;br /&gt;
* [http://frank.circleofcurrent.com/cache/avrtimercalc.htm AVR Timer Calculator]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Speicher|&lt;br /&gt;
zurücklink=AVR-Tutorial: Speicher|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Uhr|&lt;br /&gt;
vorlink=AVR-Tutorial: Uhr}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Timer]]&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;/div&gt;</summary>
		<author><name>2001:A60:13D1:CB01:352D:6309:9D08:7E1F</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87646</id>
		<title>AVR-Tutorial: Timer</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87646"/>
		<updated>2015-03-04T00:28:24Z</updated>

		<summary type="html">&lt;p&gt;2001:A60:13D1:CB01:352D:6309:9D08:7E1F: /* TIMSK */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timer sind eines der Hauptarbeitspferde in unserem Mikrocontroller. Mit ihrer Hilfe ist es möglich, in regelmäßigen Zeitabständen Aktionen zu veranlassen. Aber Timer können noch mehr!&lt;br /&gt;
* Timer können mit einem externen Pin hochgezählt werden&lt;br /&gt;
* Es gibt Möglichkeiten, bei bestimmten Zählerständen einen Interrupt auslösen zu lassen&lt;br /&gt;
* Timer können aber auch völlig selbstständig Signale an einem Ausgabepin erzeugen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Aber der Reihe nach und kurz zur Erinnerung: Die Beispiele passen zu einem ATmega8 und ggf. einer Reihe anderer AVR, können bei einigen Typen aber abweichen. &lt;br /&gt;
&lt;br /&gt;
==Was ist ein Timer?==&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist im Grunde nichts anderes als ein bestimmtes Register im Mikrocontroller, das hardwaregesteuert fortlaufend um 1 erhöht (oder verringert) wird (statt &amp;lt;i&amp;gt;um 1 erhöhen&amp;lt;/i&amp;gt; sagt man auch &#039;&#039;&#039;inkrementieren&#039;&#039;&#039;, und das Gegenstück, &#039;&#039;&#039;dekrementieren&#039;&#039;&#039;, bedeutet &amp;lt;i&amp;gt;um 1 verringern&amp;lt;/i&amp;gt;). Anstatt also Befehle im Programm vorzusehen, die regelmäßig ausgeführt werden und ein Register inkrementieren, erledigt dies der Mikrocontroller ganz von alleine. Dazu ist es möglich, den Timer mit dem Systemtakt zu verbinden und so die Genauigkeit des Quarzes auszunutzen, um ein Register regelmäßig und vor allen Dingen unabhängig vom restlichen Programmfluss (!) hochzählen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Davon alleine hätte man aber noch keinen großen Gewinn. Nützlich wird das Ganze erst dann, wenn man bei bestimmten Zählerständen eine Aktion ausführen lassen kann. Einer der &#039;bestimmten Zählerstände&#039; ist zum Beispiel der &#039;&#039;&#039;Overflow&#039;&#039;&#039;. Das Zählregister eines Timers kann natürlich nicht beliebig lange inkrementiert werden – z. B. ist der höchste Zählerstand, den ein 8-Bit-Timer erreichen kann, 2&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; – 1 = 255. Beim nächsten Inkrementierschritt tritt ein Überlauf (engl. Overflow) auf, der den Timerstand wieder zu 0 werden lässt. Und hier liegt der springende Punkt. Wir können uns nämlich an diesen Overflow &amp;quot;anhängen&amp;quot; und den Controller so konfigurieren, dass beim Auftreten des Timer-Overflows ein Interrupt ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die kann auch alles nochmal im Datenblatt von Atmel zu einigen ATMega Datenblättern nachgelesen werden: http://www.atmel.com/Images/doc8161.pdf&lt;br /&gt;
&lt;br /&gt;
==Der Vorteiler (Prescaler)==&lt;br /&gt;
&lt;br /&gt;
Wenn also der Quarzoszillator mit 4 MHz schwingt, dann würde auch der Timer 4 Millionen mal in der Sekunde erhöht werden. Da der Timer jedes Mal von 0 bis 255 zählt, bevor ein Overflow auftritt, heißt das auch, dass in einer Sekunde 4000000 / 256 = 15625 Overflows vorkommen. Ganz schön schnell! Nur: Oft ist das nicht sinnvoll. Um diese Raten zu verzögern, gibt es den Vorteiler, oder auf Englisch, Prescaler. Er kann z.B. auf die Werte 1, 8, 64, 256 oder 1024 eingestellt werden, je nach Timer (Bitte Datenblatt konsultieren!). Seine Aufgabe ist es, den Systemtakt um den angegebenen Faktor zu teilen. Steht der Vorteiler also auf 1024, so wird nur bei jedem 1024-ten Impuls vom Systemtakt das Timerregister um 1 erhöht. Entsprechend weniger häufig kommen dann natürlich die Overflows. Der Systemtakt sei wieder 4000000. Dann wird der Timer in 1 Sekunde 4000000 / 1024 = 3906.25 mal erhöht. Da der Timer wieder jedesmal bis 255 zählen muss bis ein Overflow auftritt, bedeutet dies, dass in 1 Sekunde 3906.25 / 256 = 15.25 Overflows auftreten.&lt;br /&gt;
&lt;br /&gt;
Systemtakt: 4Mhz&lt;br /&gt;
&lt;br /&gt;
  Vorteiler    Overflows/Sekunde      Zeit zwischen&lt;br /&gt;
                                      2 Overflows [s]&lt;br /&gt;
&lt;br /&gt;
      1            15625                0.000064&lt;br /&gt;
      8             1953.125            0.000512&lt;br /&gt;
     64              244.1406           0.004096&lt;br /&gt;
    256               61.0351           0.016384&lt;br /&gt;
   1024               15.2587           0.065536&lt;br /&gt;
&lt;br /&gt;
Die Zeit (in Sekunden) zwischen 2 Overflows lässt sich sehr leicht berechnen:&lt;br /&gt;
&amp;lt;math&amp;gt;t=\frac{2^\text{Bit des Timers} \cdot \text{Vorteiler}}{\text{Systemtakt in Hz}}&amp;lt;/math&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
==Erste Tests==&lt;br /&gt;
&lt;br /&gt;
Ein Programm, das einen Timer Overflow in Aktion zeigt, könnte z.&amp;amp;nbsp;B. so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp = r16&lt;br /&gt;
.def leds = r17&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
        rjmp    main                  ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
        rjmp    timer0_overflow       ; Timer Overflow Handler&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ; Stackpointer initialisieren&lt;br /&gt;
        ldi     temp, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp&lt;br /&gt;
        ldi     temp, LOW(RAMEND)     &lt;br /&gt;
        out     SPL, temp&lt;br /&gt;
	&lt;br /&gt;
        ldi     temp, 0xFF            ; Port B auf Ausgang&lt;br /&gt;
        out     DDRB, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     leds, 0xFF&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;CS00)       ; CS00 setzen: Teiler 1&lt;br /&gt;
        out     TCCR0, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;TOIE0)      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
&lt;br /&gt;
loop:   rjmp    loop&lt;br /&gt;
&lt;br /&gt;
timer0_overflow:                      ; Timer 0 Overflow Handler&lt;br /&gt;
        out     PORTB, leds&lt;br /&gt;
        com     leds&lt;br /&gt;
        reti&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Programm beginnt mit der [[AVR-Tutorial:_Interrupts|Interrupt-Vektoren-Tabelle]]. Dort ist an der Adresse &amp;lt;i&amp;gt;OVF0Addr&amp;lt;/i&amp;gt; ein Sprung zur Marke &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; eingetragen. Wenn also ein Overflow Interrupt vom Timer 0 auftritt, so wird dieser Interrupt durch den &#039;&#039;&#039;rjmp&#039;&#039;&#039; weitergeleitet an die Stelle &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm beginnt ganz normal mit der Belegung des Stackpointers. Danach wird der Port B auf Ausgang geschaltet, wir wollen hier wieder die LED anschliessen.&lt;br /&gt;
&lt;br /&gt;
Durch Beschreiben von TCCR0 mit dem Bitmuster 0b00000001, hier ausgedrückt durch (1&amp;lt;&amp;lt;CS00), wird der Vorteiler auf 1 gesetzt. Für die ersten Versuche empfiehlt es sich, das Programm mit dem AVR-Studio zunächst zu simulieren. Würden wir einen größeren Vorteiler benutzen, so müsste man ziemlich oft mittels F11 einen simulierten Schritt ausführen, um eine Änderung im Timerregister zu erreichen.&lt;br /&gt;
&lt;br /&gt;
Die nächsten Anweisungen setzen im TIMSK Register das TOIE0 Bit. Sinn der Sache ist es, dem Timer zu erlauben, bei Erreichen eines Overflow einen Interrupt auszulösen.&lt;br /&gt;
&lt;br /&gt;
Zum Schluss noch die Interrupts generell mittels &#039;&#039;&#039;sei&#039;&#039;&#039; freigeben. Dieser Schritt ist obligatorisch. Im Mikrocontroller können viele Quellen einen Interrupt auslösen. Daraus folgt: Für jede mögliche Quelle muss festgelegt werden, ob sie einen Interrupt erzeugen darf oder nicht. Die Oberhoheit hat aber das globale Interrupt Flag. Mit ihm können alle Interrupts, egal von welcher Quelle sie kommen, unterdrückt werden.&lt;br /&gt;
&lt;br /&gt;
Damit ist die Initialisierung beendet und das Hauptprogramm kann sich schlafen legen. Die &#039;&#039;&#039;loop: rjmp loop&#039;&#039;&#039; Schleife macht genau dieses.&lt;br /&gt;
&lt;br /&gt;
Tritt nun ein Overflow am Timer auf, so wird über den Umweg über die Interrupt Vektor Tabelle der Programmteil &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; angesprungen. Dieser gibt einfach nur den Inhalt des Registers leds am Port B aus. Danach wird das leds Register mit einer &#039;&#039;&#039;com&#039;&#039;&#039; Operation negiert, so dass aus allen 0 Bits eine 1 wird und umgekehrt. Die Overflow Behandlung ist damit beendet und mittels &#039;&#039;&#039;reti&#039;&#039;&#039; wird der Interrupt Handler wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
==Simulation im AVR-Studio==&lt;br /&gt;
&lt;br /&gt;
Es lohnt sich, den ganzen Vorgang im AVR-Studio simulieren zu lassen. Dazu am besten in der linken I/O View Ansicht die Einträge für PORTB und TIMER_COUNTER_0 öffnen. Wird mittels F11 durch das Programm gegangen, so sieht man, dass ab dem Moment, ab dem der Vorteiler auf 1 gesetzt wird, der Timer 0 im TCNT0 Register zu zählen anfängt. Mit jedem Druck auf F11 erhöht sich der Zählerstand. Irgendwann ist dann die Endlosschleife loop erreicht. Drücken Sie weiterhin F11 und beobachten sie, wie TCNT0 immer höher zählt, bis der Overflow erreicht wird. In dem Moment, in dem der Overflow erreicht wird, wird der Interrupt ausgelöst (hierfür muss für das Debuggen im AVR-Studio &amp;quot;Mask interrupts while stepping&amp;quot; deaktiviert sein, zu finden in Tools -&amp;gt; Options). Mit dem nächsten F11 landen sie in der Interrupt Vektor Tabelle und von dort geht es weiter zu timer_0_overflow. Weitere Tastendrücke von F11 erledigen dann die Ausgabe auf den Port B, das Invertieren des Registers r17 und der Interrupt ist damit behandelt. Nach dem &#039;&#039;&#039;reti&#039;&#039;&#039; macht der Microcontroller genau an der Stelle weiter, an der er vom Interrupt unterbrochen wurde. Und der Timer 0 hat in der Zwischenzeit weitergezählt! Nach exakt weiteren 256 Schritten, vom Auftreten des ersten Overflows an gerechnet, wird der nächste Overflow ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==Wie schnell schaltet denn jetzt der Port?==&lt;br /&gt;
&lt;br /&gt;
Eine berechtigte Frage. Dazu müssen wir etwas rechnen. Keine Angst, es ist nicht schwer, und wer das Prinzip bisher verstanden hat, der sollte keine Schwierigkeiten haben, die Berechnung nachzuvollziehen.&lt;br /&gt;
&lt;br /&gt;
Der Quarzoszillator schwingt mit 4 MHz. Das heißt, in 1 Sekunde werden 4000000 Taktzyklen generiert. Durch die Wahl des Vorteilers von 1 bedeutet das auch, dass der Timer 4000000 mal in der Sekunde erhöht wird. Von einem Overflow zum nächsten muss der Timer 256 Zählvorgänge ausführen. Also werden in 1 Sekunde 4000000 / 256 = 15625 Overflows generiert. Bei jedem Overflow schalten wir die LEDs jeweils in den anderen Zustand. D.h die LEDs blinken mit einer Frequenz von 7812.5 Hz. Das ist zuviel als dass wir es noch sehen könnten.&lt;br /&gt;
&lt;br /&gt;
Was können wir also tun, um diese Blinkfrequenz zu verringern? Im Moment ist unsere einzige Einflussgröße der Vorteiler. Wie sieht die Rechnung aus, wenn wir einen Vorteiler von 1024 wählen?&lt;br /&gt;
&lt;br /&gt;
Wiederrum: Der Systemtakt sei 4 Mhz. Durch den Vorteiler von 1024 werden daraus 4000000 / 1024 = 3906.25 Pulse pro Sekunde für den Timer. Der zählt wiederum 256 Zustände von einem Overflow zum nächsten. 3906.25 / 256 = 15.2587. Und wiederum: Im Overflow werden die LEDs ja abwechselnd ein und ausgeschaltet, also dividieren wir noch durch 2: 15.2587 / 2 = 7.629. Also knapp 7 Hz. Diese Frequenz müsste man schon mit freiem Auge sehen. Die LEDs werden ziemlich schnell vor sich hin blinken.&lt;br /&gt;
&lt;br /&gt;
Reicht diese Verzögerung noch immer nicht, dann haben wir 2 Möglichkeiten:&lt;br /&gt;
* Entweder wir benutzen einen anderen Timer. Timer 1 beispielsweise ist ein 16 Bit Timer. Der Timer zählt also nicht von 0 bis 255 sondern von 0 bis 65535. Bei entsprechender Umarbeitung des Programms und einem Vorteiler von 1024 bedeutet das, dass die LEDs einen Ein/Aus Zyklus in 33 Sekunden absolvieren.&lt;br /&gt;
* Oder wir schalten die LEDs nicht bei jedem Timer Overflow um. Man könnte zum Beispiel in einem Register bis 7 zählen und nur dann, wenn dieses Register 7 erreicht hat, wird&lt;br /&gt;
** das Register wieder auf 0 gesetzt und&lt;br /&gt;
** die LEDs umgeschaltet.&lt;br /&gt;
&lt;br /&gt;
==Timer 0==&lt;br /&gt;
&lt;br /&gt;
Timer 0 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
&lt;br /&gt;
===TCCR0===&lt;br /&gt;
====TCCR - Timer/Counter Control Register====&lt;br /&gt;
{{Byte |TCCR0 |      |      |      |      |      | CS02 | CS01 | CS00 }}&lt;br /&gt;
&lt;br /&gt;
====CS02/CS00 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS02 || CS01 || CS00 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===TIMSK - Timer/Counter&lt;br /&gt;
Interrupt Mask&lt;br /&gt;
Register===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TIMSK|      |      |      |      |      |      | OCIE0 | TOIE0 }}&lt;br /&gt;
&lt;br /&gt;
====TOIE0 - Timer 0 Overflow Interrupt Enable====&lt;br /&gt;
Ist dieses Bit gesetzt, so wird beim Auftreten eines Overflows am Timer ein Interrupt ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Anstatt der Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
ist es besser, die Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 1 &amp;lt;&amp;lt; TOIE0&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
zu wählen, da hier unmittelbar aus dem Ladekommando hervorgeht, welche Bedeutung das gesetzte Bit hat. Die vorher inkludierte m8def.inc definiert dazu alles Notwendige.&lt;br /&gt;
&lt;br /&gt;
==Timer 1==&lt;br /&gt;
&lt;br /&gt;
Timer 1 ist ein 16 Bit Timer&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Input Capture&lt;br /&gt;
* 2 Compare Einheiten&lt;br /&gt;
* div. PWM Modi&lt;br /&gt;
&lt;br /&gt;
===TCCR1B===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1B| ICNC1| ICES1|      | WGM13| WGM12| CS12 | CS11 | CS10 }}&lt;br /&gt;
&lt;br /&gt;
====CS12/CS10 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS12 || CS11 || CS10 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====ICES1 - Input Capture Edge Select====&lt;br /&gt;
ICES1 = 0 , falling edge&lt;br /&gt;
ICES1 = 1 , rising edge&lt;br /&gt;
&lt;br /&gt;
====ICNC1 - Input Capture Noise Canceler====&lt;br /&gt;
&lt;br /&gt;
===TCCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1A|COM1A1|COM1A0|COM1B1|COM1B0|FOC1A |FOC1B |WGM11 |WGM10 }}&lt;br /&gt;
&lt;br /&gt;
===OCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===OCR1B===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===ICR1===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK1===&lt;br /&gt;
{{Byte|TIMSK|      |      |TICIE1|OCIE1A|OCIE1B|TOIE1 |      |}}&lt;br /&gt;
&lt;br /&gt;
====TICIE1 - Timer 1 Input Capture Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1A - Timer 1 Output Compare A Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1B - Timer 1 Output Compare B Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====TOIE1 - Timer 1 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Timer 2==&lt;br /&gt;
Timer 2 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Compare Match Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Phasen korrekte PWM&lt;br /&gt;
&lt;br /&gt;
===TCCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR2| FOC2 | WGM20| COM21| COM20| WGM21| CS22 | CS21 | CS20 }}&lt;br /&gt;
&lt;br /&gt;
====WGM21 - Waveform Generator Mode====&lt;br /&gt;
&lt;br /&gt;
Ist diese Option Aktiviert dann wird das Zählregister des Timers (TCNT2) wieder auf 0 gesetzt,&lt;br /&gt;
sobal das Register as Output Compare Register (OCR2) und TCNT2 übereinstimmen.&lt;br /&gt;
Zu beachten ist dabei das wenn das Register kleiner als 255 gestellt ist, wird&lt;br /&gt;
der Timer nicht mehr überschritten und der Interrupt für den Overflow (TIMER2_OVF_vect) nicht mehr ausgelöst.&lt;br /&gt;
Stattdessen gibt es den Interrupt für Compare Match (TIMER2_COMP_vect)&lt;br /&gt;
Die Frequenz für die Interruptauslösung lässt sich dann wie folgt berechnen:&lt;br /&gt;
ISR_Freq = F_CPU : ( Prescaler * ORC2 )&lt;br /&gt;
&lt;br /&gt;
====CS22/CS20 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS22 || CS21 || CS20 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 128&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===OCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK2===&lt;br /&gt;
{{Byte|TIMSK| OCIE2| TOIE2|      |      |      |      |      |      }}&lt;br /&gt;
&lt;br /&gt;
====OCIE2 - Timer 2 Output Compare Interrupt Enable====&lt;br /&gt;
====TOIE2   Timer 2 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Was geht noch mit einem Timer?==&lt;br /&gt;
&lt;br /&gt;
Timer sind sehr universelle Microcontroller Bestandteile. Für weitergehende Studien ist es daher unerlässlich, das entsprechende Datenblatt des Microcontrollers zu studieren. Oft ist es z.&amp;amp;nbsp;B. möglich, dass der Timer bei erreichen von bestimmten Zählerständen einen Ausgabepin von sich aus ein-/aus-/umschaltet. Er erledigt dann das, was wir oben noch mit einem Interrupt gemacht haben, eigenständig komplett in Hardware. Bei einigen Timern ist es möglich, damit eine [[PWM]] (Pulsweiten-Modulation) aufzubauen.&lt;br /&gt;
&lt;br /&gt;
Ein paar der Timermodule lassen sich auch als Counter verwenden. Damit kann man z.&amp;amp;nbsp;B. die Anzahl externer Ereignisse wie Schaltvorgänge eines Inkrementalgebers bestimmen.&lt;br /&gt;
&lt;br /&gt;
Andere bieten die Möglichkeit, über einen externen Uhrenquarz getaktet zu werden (Anwendung z.&amp;amp;nbsp;B. eine &amp;quot;Echtzeituhr&amp;quot; oder als &amp;quot;Weckfunktion&amp;quot; aus einem Standby/Powerdownmodus).&lt;br /&gt;
&lt;br /&gt;
Durch geschickte Umprogrammierung in Echtzeit, lässt sich mit einem Timer eine [[PLL]] aufbauen, die sich fortwährend auf einen Eingangstakt synchronisiert. Damit wird vermieden, dass der Controller ein Signal ständig abpollen muss, sondern das Signale wird per Timer-Interrupt verarbeitet. Massgeblich ist die Messung der aktuellen- und Schätzung der kommenden Flanke mithilfe eines einstellbaren [[Taktteiler]]-verhältnisses.&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.uni-koblenz.de/~physik/informatik/MCU/Timer.pdf Timer/Counter und PWM beim ATMega16 Mikrocontroller] Proseminar von Marcel Jakobs, September 2006 (PDF)&lt;br /&gt;
* [http://frank.circleofcurrent.com/cache/avrtimercalc.htm AVR Timer Calculator]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Speicher|&lt;br /&gt;
zurücklink=AVR-Tutorial: Speicher|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Uhr|&lt;br /&gt;
vorlink=AVR-Tutorial: Uhr}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Timer]]&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;/div&gt;</summary>
		<author><name>2001:A60:13D1:CB01:352D:6309:9D08:7E1F</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87645</id>
		<title>AVR-Tutorial: Timer</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=87645"/>
		<updated>2015-03-04T00:23:57Z</updated>

		<summary type="html">&lt;p&gt;2001:A60:13D1:CB01:352D:6309:9D08:7E1F: /* Simulation im AVR-Studio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timer sind eines der Hauptarbeitspferde in unserem Mikrocontroller. Mit ihrer Hilfe ist es möglich, in regelmäßigen Zeitabständen Aktionen zu veranlassen. Aber Timer können noch mehr!&lt;br /&gt;
* Timer können mit einem externen Pin hochgezählt werden&lt;br /&gt;
* Es gibt Möglichkeiten, bei bestimmten Zählerständen einen Interrupt auslösen zu lassen&lt;br /&gt;
* Timer können aber auch völlig selbstständig Signale an einem Ausgabepin erzeugen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Aber der Reihe nach und kurz zur Erinnerung: Die Beispiele passen zu einem ATmega8 und ggf. einer Reihe anderer AVR, können bei einigen Typen aber abweichen. &lt;br /&gt;
&lt;br /&gt;
==Was ist ein Timer?==&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist im Grunde nichts anderes als ein bestimmtes Register im Mikrocontroller, das hardwaregesteuert fortlaufend um 1 erhöht (oder verringert) wird (statt &amp;lt;i&amp;gt;um 1 erhöhen&amp;lt;/i&amp;gt; sagt man auch &#039;&#039;&#039;inkrementieren&#039;&#039;&#039;, und das Gegenstück, &#039;&#039;&#039;dekrementieren&#039;&#039;&#039;, bedeutet &amp;lt;i&amp;gt;um 1 verringern&amp;lt;/i&amp;gt;). Anstatt also Befehle im Programm vorzusehen, die regelmäßig ausgeführt werden und ein Register inkrementieren, erledigt dies der Mikrocontroller ganz von alleine. Dazu ist es möglich, den Timer mit dem Systemtakt zu verbinden und so die Genauigkeit des Quarzes auszunutzen, um ein Register regelmäßig und vor allen Dingen unabhängig vom restlichen Programmfluss (!) hochzählen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Davon alleine hätte man aber noch keinen großen Gewinn. Nützlich wird das Ganze erst dann, wenn man bei bestimmten Zählerständen eine Aktion ausführen lassen kann. Einer der &#039;bestimmten Zählerstände&#039; ist zum Beispiel der &#039;&#039;&#039;Overflow&#039;&#039;&#039;. Das Zählregister eines Timers kann natürlich nicht beliebig lange inkrementiert werden – z. B. ist der höchste Zählerstand, den ein 8-Bit-Timer erreichen kann, 2&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; – 1 = 255. Beim nächsten Inkrementierschritt tritt ein Überlauf (engl. Overflow) auf, der den Timerstand wieder zu 0 werden lässt. Und hier liegt der springende Punkt. Wir können uns nämlich an diesen Overflow &amp;quot;anhängen&amp;quot; und den Controller so konfigurieren, dass beim Auftreten des Timer-Overflows ein Interrupt ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die kann auch alles nochmal im Datenblatt von Atmel zu einigen ATMega Datenblättern nachgelesen werden: http://www.atmel.com/Images/doc8161.pdf&lt;br /&gt;
&lt;br /&gt;
==Der Vorteiler (Prescaler)==&lt;br /&gt;
&lt;br /&gt;
Wenn also der Quarzoszillator mit 4 MHz schwingt, dann würde auch der Timer 4 Millionen mal in der Sekunde erhöht werden. Da der Timer jedes Mal von 0 bis 255 zählt, bevor ein Overflow auftritt, heißt das auch, dass in einer Sekunde 4000000 / 256 = 15625 Overflows vorkommen. Ganz schön schnell! Nur: Oft ist das nicht sinnvoll. Um diese Raten zu verzögern, gibt es den Vorteiler, oder auf Englisch, Prescaler. Er kann z.B. auf die Werte 1, 8, 64, 256 oder 1024 eingestellt werden, je nach Timer (Bitte Datenblatt konsultieren!). Seine Aufgabe ist es, den Systemtakt um den angegebenen Faktor zu teilen. Steht der Vorteiler also auf 1024, so wird nur bei jedem 1024-ten Impuls vom Systemtakt das Timerregister um 1 erhöht. Entsprechend weniger häufig kommen dann natürlich die Overflows. Der Systemtakt sei wieder 4000000. Dann wird der Timer in 1 Sekunde 4000000 / 1024 = 3906.25 mal erhöht. Da der Timer wieder jedesmal bis 255 zählen muss bis ein Overflow auftritt, bedeutet dies, dass in 1 Sekunde 3906.25 / 256 = 15.25 Overflows auftreten.&lt;br /&gt;
&lt;br /&gt;
Systemtakt: 4Mhz&lt;br /&gt;
&lt;br /&gt;
  Vorteiler    Overflows/Sekunde      Zeit zwischen&lt;br /&gt;
                                      2 Overflows [s]&lt;br /&gt;
&lt;br /&gt;
      1            15625                0.000064&lt;br /&gt;
      8             1953.125            0.000512&lt;br /&gt;
     64              244.1406           0.004096&lt;br /&gt;
    256               61.0351           0.016384&lt;br /&gt;
   1024               15.2587           0.065536&lt;br /&gt;
&lt;br /&gt;
Die Zeit (in Sekunden) zwischen 2 Overflows lässt sich sehr leicht berechnen:&lt;br /&gt;
&amp;lt;math&amp;gt;t=\frac{2^\text{Bit des Timers} \cdot \text{Vorteiler}}{\text{Systemtakt in Hz}}&amp;lt;/math&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
==Erste Tests==&lt;br /&gt;
&lt;br /&gt;
Ein Programm, das einen Timer Overflow in Aktion zeigt, könnte z.&amp;amp;nbsp;B. so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp = r16&lt;br /&gt;
.def leds = r17&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
        rjmp    main                  ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
        rjmp    timer0_overflow       ; Timer Overflow Handler&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ; Stackpointer initialisieren&lt;br /&gt;
        ldi     temp, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp&lt;br /&gt;
        ldi     temp, LOW(RAMEND)     &lt;br /&gt;
        out     SPL, temp&lt;br /&gt;
	&lt;br /&gt;
        ldi     temp, 0xFF            ; Port B auf Ausgang&lt;br /&gt;
        out     DDRB, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     leds, 0xFF&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;CS00)       ; CS00 setzen: Teiler 1&lt;br /&gt;
        out     TCCR0, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;TOIE0)      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
&lt;br /&gt;
loop:   rjmp    loop&lt;br /&gt;
&lt;br /&gt;
timer0_overflow:                      ; Timer 0 Overflow Handler&lt;br /&gt;
        out     PORTB, leds&lt;br /&gt;
        com     leds&lt;br /&gt;
        reti&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Programm beginnt mit der [[AVR-Tutorial:_Interrupts|Interrupt-Vektoren-Tabelle]]. Dort ist an der Adresse &amp;lt;i&amp;gt;OVF0Addr&amp;lt;/i&amp;gt; ein Sprung zur Marke &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; eingetragen. Wenn also ein Overflow Interrupt vom Timer 0 auftritt, so wird dieser Interrupt durch den &#039;&#039;&#039;rjmp&#039;&#039;&#039; weitergeleitet an die Stelle &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm beginnt ganz normal mit der Belegung des Stackpointers. Danach wird der Port B auf Ausgang geschaltet, wir wollen hier wieder die LED anschliessen.&lt;br /&gt;
&lt;br /&gt;
Durch Beschreiben von TCCR0 mit dem Bitmuster 0b00000001, hier ausgedrückt durch (1&amp;lt;&amp;lt;CS00), wird der Vorteiler auf 1 gesetzt. Für die ersten Versuche empfiehlt es sich, das Programm mit dem AVR-Studio zunächst zu simulieren. Würden wir einen größeren Vorteiler benutzen, so müsste man ziemlich oft mittels F11 einen simulierten Schritt ausführen, um eine Änderung im Timerregister zu erreichen.&lt;br /&gt;
&lt;br /&gt;
Die nächsten Anweisungen setzen im TIMSK Register das TOIE0 Bit. Sinn der Sache ist es, dem Timer zu erlauben, bei Erreichen eines Overflow einen Interrupt auszulösen.&lt;br /&gt;
&lt;br /&gt;
Zum Schluss noch die Interrupts generell mittels &#039;&#039;&#039;sei&#039;&#039;&#039; freigeben. Dieser Schritt ist obligatorisch. Im Mikrocontroller können viele Quellen einen Interrupt auslösen. Daraus folgt: Für jede mögliche Quelle muss festgelegt werden, ob sie einen Interrupt erzeugen darf oder nicht. Die Oberhoheit hat aber das globale Interrupt Flag. Mit ihm können alle Interrupts, egal von welcher Quelle sie kommen, unterdrückt werden.&lt;br /&gt;
&lt;br /&gt;
Damit ist die Initialisierung beendet und das Hauptprogramm kann sich schlafen legen. Die &#039;&#039;&#039;loop: rjmp loop&#039;&#039;&#039; Schleife macht genau dieses.&lt;br /&gt;
&lt;br /&gt;
Tritt nun ein Overflow am Timer auf, so wird über den Umweg über die Interrupt Vektor Tabelle der Programmteil &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; angesprungen. Dieser gibt einfach nur den Inhalt des Registers leds am Port B aus. Danach wird das leds Register mit einer &#039;&#039;&#039;com&#039;&#039;&#039; Operation negiert, so dass aus allen 0 Bits eine 1 wird und umgekehrt. Die Overflow Behandlung ist damit beendet und mittels &#039;&#039;&#039;reti&#039;&#039;&#039; wird der Interrupt Handler wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
==Simulation im AVR-Studio==&lt;br /&gt;
&lt;br /&gt;
Es lohnt sich, den ganzen Vorgang im AVR-Studio simulieren zu lassen. Dazu am besten in der linken I/O View Ansicht die Einträge für PORTB und TIMER_COUNTER_0 öffnen. Wird mittels F11 durch das Programm gegangen, so sieht man, dass ab dem Moment, ab dem der Vorteiler auf 1 gesetzt wird, der Timer 0 im TCNT0 Register zu zählen anfängt. Mit jedem Druck auf F11 erhöht sich der Zählerstand. Irgendwann ist dann die Endlosschleife loop erreicht. Drücken Sie weiterhin F11 und beobachten sie, wie TCNT0 immer höher zählt, bis der Overflow erreicht wird. In dem Moment, in dem der Overflow erreicht wird, wird der Interrupt ausgelöst (hierfür muss für das Debuggen im AVR-Studio &amp;quot;Mask interrupts while stepping&amp;quot; deaktiviert sein, zu finden in Tools -&amp;gt; Options). Mit dem nächsten F11 landen sie in der Interrupt Vektor Tabelle und von dort geht es weiter zu timer_0_overflow. Weitere Tastendrücke von F11 erledigen dann die Ausgabe auf den Port B, das Invertieren des Registers r17 und der Interrupt ist damit behandelt. Nach dem &#039;&#039;&#039;reti&#039;&#039;&#039; macht der Microcontroller genau an der Stelle weiter, an der er vom Interrupt unterbrochen wurde. Und der Timer 0 hat in der Zwischenzeit weitergezählt! Nach exakt weiteren 256 Schritten, vom Auftreten des ersten Overflows an gerechnet, wird der nächste Overflow ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==Wie schnell schaltet denn jetzt der Port?==&lt;br /&gt;
&lt;br /&gt;
Eine berechtigte Frage. Dazu müssen wir etwas rechnen. Keine Angst, es ist nicht schwer, und wer das Prinzip bisher verstanden hat, der sollte keine Schwierigkeiten haben, die Berechnung nachzuvollziehen.&lt;br /&gt;
&lt;br /&gt;
Der Quarzoszillator schwingt mit 4 MHz. Das heißt, in 1 Sekunde werden 4000000 Taktzyklen generiert. Durch die Wahl des Vorteilers von 1 bedeutet das auch, dass der Timer 4000000 mal in der Sekunde erhöht wird. Von einem Overflow zum nächsten muss der Timer 256 Zählvorgänge ausführen. Also werden in 1 Sekunde 4000000 / 256 = 15625 Overflows generiert. Bei jedem Overflow schalten wir die LEDs jeweils in den anderen Zustand. D.h die LEDs blinken mit einer Frequenz von 7812.5 Hz. Das ist zuviel als dass wir es noch sehen könnten.&lt;br /&gt;
&lt;br /&gt;
Was können wir also tun, um diese Blinkfrequenz zu verringern? Im Moment ist unsere einzige Einflussgröße der Vorteiler. Wie sieht die Rechnung aus, wenn wir einen Vorteiler von 1024 wählen?&lt;br /&gt;
&lt;br /&gt;
Wiederrum: Der Systemtakt sei 4 Mhz. Durch den Vorteiler von 1024 werden daraus 4000000 / 1024 = 3906.25 Pulse pro Sekunde für den Timer. Der zählt wiederum 256 Zustände von einem Overflow zum nächsten. 3906.25 / 256 = 15.2587. Und wiederum: Im Overflow werden die LEDs ja abwechselnd ein und ausgeschaltet, also dividieren wir noch durch 2: 15.2587 / 2 = 7.629. Also knapp 7 Hz. Diese Frequenz müsste man schon mit freiem Auge sehen. Die LEDs werden ziemlich schnell vor sich hin blinken.&lt;br /&gt;
&lt;br /&gt;
Reicht diese Verzögerung noch immer nicht, dann haben wir 2 Möglichkeiten:&lt;br /&gt;
* Entweder wir benutzen einen anderen Timer. Timer 1 beispielsweise ist ein 16 Bit Timer. Der Timer zählt also nicht von 0 bis 255 sondern von 0 bis 65535. Bei entsprechender Umarbeitung des Programms und einem Vorteiler von 1024 bedeutet das, dass die LEDs einen Ein/Aus Zyklus in 33 Sekunden absolvieren.&lt;br /&gt;
* Oder wir schalten die LEDs nicht bei jedem Timer Overflow um. Man könnte zum Beispiel in einem Register bis 7 zählen und nur dann, wenn dieses Register 7 erreicht hat, wird&lt;br /&gt;
** das Register wieder auf 0 gesetzt und&lt;br /&gt;
** die LEDs umgeschaltet.&lt;br /&gt;
&lt;br /&gt;
==Timer 0==&lt;br /&gt;
&lt;br /&gt;
Timer 0 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
&lt;br /&gt;
===TCCR0===&lt;br /&gt;
====TCCR - Timer/Counter Control Register====&lt;br /&gt;
{{Byte |TCCR0 |      |      |      |      |      | CS02 | CS01 | CS00 }}&lt;br /&gt;
&lt;br /&gt;
====CS02/CS00 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS02 || CS01 || CS00 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===TIMSK===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TIMSK|      |      |      |      |      |      | OCIE0 | TOIE0 }}&lt;br /&gt;
&lt;br /&gt;
====TOIE0 - Timer 0 Overflow Interrupt Enable====&lt;br /&gt;
Ist dieses Bit gesetzt, so wird beim Auftreten eines Overflows am Timer ein Interrupt ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Anstatt der Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
ist es besser, die Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 1 &amp;lt;&amp;lt; TOIE0&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
zu wählen, da hier unmittelbar aus dem Ladekommando hervorgeht, welche Bedeutung das gesetzte Bit hat. Die vorher inkludierte m8def.inc definiert dazu alles Notwendige.&lt;br /&gt;
&lt;br /&gt;
==Timer 1==&lt;br /&gt;
&lt;br /&gt;
Timer 1 ist ein 16 Bit Timer&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Input Capture&lt;br /&gt;
* 2 Compare Einheiten&lt;br /&gt;
* div. PWM Modi&lt;br /&gt;
&lt;br /&gt;
===TCCR1B===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1B| ICNC1| ICES1|      | WGM13| WGM12| CS12 | CS11 | CS10 }}&lt;br /&gt;
&lt;br /&gt;
====CS12/CS10 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS12 || CS11 || CS10 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====ICES1 - Input Capture Edge Select====&lt;br /&gt;
ICES1 = 0 , falling edge&lt;br /&gt;
ICES1 = 1 , rising edge&lt;br /&gt;
&lt;br /&gt;
====ICNC1 - Input Capture Noise Canceler====&lt;br /&gt;
&lt;br /&gt;
===TCCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1A|COM1A1|COM1A0|COM1B1|COM1B0|FOC1A |FOC1B |WGM11 |WGM10 }}&lt;br /&gt;
&lt;br /&gt;
===OCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===OCR1B===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===ICR1===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK1===&lt;br /&gt;
{{Byte|TIMSK|      |      |TICIE1|OCIE1A|OCIE1B|TOIE1 |      |}}&lt;br /&gt;
&lt;br /&gt;
====TICIE1 - Timer 1 Input Capture Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1A - Timer 1 Output Compare A Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1B - Timer 1 Output Compare B Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====TOIE1 - Timer 1 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Timer 2==&lt;br /&gt;
Timer 2 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Compare Match Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Phasen korrekte PWM&lt;br /&gt;
&lt;br /&gt;
===TCCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR2| FOC2 | WGM20| COM21| COM20| WGM21| CS22 | CS21 | CS20 }}&lt;br /&gt;
&lt;br /&gt;
====WGM21 - Waveform Generator Mode====&lt;br /&gt;
&lt;br /&gt;
Ist diese Option Aktiviert dann wird das Zählregister des Timers (TCNT2) wieder auf 0 gesetzt,&lt;br /&gt;
sobal das Register as Output Compare Register (OCR2) und TCNT2 übereinstimmen.&lt;br /&gt;
Zu beachten ist dabei das wenn das Register kleiner als 255 gestellt ist, wird&lt;br /&gt;
der Timer nicht mehr überschritten und der Interrupt für den Overflow (TIMER2_OVF_vect) nicht mehr ausgelöst.&lt;br /&gt;
Stattdessen gibt es den Interrupt für Compare Match (TIMER2_COMP_vect)&lt;br /&gt;
Die Frequenz für die Interruptauslösung lässt sich dann wie folgt berechnen:&lt;br /&gt;
ISR_Freq = F_CPU : ( Prescaler * ORC2 )&lt;br /&gt;
&lt;br /&gt;
====CS22/CS20 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS22 || CS21 || CS20 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 128&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===OCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK2===&lt;br /&gt;
{{Byte|TIMSK| OCIE2| TOIE2|      |      |      |      |      |      }}&lt;br /&gt;
&lt;br /&gt;
====OCIE2 - Timer 2 Output Compare Interrupt Enable====&lt;br /&gt;
====TOIE2   Timer 2 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Was geht noch mit einem Timer?==&lt;br /&gt;
&lt;br /&gt;
Timer sind sehr universelle Microcontroller Bestandteile. Für weitergehende Studien ist es daher unerlässlich, das entsprechende Datenblatt des Microcontrollers zu studieren. Oft ist es z.&amp;amp;nbsp;B. möglich, dass der Timer bei erreichen von bestimmten Zählerständen einen Ausgabepin von sich aus ein-/aus-/umschaltet. Er erledigt dann das, was wir oben noch mit einem Interrupt gemacht haben, eigenständig komplett in Hardware. Bei einigen Timern ist es möglich, damit eine [[PWM]] (Pulsweiten-Modulation) aufzubauen.&lt;br /&gt;
&lt;br /&gt;
Ein paar der Timermodule lassen sich auch als Counter verwenden. Damit kann man z.&amp;amp;nbsp;B. die Anzahl externer Ereignisse wie Schaltvorgänge eines Inkrementalgebers bestimmen.&lt;br /&gt;
&lt;br /&gt;
Andere bieten die Möglichkeit, über einen externen Uhrenquarz getaktet zu werden (Anwendung z.&amp;amp;nbsp;B. eine &amp;quot;Echtzeituhr&amp;quot; oder als &amp;quot;Weckfunktion&amp;quot; aus einem Standby/Powerdownmodus).&lt;br /&gt;
&lt;br /&gt;
Durch geschickte Umprogrammierung in Echtzeit, lässt sich mit einem Timer eine [[PLL]] aufbauen, die sich fortwährend auf einen Eingangstakt synchronisiert. Damit wird vermieden, dass der Controller ein Signal ständig abpollen muss, sondern das Signale wird per Timer-Interrupt verarbeitet. Massgeblich ist die Messung der aktuellen- und Schätzung der kommenden Flanke mithilfe eines einstellbaren [[Taktteiler]]-verhältnisses.&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.uni-koblenz.de/~physik/informatik/MCU/Timer.pdf Timer/Counter und PWM beim ATMega16 Mikrocontroller] Proseminar von Marcel Jakobs, September 2006 (PDF)&lt;br /&gt;
* [http://frank.circleofcurrent.com/cache/avrtimercalc.htm AVR Timer Calculator]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Speicher|&lt;br /&gt;
zurücklink=AVR-Tutorial: Speicher|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Uhr|&lt;br /&gt;
vorlink=AVR-Tutorial: Uhr}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Timer]]&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;/div&gt;</summary>
		<author><name>2001:A60:13D1:CB01:352D:6309:9D08:7E1F</name></author>
	</entry>
</feed>