Pfad:
Home ==>
Mikrobeginner ==> 4. LED mit Timer
This page in English (external):
Lektion 4: Eine LED blinkt mit dem Timer
Mit dieser Lektion beenden wir die elendig langweiligen Schleifen und lassen die interne
Timer-Hardware die langwierige Timing-Aufgabe vollautomatisch und exakt verrichten.
4.0 Übersicht
- Einführung in die Timer-Hardware
- Hardware, Bauteile, Aufbau
- Timer mit Standardeinstellungen
- Timer im CTC-Modus
- Timer im 128-kHz-Modus
Der im Prozessor eingebaute Zähler (Timer/Counter, TC) ist die am häufigsten benutzte
Hardwarekomponente. Der Timer wird auch bei späteren Lektionen zur Anwendung kommen,
deshalb hier schon mal ein paar Anwendungen, um die LED auf verschiedene Arten blinken zu
lassen.
Unterschiedliche AVR-Typen haben eine unterschiedliche Anzahl Zähler eingebaut. Diese sind
mit Null beginnend durchnummeriert. Bei der Benennung von Timer-Ports beziehen sich 0, 1 oder
2 immer auf die Zählernummer. Der ATtiny13 hat nur einen Zähler, dennoch ist bei
allen Portbenennungen eine Null eingefügt.
4.1.1 Timer
Timer in den AVR sind 8 oder 16 Bit breite Zähleinrichtungen. Sie zählen in der Regel
aufwärts, bei 8 Bit Breite von 0 bis 255, bei 16 Bit Breite von 0 bis 65.535 und starten
danach einfach wieder bei Null. Ihr Zählerstand ist im Port TCNT (8 Bit) bzw. in den beiden
Ports TCNTH und TCNTL (16 Bit) zugänglich. Wird der Zählerport beschrieben, wird der
Zähler auf diesen Stand gesetzt.
4.1.2 Timer-Impulsquellen
Die Möglichkeiten, mit denen der Zähler mit Impulsen versorgt werden kann, sind
vielfältig. Mit dem Kontrollport B des 8-Bit-Timers, TCCRB, wird die Taktquelle des Timers
ausgewählt. Multiplexer bedeutet "adressgesteuerter Umschalter". Drei Bits im
Kontrollregister wählen damit die Signalquelle aus.

