Path:
Home =>
AVR-Überblick =>
Zeitschleifen => 16-Bit-Doppelregister
(This page in English:
)
Zeitschleife mit 16-Bit-Doppelregister in AVR Assembler
Hier wird eine 16-Bit-Zeitschleife mit einem Doppelregister erklärt. Mit dieser
können Verzögerungen um ca. eine halbe Sekunde realisiert werden. Damit
wird eine Blinkschaltung mit einer LED realisiert.
Code einer 16-Bit-Schleife
Eine Zeitschleife mit einem 16-Bit-Doppelregister sieht in Assembler
folgendermaßen aus:
.equ c1 = 50000 ; Anzahl Durchläufe der Schleife
ldi R25,HIGH(c1) ; Lade MSB-Register mit Schleifenwert
ldi R24,LOW(c1) ; Lade LSB-Register mit Schleifenwert
Loop: ; Schleifenbeginn
sbiw R24,1 ; Doppelregisterwert um Eins verringern
brne Loop ; wenn nicht Null dann wieder Schleifenbeginn
Die Konstante c1 gibt wieder die Anzahl Schleifendurchläufe direkt an.
Da in ein 16-Bit-Register Zahlen bis 65535 passen, ist die Schleife 256 mal
leistungsfähiger als ein einzelnes 8-Bit-Register.
Die Instruktion "SBIW R24,1" verringert das Doppelregister wortweise, d.h. nicht
nur der Inhalt von R24 wird um eins verringert, bei einem Unterlauf von R24 wird
auch das nächsthöhere Register R25 um Eins verringert.
Das Doppelregister aus R24 und R25 (besser als R25:R24 benannt) eignet sich für
solche Schleifen besonders gut, weil die Doppelregister X (R27:R26), Y (R29:R28) und
Z (R31:R30) neben den 16-Bit-Operationen ADIW und SBIW auch noch andere Instruktionen
kennen, und daher für den schnöden Zweck einer Schleife zu schade sind und
R25:R24 eben nur ADIW und SBIW können.
Prozessortakte
Die Anzahl Prozessortakte, die die einzelnen Instruktionen benötigen, steht wieder
in den Datenbüchern der AVRs. Demnach ergibt sich für die 16-Bit-Schleife
folgendes Bild:
.equ c1 = 50000 ; 0 Takte, macht der Assembler alleine
ldi R25,HIGH(c1) ; 1 Takt
ldi R24,LOW(c1) ; 1 Takt
Loop: ; Schleifenbeginn
sbiw R24,1 ; 2 Takte
brne Loop ; 2 Takte wenn nicht Null, 1 Takt bei Null
Damit setzt sich die Anzahl Takte folgendermaßen zusammen:
- Laden: 2 Takte, Anzahl Durchläufe: 1 mal
- Schleife mit Verzweigung an den Schleifenbeginn: 4 Takte, Anzahl Durchläufe:
c1 - 1 mal
- Schleife ohne Verzweigung an den Schleifenbeginn: 3 Takte, Anzahl Durchläufe:
1 mal
Damit ergibt sich die Anzahl Takte nt zu:
nt = 2 + 4*(c1-1) + 3
oder mit aufgelöster Klammer zu:
nt = 2 + 4*c1 - 4 + 3
oder noch einfacher zu:
nt = 4*c1 + 1
Zeitverzögerung
Die Maximalzahl an Takten ergibt sich, wenn c1 zu Beginn auf 0 gesetzt wird, dann wird
die Schleife 65536 mal durchlaufen. Maximal sind also 4*65536+1 = 262145 Takte
Verzögerung möglich. Mit der Anzahl Prozessortakte von oben (c1=50000,
nc=4*c1+1) und 1,2 MHz Takt ergibt sich eine Verzögerung von 166,7 ms.
Variable Zeitverzögerungen unterschiedlicher Länge sind manchmal nötig.
Dies kann z.B. der Fall sein, wenn die gleiche Software bei verschiedenen Taktfrequenzen
laufen soll. Dann sollte die Software so flexibel gestrickt sein, dass nur die
Taktfrequenz geändert wird und sich die Zeitschleifen automatisch anpassen. So ein
Stück Software ist im Folgenden gezeigt. Zwei verschiedene Zeitverzögerungen
sind als Rechenbeispiele angegeben (1 ms, 100 ms).
;
; Verzoegerung 16-Bit mit variabler Dauer
;
.include "tn13def.inc"
;
; Hardware-abhaengige Konstante
;
.equ fc = 1200000 ; Prozessortakt (default)
;
; Meine Konstante
;
.equ fck = fc / 1000 ; Taktfrequenz in kHz
;
; Verzoegerungsroutine
;
Delay1ms: ; 1 ms Routine
.equ c1ms = (1000*fck)/4000 - 1 ; Konstante fuer 1 ms
ldi R25,HIGH(c1ms) ; lade Zaehler
ldi R24,LOW(c1ms)
rjmp delay
;
Delay100ms: ; 100 ms Routine
.equ c100ms = (100*fck)/4 - 1 ; Konstante fuer 100 ms
ldi R25,HIGH(c100ms) ; lade Zaehler
ldi R24,LOW(c100ms)
rjmp delay
;
; Verzoederungsschleife, erwartet Konstante in R25:R24
;
Delay:
sbiw R24,1 ; herunter zaehlen
brne Delay ; zaehle bis Null
nop ; zusaetzliche Verzoegerung
Hinweise: Die Konstanten c1ms und c100ms werden auf unterschiedliche Weise berechnet,
um bei der Ganzzahlen-Verarbeitung durch den Assembler einerseits zu große
Rundungsfehler und andererseits Überläufe zu vermeiden.
Verlängerung!
Mit folgendem Trick können Sie wieder etwas Verlängerung herausholen:
.equ c1 = 0 ; 0 Takte, macht der Assembler alleine
ldi R25,HIGH(c1) ; 1 Takt
ldi R24,LOW(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
nop ; tue nichts, 1 Takt
sbiw R24 ; 2 Takte
brne Loop ; 2 Takte wenn nicht Null, 1 Takt bei Null
Jeder Schleifendurchlauf (bis auf den letzten) braucht jetzt zehn Takte und es gelten
folgende Formeln:
nc = 2 + 10*(c1 - 1) + 9
oder
nc = 10 * c1 + 1
Maximal sind jetzt 655361 Takte Verzögerung möglich
Das Blinkprogramm
Damit sind wir beim beliebten "Hello World" für AVRs: der im Sekundenrhytmus
blinkenden LED an einem AVR-Port. Die Hardware, die es dazu braucht, ist bescheiden.
Die Software steht da:
.inc "tn13def.inc" ; für einen ATtiny13
.equ c1 = 60000 ; Bestimmt die Blinkfrequenz
sbi DDRB,0 ; Portbit ist Ausgang
Loop:
sbi PORTB,0 ; Portbit auf high
ldi R25,HIGH(c1)
ldi R24,LOW(c1)
Loop1:
nop
nop
nop
nop
nop
sbiw R24,1
brne Loop1
cbi PORTB,0 ; Portbit auf low
ldi R25,HIGH(c1)
ldi R24,LOW(c1)
Loop2:
nop
nop
nop
nop
nop
sbiw R24,1
brne Loop2
rjmp Loop
Gut blink!
To the top of that page
©2009 by http://www.avr-asm-tutorial.net