Path: Home => AVR-Überblick => Zeitschleifen => 16-Bit-Doppelregister
Zeitschleife

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:
  1. Laden: 2 Takte, Anzahl Durchläufe: 1 mal
  2. Schleife mit Verzweigung an den Schleifenbeginn: 4 Takte, Anzahl Durchläufe: c1 - 1 mal
  3. 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

LED am AVR 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