Acht verschiedene Quellen stehen zur Auswahl:
# | Bin | Zustand | Taktung |
0 | 000 | Aus | Kein Signal, Zählen abgeschaltet |
1 | 001 | Timer | Prozessortakt |
2 | 010 | Timer | Prozessortakt durch Acht |
3 | 011 | Timer | Prozessortakt durch 64 |
4 | 100 | Timer | Prozessortakt durch 512 |
5 | 101 | Timer | Prozessortakt durch 1.024 |
6 | 110 | Counter | externer Anschluss T, fallende Flanken |
7 | 111 | Counter | externer Anschluss T, steigende Flanken |
Mit den Zeilen
ldi R16,1 ; R16 auf 1
out TCCR0B,R16 ; in Kontrollport B
lässt sich der Timer mit dem Prozessortakt starten, mit
clr R16 ; R16 auf Null
out TCCR0B,R16 ; in Kontrollport B
wird der Timer wieder gestoppt. Mit der Instruktion "OUT" werden alle acht Bits des
angegebenen Ports mit dem Inhalt des angegeben Registers beschrieben.
4.1.3 Timer und Compare-Match
Die ganze Timerei wäre nicht viel wert, wenn wir nun ständig den Timer auf seinen
Zählerstand überwachen müssten, um einen Ablauf mit bestimmter Dauer zu
erreichen. Für diese Aufgabe wurden Vergleicher eingebaut.
In der Regel haben alle Timer zwei Vergleicher, A und B. Mit dem Eintreten des Compare Match
Ereignisses können automatische Vorgänge ausgelöst werden oder der Prozessor
kann unterbrochen werden. Weiteres siehe spätere Lektionen.
4.1.4 Timer im CTC-Modus
Die naheliegendste Anwendung der Vergleicher ist es, den Zähler bei Erreichen des
Compare-Wertes auf Null zu setzen und von vorn beginnen zu lassen. Dies wird als CTC bezeichnet
("Clear timer on compare").
Man beachte, dass der Compare-Match nicht bei sofortiger Gleichheit rücksetzt, sondern
erst mit Eintreten des nächsten Zählimpulses. Das garantiert eine exakt definierte
Länge von Impulsen unabhängig von der physischen Vergleichsgeschwindigkeit. Im
vorliegenden Fall wird das Vergleichsregister auf Neun eingestellt, womit 10 Zählimpulse
Dauer zum CTC führen (Impulse 0 bis 9 = 10 Impulse).
CTC ist bei allen Timern mit dem Compare-Register A möglich. Compare-Register B kann
für andere Zwecke verwendet werden. Manche AVRs verfügen auch noch über ein
weiteres Register, mit dem ein weiterer CTC-Mode möglich ist und die Vergleicher A und B
für andere Aufgaben frei sind.
4.1.5 Ausgänge mit dem Timer manipulieren
Die zweithäufigste Verwendung von Compare-Match ist das Setzen oder Löschen von
Portpins. Damit macht sich der Match außerhalb bemerkbar und es können elektrische
Impulse nahezu beliebiger Dauer an Ausgangspins erzeugt werden. Für den ATtiny13 ist
PB0 für den Vergleicher A festgelegt (Ausgang OC0A), für B PB1 (OC0B).
Zur Verwendung genügt es, den entsprechenden Portpin als Ausgang zu definieren (seinen
Ausgangstreiber einzuschalten, z.B. mit sbi DDRB,DDB0) und mit zwei Kontrollbits das Verhalten
dieses Pins festzulegen. Vier Modi stehen zur Verfügung:
COM0A1 COM0B1 | COM0AO COM0B0 | Funktion OC0A/OC0B |
0 | 0 | Portpin wird nicht beeinflusst |
0 | 1 | Portpin wechselt Polarität bei Compare Match (Torkeln, Toggle) |
1 | 0 | Portpin bei Compare Match auf Null setzen |
1 | 1 | Portpin bei Compare Match auf Eins setzen |
Zur Beachtung: das gilt nur für den Fall, dass der Zähler im normalen Zählmodus
betrieben wird. Für andere Modi passiert was anderes.
Damit stehen für die Blinkerei ganz neue Möglichkeiten zur Verfügung.
Für die Blinker kommt die gleiche Hardware zum Einsatz, wie wir sie schon in Lektion 2
aufgebaut haben.
4.3.1 Funktionsweise
Die einfachste Art, den Blinker zu bauen, ist den Timer bis 255 zählen zu lassen und bei
einem Compare-Match den Ausgang torkeln zu lassen. Damit stellt sich eine Blinkfrequenz von
1.200.000 / 1.024 / 256 / 2 = 2,29 Hz
ein. Das ist schneller als es soll und wäre für eine Uhr ziemlich daneben.
4.3.2 Programm
Hier ist das Programm (Quellcode hier). Es schaltet zuerst den
Portpin PB0 als Ausgang, setzt dann das Compare A Register, versetzt den Ausgang OC0A in den
Toggle-Modus und startet den Timer mit dem durch 1024 geteilten Takt.
;
; *************************************
; * Timer zum Blinken *
; * (C)2016 by www.gsc-elektronic.net *
; *************************************
;
.NOLIST
.INCLUDE "tn13def.inc"
.LIST
;
; ---------- Register -----------------
.def rmp = R16 ; Vielzweckregister
;
; ---------- Timing -------------------
; Interner RC-Oszillator = 9.600.000 Hz
; Clock-Vorteiler CLKPR = 8
; Interner Prozessortakt = 1.200.000 Hz
; TC0-Vorteiler = 1.024
; TC0-Tick = 1.171,875 Hz
; TC0-Durchlauf = 256
; TC0-Durchlauffrequenz = 4,578 Hz
; TC0-Toggle-Frequenz = 2,289 Hz
;
; ---------- Start --------------------
; PB0 als Ausgang
sbi DDRB,DDB0 ; PB0 als Ausgang
; setze Compare Match
ldi rmp,0xFF ; Match bei 255
out OCR0A,rmp ; in Compare Match A
; toggle PB0 bei Compare Match
ldi rmp,1<<COM0A0 ; Toggle Mode
out TCCR0A,rmp ; in Kontrollregister A
; Timer starten
ldi rmp,(1<<CS02)|(1<<CS00) ; Prescaler 1024
out TCCR0B,rmp ; in Kontrollregister B
Schleife:
rjmp Schleife
Die Instruktion "OUT" beschreibt alle acht Bits in einem Port
gleichzeitig aus einem Register.
Nachdem die Hardware gestartet ist, wird der Prozessor nicht mehr benötigt und geht in
eine unendliche Schleife (Schleife: rjmp Schleife).
Eine Besonderheit ist noch zu klären, die Formulierung "ldi rmp,1<<COM0A0".
Damit wird das Portbit COM0A0 im Port TCCR0A auf Eins gesetzt. COM0A0 ist das Bit 6 in diesem
Port. Eigentlich wäre zu schreiben: "ldi rmp,0b01000000" (0b startet eine
Binärzahl). Spätestens eine Stunde nachdem wir das geschrieben haben, will uns nicht
mehr einfallen, was "01000000" nun eigentlich heißt (dass es sich um das Bit
COM0A0 handelt). Deshalb die Formulierung "ldi rmp,1<<COM0A0". Sie bedeutet
- Nimm eine Eins, also 0b00000001,
- schiebe diese COM0A0-mal nach links (<<),
- weil COM0A0 in der Datei "tn13def.inc" mit ".equ COM0A0 = 6" definiert
ist, wird sechs mal nach links geschoben (<< bedeutet Linksschieben) und dabei von
rechts eine binäre Null hineingeschoben,
- also wird aus 0b00000001 schließlich 0b01000000.
Es ist wichtig zu verstehen, dass die Schieberei hierbei nur vom Assembler beim Übersetzen
des Programmcodes vollzogen wird. << hat mit der Schiebeinstruktion des Prozessors nichts
zu tun. Die gibt es nämlich auch, sie heißt "LSL"
(Logical Shift Left) und braucht als Parameter ein Register, das nach Links geschoben werden
soll.
In der Zeile "ldi rmp,(1<<CS02)|(1<<CS00)" werden gleichzeitig zwei Bits
auf Eins gesetzt. Weil CS02 in der def.inc mit 2 definiert ist, CS00 aber mit Null, kommt bei
den beiden Klammerausdrücken einerseits 0b00000100 (eine 1 zweimal links geschoben) und
andererseits 0b00000001 (eine 1 keinmal links geschoben) heraus. Das Zeichen | sagt dem
Assembler, die beiden Ergebnisse binär mit ODER zu verknüpfen, woraus dann 0b00000101
wird. Auch hier hat das nichts mit dem Prozessor zu tun, dessen
ODER-Verknüpfung zweier Register heißt "OR". Das | macht allein der
Assembler beim Übersetzen in Maschinencode.
Die Zeichen << und | sind mathematische Operatoren des Assemblers, wovon es noch viele
weitere gibt. Wie z. B. +, -, * und /. Alles nur Mitteilungen an den Assembler, der
Prozessor kriegt davon nichts mit.
4.3.3 Simulieren des Timers in diesem Modus
Die nachfolgende Simulation verwendet den Simulator
avr_sim, um den Timer
in diesem Modus nachzuahmen.
Nach dem Initiieren ist der Timer TC0 in diesem Zustand:
- Der Timer-Modus ist "Normales Aufwärtszählen" ("normal
counting").
- Der Ausgangspin PB0 torkelt ("toggles") wenn der Timer den im
Vergleichsregister A eingestellten Wert erreicht und der nächste Zählimpuls
eintritt.
- Vergleichswert A ("Compare A") und der Höchstwert ("TOP")
sind auf 255 gesetzt.
- Der Vorteiler ("prescaler") teilt die Taktfrequenz des Prozessors durch
1,024, der Timer läuft also mit 1.171,875 Hz Taktfrequenz.
Nach der Initiierung ist das Richtungsbit DDB0 des Ports B Eins. Das bedeutet, dass der
Ausgabepin PB0 dem Zustand des Portregisters PORTB0 folgt, auf niedriges Potential
geht und die LED, die mit der Anode an der positiven Betriebsspannung liegt,
eingeschaltet ist.
Nun zählt der Timer. Jeder Einzelschritt erhöht den Vorteilerwert. Erreicht
der Vorteiler den Wert 1.024 wird das Portregister TCNT um Eins erhöht und der
Vorteiler startet bei Null neu.
Nach 256 * 1.024 = 262.144 Taktzyklen erreicht der Timer den Vergleichswert
im Portregister "Compare A" und, wenn der nächste Taktimpuls
eintritt, tritt ein Compare Match ein. Da der Timer damit auch seinen
Höchstwert ("TOP") überschreitet, beginnt das
Zählregister TCNT dann wieder bei Null (Zählerüberlauf).
Das Überschreiten des Compare-Match-A-Wertes lässt auch das Portbit
PORTB0 torkeln, der Ausgangspin PB0 wird jetzt high und die LED wird ausgeschaltet.
Diese Umschaltung erfolgt durch den Timer automatisch, dazu ist keinerlei
weitere Prozessoraktivität nötig.
Der Simulator hat zu diesem Zeitpunkt 131.079 Instruktionen ausgeführt,
die meisten davon relative Sprünge RJMP, die zu ihrer Ausführung
zwei Taktzyklen brauchen. 218,46 ms sind seit dem Start vergangen. Die
Stoppuhr ("Stopwatch"), die nach der Initiierung zurückgesetzt
worden ist, zeigt 218,452 ms an, was mit unseren vorberechneten
4,58 Timerzyklen pro Sekunde und einer Blinkfrequenz von 2,29 Hz
übereinstimmt.
4.3.4 Vor- und Nachteile
Der Vorteil dieser Lösung im Vergleich zur Verzögerungsschleifen-Lösung in
Lektion 3 ist, dass der Prozessor nicht mit Unsinn wie dem Abzählen von Schleifen
beschäftigt wird. Der Zählvorgang läuft im Timer ab, der Schaltvorgang am
Portpin wird vom Vergleicher erledigt. Der Prozessor könnte sich um andere Aufgaben
kümmern, ohne dass die Zählerei und Schalterei irgendwie gestört würde.
Der Nachteil dieser Lösung ist, dass es mit der Sekundenblinkerei nicht hinhaut, das
Blinken ist doppelt schneller. Ursache ist, dass das Teilen des Prozessortakts durch 1.024
und durch 256 immer krumme Werte liefert (es sei denn, der Prozessor liefe mit 2,4576 MHz
Takt, wofür wir einen externen Taktgeber bräuchten) und weil der Takt 1,2 MHz
zu schnell ist und die Vorteilerei zu groß für eine Sekunde ist. Daher müssen
andere Lösungen her, bei denen der Prozessortakt entscheidend verlangsamt wird.
4.4.1 Funktionsweise
Prozessortakt verlangsamen
Alle Tiny- und Mega-Typen des AVR neueren Datums haben eine Einrichtung, die das Teilen des
Taktes interner und externer Oszillatoren ermöglichen, bevor diese auf den Prozessor und
alle andere interne Hardware losgelassen werden. Als Teilerfaktoren stehen Zweierpotenzen von
1 bis 256 zur Verfügung. Bei 9,6 MHz internem RC-Oszillatortakt entspricht das
9,6 MHz bis 37,5 kHz Prozessortakt.
Ohne es zu wissen, haben wir diesen Vorteiler bereits praktisch verwendet. Er ist nämlich
werksseitig auf das Teilen durch Acht eingestellt. Das können wir durch Löschen der
CKDIV8-Fuse im Prozessor aufheben (siehe
hier, wobei der Prozessor dann
mit 9,6 MHz Takt läuft (Achtung! Bei niedrigen Betriebsspannungen schafft der
langsamere Typ ATtiny13V diesen Takt nicht! Die Fuse kann dann nur mit erhöhter
Betriebsspannung wieder gesetzt werden!).
Um nicht nur 1 oder 8 als Teilerfaktoren verwenden zu können, muss auf den Port CLKPR
zugegriffen werden. Damit das nicht aus Versehen passiert, gibt es eine bestimmte Prozedur, um
das zu erledigen. Zuerst muss das Bit CLKPCE im Port CLKPR auf Eins gesetzt werden (alle
anderen Bits MÜSSEN beim Schreiben Null sein). Sofort danach werden die CLKPS-Bits
gesetzt (mit CLKPCE auf Null). Kurze Zeit später ist das Schreibzugriffsfenster wieder zu.
Das Setzen von 32 als Vorteiler erledigt man mit folgendem Programmcode:
ldi R16,1<<CLKPCE ; Program Enable Bit auf Eins
out CLKPR,R16 ; in Port CLKPR schreiben
ldi R16,(1<<CLKPS2)|(1<<CLKPS0) ; Teiler = 32
out CLKPR,R16 ; in Port CLKPR schreiben
Nun läuft der Prozessor mit 9,6 MHz / 32 = 300 kHz Takt. Aber Obacht! Beim
Programmieren mittels ISP muss jetzt auch der Takt niedriger (< 75 kHz) angesetzt
werden, sonst meldet der Programmieradapter einen Fehler.
Auf diese Weise wird der Prozessor zur lahmen Ente gemacht. Das macht man aber nur, wenn es
denn nötig ist, wenn man z. B. Strom sparen will. Der Strombedarf ist nämlich
etwa linear mit der Taktfrequenz, wie der nebenstehende Auszug aus dem Device Databook zeigt.
Mit der Herabsetzung der Taktfrequenz auf 300 kHz hat sich der Strombedarf des Prozessors
von 1 bis 2 mA auf ganze 0,3 mA erniedrigt. Das tut einer Batterie oder einem Akku
ganz gut und verfünffacht seine Haltbarkeit (als wenn es sonst nichts anderes anzutreiben
gäbe).
Prozessor schlafen legen
Eine wirksame Methode zum Stromsparen ist es, den Prozessor nicht in "Schleife: rjmp
Schleife" zu schicken, wenn er nicht gebraucht wird, sondern ihn ganz schlafen zu
legen. Dann stellt er das Lesen aus dem Flashspeicher, das Dekodieren und Ausführen von
Instruktionen ganz ein. Das nennt sich Idle und bedeutet so viel wie Leerlauf.
Auch dieser Zustand muss erst eingeschaltet werden. Er lässt sich einschalten, indem das
Sleep-Enable-Bit im Port MCUCR (Micro controler universal control register) gesetzt wird und
die Sleep-Instruktion ausgeführt wird. Also etwa so:
ldi R16,1<<SE ; Schlafen ermöglichen
out MCUCR,R16 ; in Kontrollregister
sleep ; schlafen legen
In unserem Fall weckt nichts mehr den Prozessor auf, nur das Programmiergerät mit einem
Reset. Es gibt aber auch andere Weckmechanismen, die kommen aber erst später zum Einsatz.
Timer im CTC-Modus
Der Vergleicher A im Timer kann noch für eine weitere Betriebsart des Timers verwendet
werden, nämlich den CTC-Modus. In unserem Fall kann man diese Betriebsart verwenden, um
krumme, d. h. nicht-zweierpotenzige, aber ganzzahlige Teilerverhältnisse zu
erreichen. Damit kommen wir näher an die Sekunde heran als im vorherigen Beispiel.
Das hier sind alle Betriebsmodi des Timers. Der CTC-Modus ist einstellbar, indem das WGM1-Bit
auf 1 gesetzt wird. Der höchste Wert des Timers (TOP) ist die im Port OCRA gespeicherte
Zahl. Danach setzt der Timer wieder zurück.
Die drei WGM-Bits WGM02, WGM01 und WGM00 des Timers 0 sind - unlogischerweise - in den zwei
Ports TCCR0A und TCCR0B verteilt. Uns ficht das nicht an, da wir nur WGM01 auf Eins setzen
müssen. Da dazu auch noch das Bit COM0A0 im TCCR0A zu setzen ist, kommt wieder das
(1<<WGM01)|(1<<COM0A0) zum Einsatz.
4.4.2 Programm
Das riesige Programm ist hier gelistet (Quellcode hier).
Zuerst wird die Taktfrequenz des Prozessors verstellt, dann das Portbit PB0 als Ausgang
geschaltet, dann der Timer programmiert und zuletzt der Prozessor schlafen gelegt. Für
den Fall, dass er aufwachen sollte, ist noch das erneute Schlafenlegen programmiert.
;
; *************************************
; * LED-Blinker mit Timer *
; * (C)2016 by www.gsc-elektronic.net *
; *************************************
;
.NOLIST
.INCLUDE "tn13def.inc"
.NOLIST
;
; ------ Register ---------------------
.def rmp = R16 ; Vielzweckregister
;
; ------ Timing -----------------------
; Interner RC-Oszillator = 9.600.000 Hz
; Vorteiler CLKPR = 32
; Taktfrequenz Prozessor = 300.000 Hz
; Vorteiler TC0 = 1.024
; Timer-Tick TC0 = 292,97 Hz
; Timer-CTC-Teiler = 146
; Taktfrequenz CTC-OC0A = 2,006 Hz
; Frequenz CTC-Toggle = 1,003 Hz
;
; ------ Konstanten -------------------
.equ fRC = 9600000 ; Prozessortakt
.equ pClk = 32 ; Clock-Prescaler
.equ pTC0 = 1024 ; TC0-Prescaler
.equ pCtc = fRC / pClk / pTC0 / 2 ; Teiler
.equ cCtc = pCtc - 1 ; CTC-Wert
;
; ------ Programmstart ----------------
Start:
; Die Taktfrequenz des Prozessors herabsetzen
ldi rmp,1<<CLKPCE ; CLKPR-Schreiben ermoeglichen
out CLKPR,rmp ; an CLKPR-Port
ldi rmp,(1<<CLKPS2) | (1<<CLKPS0) ; Teiler = 32
out CLKPR,rmp ; an CLKPR-Port6
; PB0 als Ausgang
sbi DDRB,DDB0 ; Datenrichtung Ausgang
; Den Timer programmieren und starten
ldi rmp,cCtc ; Den Vergleicherwert ...
out OCR0A,rmp ; ... in das Compare-Register A schreiben
ldi rmp,(1<<COM0A0) | (1<<WGM01) ; Toggle OC0A, CTC-Mode
out TCCR0A,rmp ; in Kontrollregister A
ldi rmp,(1<<CS02) | (1<<CS00) ; Vorteiler 1024
out TCCR0B,rmp ; in Kontrollregister B
;
ldi rmp,1<<SE ; Schlafmodus Idle
out MCUCR,rmp ; in Kontrollregister
Aufwachen:
sleep ; Prozessor schlafen legen
nop ; nach dem Aufwachen
rjmp Aufwachen ; wieder schlafen legen
;
; Ende Quellcode
;
Nicht vergessen: der Prozessor arbeitet ab jetzt mit 300 kHz Takt, die ISP-Frequenz muss
für das erneute Ansprechen mit dem Programmiergerät herabgesetzt werden.
4.4.3 Simulieren des Timerbetriebs im CTC-Modus
Wieder simulieren wir den Timer mit
avr_sim.
Das ist der Zustand nach der Initiierung. Die Taktfrequenz des Prozessors
wurde durch das Schreiben in das CLKPR-Portregister auf 300 kHz herabgesetzt.
Der Timer ist im CTC-Modus, mit dem Vergleichsregister Compare A als TOP-Wert.
Der Pin PB0 torkelt bei Überschreiten des TOP-Werts.
Das ist der Zustand wenn das erste Compare-Match-Ereignis erreicht ist: 498 ms
sind vorbei und das Portbit PB0 ist gesetzt, was die LED ausschaltet.
Das zweite Compare-Match-Ereignis wird nach 996.69 ms erreicht. Das ist sehr nah
an der Sekunde, aber nicht genau eine Sekunde.
4.4.4 Vor- und Nachteile
Der Strombedarf der Schaltung ist jetzt stark herabgesetzt, durch Takterniedrigung auf
300 kHz und Schlafmodus. Weniger geht nur noch, wenn wir die Betriebsspannung von 4,8
auf z. B. 3,3 V herabsetzen.
Nachteilig ist, dass wir noch immer nicht genau die eine Sekunde getroffen haben. Die
Abweichung ist zwar viel geringer als die Abweichung des internen RC-Generators vom Soll-Wert
(+/-10%), aber für eine Uhr selbst dann nicht zu gebrauchen, wenn wir einen externen
Quarzoszillator anschließen würden.
Der ATtiny13 verfügt noch über einen weiteren internen RC-Oszillator, der per Fuse
als Taktquelle ausgewählt werden kann. Er hat eine Frequenz von 128 kHz, die per
CLKPR weiter geteilt werden kann, bis herunter auf 500 Hz. Tun Sie das nicht, es sei denn,
sie haben ein Programmiergerät mit weniger als 125 Hz Taktfrequenz. Das AVRISPmkII
kann 50,1 Hz, wäre also für diese Aufgabe noch geeignet.
4.5.1 Funktionsweise
Mit 128 kHz Taktfrequenz des Prozessors und des Timers muss für eine
CTC-Toggle-Frequenz insgesamt durch 64.000 geteilt werden. 1.024 als Timer-Vorteiler führt
bereits zu krummen 62,5 Hz. Mit 512 als Vorteiler muss der CTC auf 250 eingestellt werden,
damit genau 2,00000 Hz Toggle-Frequenz herauskommen. Das ist mit dem 8-Bit-Timer
im ATtiny13 realisierbar, der ja bis 255 zählen kann.
4.5.2 Programm
Das Programm ähnelt dem vorherigen, nur der Timer-Vorteiler und der CTC-Wert ist anders
(Quellcode hier).
Bevor wir das programmieren, müssen wir die 32 im CLKPR aus dem vorherigen Experiment
wieder loswerden. Dazu schreiben wir im vorherigen Program die Zeile
"ldi rmp,(1<CLKPS2)|(1<CLKPS0)" in "ldi rmp,(1<CLKPS2)|(1<CLKPS0)"
um, assemblieren und programmieren das Ergebnis in den Chip. Nun ist der CLKPR wieder
"normal" und es kann das folgende programmiert werden. Wir können dies aber auch
lassen und stattdessen die CKDIV8-Fuse vorübergehend setzen (siehe unten).
;
; ****************************************
; * Blink mit Timer, RC-Osz. mit 128 kHz *
; * (C)2016 by www.gsc-elektronic.net *
; ****************************************
;
.NOLIST
.INCLUDE "tn13def.inc"
.LIST
;
; ------- Register -----------------------
.def rmp = R16 ; Vielzweckregister
;
; ------- Timing -------------------------
; Interner RC-Oszillator = 128.000 Hz
; Clock-Vorteiler CLKPR = 1
; Interne Taktfrequenz = 128.000 Hz
; TC0-Vorteiler = 256
; TC0-Timertick = 500 Hz
; TC0-CTC-Teiler = 250
; TC0-Togglefrequenz = 1 Hz
;
; --------- Konstanten -------------------
.equ cCtc = 250-1
;
; --------- Programm ---------------------
; PB0 als Ausgang
sbi DDRB,DDB0 ; Portbit als Ausgang
; Timer Compare-Match A auf 250
ldi rmp,cCtc ; Match-A-Wert
out OCR0A,rmp ; in Match-Register A
; Timer als CTC und Toggle Ausgang A
ldi rmp,(1<<COM0A0)|(1<<WGM01) ; Toggle und CTC
out TCCR0A,rmp ; in Kontrollregister A
ldi rmp,1<<CS02 ; Vorteiler auf 256
out TCCR0B,rmp ; in Kontrollregister B
; Schlafen ermoeglichen
ldi rmp,1<<SE
out MCUCR,rmp
; Schlafschleife
Schleife:
sleep ; schlafen legen
nop ; nach Aufwachen
rjmp Schleife
;
; Ende Quellcode
;
Programmiert man das in den Tiny, blinkt es hektisch, da der Takt noch bei 1,2 MHz liegt.
Jetzt müssen wir den Takt auf den internen 128 kHz-Oszillator einzustellen. Dazu
wird in der Fuses-Abteilung der Programmiertools der 128 kHz-Oszillator ausgewählt
und der Haken bei der CKDIV8-Fuse entfernt. Das ganze geht mit dem Button "Program"
an das Programmiergerät und hat hoffentlich das taktvolle Ein-Sekunden-Blinken der LED
zur Folge.
4.5.3 Simulation des Timerbetriebs bei 128 kHz Takt
Simulation mit
avr_sim
ergibt Folgendes.
Nach dem Init mit einer Taktfrequenz von 128 kHz sind 62,5 µs vergangen.
Der Timer ist im CTC-Modus mit dem Compare-Register A als TOP-Wert.
Nachdem der erste Compare Match auftrat sieht die Simulation so aus:
Die simulierten Zeiten sind ziemlich genau.
Alles ist korrekt beim zweiten Compare Match.
4.5.4 Vor- und Nachteile
Jetzt stimmt das Teilerverhältnis zwar theoretisch ganz genau, über die Genauigkeit
des 128 kHz-Oszillators schweigt sich ATMEL in seinen Datenblättern aber völlig
aus. Um einen externen Quarzoszillator kommen wir also bei einer Uhr nicht herum. Immerhin hat
die ganze komplizierte Timing-Mimik nun einen Stromverbrauch, der bei einem Fünfzigstel
der LED liegt.
©2016-2018 by http://www.gsc-elektronic.net