Path: Home => AVR overview => Time loops => with a 16 bit double register
Zeitschleife

Time loops with a 16 bit double register in AVR assembler

With this you are able to program time loops for delays of up to a half second. The blinking of a LED is performed by this.

Code of a 16 bit loop

A time loop with a 16 bit double register in assembler looks like that:

.equ c1 = 50000 ; Number of exections of the loops
	ldi R25,HIGH(c1) ; Load MSB register with the upper byte
	ldi R24,LOW(c1) ; Load LSB register with the lower byte
Loop: ; Loop starts here
	sbiw R24,1 ; Decrease double register value by one
	brne Loop ; if not zero start loop again, if zero continue
The constant c1 again defines the number of loop executions. As the 16 bit register can have 65,536 different numbers, it can count 256 times longer than with an 8 bit register only.

The instruction "SBIW R24,1" decreases the register pair word-wise. That means that whenever the LSB underflows, the MSB is also automatically reduced by 1. Note that only the register pairs R25:R24, R27:R26, R29:R28 and R31:R30 can do that. As R27:R26 (called X), R29:R28 (called Y) and R31:R30 (called Z) can do additional things, R25:R24 is the number 1 candidate for that use as 16 bit counter.

Controller clock cycles

The number of clock cycles for these instructions LDI, SBIW and BRNE can be read from the device data book for the AVR. The following are the clock cycles:

.equ c1 = 50000 ; No instruction, 0 cycles, only for the assembler
	ldi R25,HIGH(c1) ; 1 cycle
	ldi R24,LOW(c1) ; 1 cycle
Loop: ; Loop starts here, no instruction, only for the assembler
	sbiw R24,1 ; 2 cycles
	brne Loop ; 2 cycles if not zero, 1 cycle if zero
The number of clock cycles is the sum of
  1. Load: 2 instructions 1 cycle each, once executed,
  2. Loop: 2 cycles for SBIW, two cycles for BRNE and not zero, executed (c1 - 1) times,
  3. Loop end: 2 cycles for SBIW, one cycle for BRNE, executed once.
The number of clock cycles therefore is:
ncycles = 2 + 4 * (c1 - 1) + 3

or:
ncycles = 2 + 4 * c1 - 4 + 3

or even simpler:
ncycles = 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