Path:
Home =>
AVR-Überblick =>
Zeitschleifen => 8-Bit-Register
(This page in English:
)
Zeitschleife mit 8-Bit-Register in AVR Assembler
Hier wird eine 8-Bit-Zeitschleife erklärt. Wenn Sie das alles schon wissen,
blättern Sie es trotzdem kurz durch. Die Zeitberechnungen und die Taktfrequenzen
könnten einiges Neues bringen, das bei den etwas komplizierteren Zeitschleifen
behilflich sein könnte.
Code einer 8-Bit-Schleife
Eine Zeitschleife mit einem 8-Bit-Register sieht in Assembler folgendermaßen aus:
.equ c1 = 200 ; Anzahl Durchläufe der Schleife
ldi R16,c1 ; Lade Register mit Schleifenwert
Loop: ; Schleifenbeginn
dec R16 ; Registerwert um Eins verringern
brne Loop ; wenn nicht Null dann Schleifenbeginn
Praktischerweise gibt die Konstante c1 die Anzahl Schleifendurchläufe direkt an.
Mit ihr kann die Anzahl der Durchläufe und damit die Verzögerung variiert
werden. Da in ein 8-Bit-Register nur Zahlen bis 255 passen, ist die
Leistungsfähigkeit arg eng beschränkt.
Prozessortakte
Für die Zeitverzögerung mit einer solchen Schleife sind zwei Größen
maßgebend:
- die Anzahl Prozessortakte, die die Schleife benötigt, und
- die Zeitdauer eines Prozessortakts.
Die Anzahl Prozessortakte, die die einzelnen Instruktionen benötigen, stehen in
den Datenbüchern der AVRs. Und zwar ziemlich weit hinten, unter "Instruction Set
Summary", in der Spalte "#Clocks". Demnach ergibt sich folgendes Bild:
.equ c1 = 200 ; 0 Takte, macht der Assembler alleine
ldi R16,c1 ; 1 Takt
Loop: ; Schleifenbeginn
dec R16 ; 1 Takt
brne Loop ; 2 Takte wenn nicht Null, 1 Takt bei Null
Damit setzt sich die Anzahl Takte folgendermaßen zusammen:
- Laden: 1 Takt, Anzahl Durchläufe: 1 mal
- Schleife mit Verzweigung an den Schleifenbeginn: 3 Takte, Anzahl Durchläufe:
c1 - 1 mal
- Schleife ohne Verzweigung an den Schleifenbeginn: 2 Takte, Anzahl Durchläufe:
1 mal
Damit ergibt sich die Anzahl Takte nt zu:
nt = 1 + 3*(c1-1) + 2
oder mit aufgelöster Klammer zu:
nt = 1 + 3*c1 - 3 + 2
oder halt noch einfacher zu:
nt = 3*c1
Jetzt haben wir die Anzahl Takte.
Taktfrequenz des AVR
Die Dauer eines Takts ergibt sich aus der Taktfrequenz
des AVR. Die ist gar nicht so einfach zu ermitteln, weil es so viele Möglichkeiten
gibt, sie auszuwählen oder zu verstellen:
- AVRs ohne interne Oszillatoren: diese brauchen entweder
- einen externen Quarz,
- einen externen Keramikresonator, oder
- einen externen Oszillator
Die Taktfrequenz wird in diesem Fall von den externen Komponenten bestimmt.
- AVRs mit einem oder mehreren internen Oszillatoren: diese haben eine voreingestellte
Taktfrequenz, die im Kapitel "System Clock and Clock Options" bzw. im Unterkapitel
"Default Clock Source" steht. Jeder AVR-Typ hat da so seine besondere Vorliebe.
- AVRs mit internen RC-Oszillatoren bieten ferner die Möglichkeit, diesen zu
verstellen. Dazu werden Werte in den Port OSCCAL geschrieben. Bei älteren AVR
geschieht das durch den Programmierer, bei moderneren schreibt ein automatischer
Mechanismus den OSCCAL-Wert zu Beginn in den Port. Auch die Automatik benötigt
den Handeingriff, wenn höhere Genauigkeit gefordert ist und der AVR abseits der
Spannung oder Betriebstemperatur betrieben wird, für die er kalibriert ist (beim
ATtiny13 z.B. 3 V und 25°C).
- Im Kapitel "System Clock and Clock Options" wird auch erklärt, wie man durch
Verstellen von Fuses
- zwischen internen und externen Taktquellen auswählt,
- einen internen Vorteiler zwischen Taktquelle und Prozessortakt schalten kann
(Clock Prescaler, siehe unten),
- eine Wartezeit beim Start des Prozessors einfügt, bis der Oszillator stabil
schwingt ("Delay from Reset").
Die Fuses werden mittels Programmiergerät eingestellt. Obacht! Beim Verstellen
von Fuses, z.B. auf eine externe Taktquelle, muss diese auch angeschlossen sein. Sonst
verabschiedet sich der Prozessor absolut taktlos vom Programmiergerät und gibt
diesem keine sinnvollen Antworten mehr.
- Um das Publikum zu verwirren, haben einige AVR noch einen Vorteiler für den
Prozessortakt (Clock Prescaler). Dieser lässt sich entweder per Fuse (siehe oben)
auf 1 oder 8 einstellen, bei manchen AVR aber auch per Software auf Teilerwerte von
1, 2, 4, 8, bis 256 einstellen (Port CLKPR).
Haben Sie aus all dem Durcheinander jetzt herausgefunden, mit wieviel MHz der AVR nun
eigentlich läuft (fc), dann ergibt sich die Dauer eines Prozessortakts (tc) zu:
tc [µs] = 1 / fc [MHz]
Bei 1,2 MHz Takt (ATtiny13, interner RC-Oszillator mit 9,6 MHz, CLKPR = 8) sind das
z.B. 0,83 µs. Die restlichen Stellen können Sie getrost vergessen, der
interne RC-Oszillator ist so arg ungenau, dass weitere Stellen eher dem Glauben an
Zauberei ähneln.
Zeitverzögerung
Mit der Anzahl Prozessortakte von oben (nc=3*c1, c1=200, nc=600) und 1,2 MHz
Takt ergibt sich eine Verzögerung von 500 µs. Mit maximal
640 µs ist die Maximalbegrenzung dieser Konstruktion erreicht.
Verlängerung!
Mit folgendem Trick können Sie noch etwas Verlängerung herausholen:
.equ c1 = 200 ; 0 Takte, macht der Assembler alleine
ldi R16,c1 ; 1 Takt
Loop: ; Schleifenbeginn
nop ; tue nichts, 1 Takt
nop ; tue nichts, 1 Takt
nop ; tue nichts, 1 Takt
nop ; tue nichts, 1 Takt
nop ; tue nichts, 1 Takt
dec R16 ; 1 Takt
brne Loop ; 2 Takte wenn nicht Null, 1 Takt bei Null
Jetzt braucht jeder Schleifendurchlauf (bis auf den letzten) acht Takte und es gelten
folgende Formeln:
nc = 1 + 8*(c1 - 1) + 7
oder
nc = 8 * c1
Das verlängert die 8-Bit-Registerschleife immerhin auf 256 * 8 = 2048 Takte oder
- bei 1,2 MHz - auf ganze 1,7 ms.
Das Summprogramm
Immer noch nicht für die Blink-LED geeignet, aber immerhin für ein angenehmes
Brummen mit 586 Hz im Lautsprecher. Schließen Sie einen Lautsprecher an Port
B, Bit 0, an, fairerweise über einen Elko von einigen µF, und lassen Sie
das folgende Programm auf den ATtiny13 los:
.inc "tn13def.inc" ; für einen ATtiny13
.equ c1 = 0 ; Bestimmt die Tonhöhe
sbi DDRB,0 ; Portbit ist Ausgang
Loop:
sbi PORTB,0 ; Portbit auf high
ldi R16,c1
Loop1:
nop
nop
nop
nop
nop
dec R16
brne Loop1
cbi PORTB,0 ; Portbit auf low
ldi R16,c1
Loop2:
nop
nop
nop
nop
nop
dec R16
brne Loop2
rjmp Loop
Gut brumm!
To the top of that page
©2009 by http://www.avr-asm-tutorial.net