GENERAZIONE PRECISA DI RITARDI CON AVR
Ecco una utilissima libreria per AVR studio contenente una funzione di ritardo estremamente precisa. La funzione deve essere chiamata con _waste_us n dove n è un valore intero compreso tra i valori 1000000/F_CPU (F_CPU è una costante definita) e 25769803779/F dove F è la frequenza della CPU espressa in MHz. La macro genererà un ritardo compreso tra 1ms e 25769803779ms. La precisione è dell’ordine di 1/F [ms]. Per utilizzare il codice (riportato nel listato 1) è necessario selezionare il corretto valore di F_CPU (togliendo il relativo “;” che lo rende un commento), salvare il file nella stessa directory del proprio progetto. Quindi includerlo con la direttiva .INCLUDE all’inizio del programma. Il listato 1 riporta il codice integrale.
; Selezionare il corretto valore per F_CPU
; .equ F_CPU = 1000000 ;Hz
; .equ F_CPU = 2000000 ;Hz
; .equ F_CPU = 3579545 ;Hz
; .equ F_CPU = 3686400 ;Hz
; .equ F_CPU = 4000000 ;Hz
; .equ F_CPU = 4032000 ;Hz
; .equ F_CPU = 4096000 ;Hz
; .equ F_CPU = 4194304 ;Hz
; .equ F_CPU = 4433619 ;Hz
; .equ F_CPU = 4915200 ;Hz
; .equ F_CPU = 5000000 ;Hz
; .equ F_CPU = 5068800 ;Hz
; .equ F_CPU = 5990400 ;Hz
; .equ F_CPU = 6000000 ;Hz
; .equ F_CPU = 6144000 ;Hz
; .equ F_CPU = 6500000 ;Hz
; .equ F_CPU = 7372800 ;Hz
; .equ F_CPU = 7680000 ;Hz
; .equ F_CPU = 8000000 ;Hz
; .equ F_CPU = 9000000 ;Hz
.equ F_CPU = 9400000 ;Hz
; .equ F_CPU = 9216000 ;Hz
; .equ F_CPU = 9830400 ;Hz
; .equ F_CPU = 10000000 ;Hz
; .equ F_CPU = 10240000 ;Hz
; .equ F_CPU = 11000000 ;Hz
; .equ F_CPU = 11059200 ;Hz
; .equ F_CPU = 11520000 ;Hz
; .equ F_CPU = 12000000 ;Hz
; .equ F_CPU = 12000393 ;Hz
; .equ F_CPU = 12288000 ;Hz
; .equ F_CPU = 13500000 ;Hz
; .equ F_CPU = 14318180 ;Hz
; .equ F_CPU = 14745600 ;Hz
; .equ F_CPU = 15000000 ;Hz
; .equ F_CPU = 15360000 ;Hz
; .equ F_CPU = 16000000 ;Hz
; .equ F_CPU = 16000312 ;Hz
; .equ F_CPU = 16257000 ;Hz
; .equ F_CPU = 16384000 ;Hz
; .equ F_CPU = 17734475 ;Hz
; .equ F_CPU = 18000000 ;Hz
; .equ F_CPU = 18432000 ;Hz
; .equ F_CPU = 19660800 ;Hz
; .equ F_CPU = 20000000 ;Hz
.Macro _waste_us ;n
.set Fraction = @0*F_CPU/1000000 ;
.set Fraction = Fraction * 100
.set Fraction = @0*F_CPU/10000 - Fraction
.if Fraction >= 50
.set Cycles_Needed = (@0 * F_CPU /1000000)+1
.endif
.if Fraction < 50
.set Cycles_Needed = (@0 * F_CPU /1000000)
.endif
_Cycle_waster Cycles_Needed
.endmacro
.macro _Cycle_waster
.If @0 == 1
nop
.EndIf
.If @0 == 2
nop
nop
.EndIf
.If ((@0 > 2) && (@0 < 769))
;C=3n
;769=(3 * (2^8)) + 1
.set Loops_Needed = @0/3
ldi R16,Low(Loops_Needed)
Loop:
dec R16
brne Loop
.set Cycles_Left_To_Do = @0 - (3*Loops_Needed)
_Cycle_waster Cycles_Left_To_Do
.EndIf
.If (@0 > 768) && (@0 < 262146)
;C=1+4n
;262146 = 1 + (4 * 2^16) + 1
.set Loops_Needed = (@0 - 1)/4
ldi ZL,Low(Loops_Needed)
ldi ZH,High(Loops_Needed)
Loop:
sbiw ZL,1
;If your AVR does not support SBIW then replace use
; subi ZL,1
; sbci ZH,0
;This has no effect on the timing. It only takes a word more code
brne Loop
.set Cycles_Left_To_Do = (@0 - (4*Loops_Needed))-1
_Cycle_waster Cycles_Left_To_Do
.EndIf
.If (@0 > 262145) && (@0 < 83886083)
;C=2+5n
;83.886.083 = 2 + (5 * 2^24) +1
.set Loops_Needed = (@0 - 2)/5
ldi R16,Low(Loops_Needed)
ldi ZL,Byte2(Loops_Needed)
ldi ZH,Byte3(Loops_Needed)
Loop:
subi R16,1
sbci ZL,0
sbci ZH,0
brne Loop
.set Cycles_Left_To_Do = (@0 - (5*Loops_Needed))-2
_Cycle_waster Cycles_Left_To_Do
.EndIf
.If (@0 > 83886082) && (@0 < 25769803780)
;C=3+6n
;25769803780 = 3 + (6 * 2^32) +1
.set Loops_Needed = (@0 - 3)6
ldi XL,Low(Loops_Needed)
ldi XH,Byte2(Loops_Needed)
ldi ZL,Byte3(Loops_Needed)
ldi ZH,Byte4(Loops_Needed)
Loop:
sbiw XL
;if your AVR does not support SBIW then replace use
; subi XL
; sbci XH,0
;This has no effect on the timing. It only takes a word more code
sbci ZL,0
sbci ZH,0
brne Loop
.set Cycles_Left_To_Do = (@0 - (6*Loops_Needed)) - 3
_Cycle_waster Cycles_Left_To_Do
.endif
.endmacro
| Listato 1 |




In questo modo potremmo implementare applicazioni real time con una buona precisione considerando il rapporto 1/F (dove F è la frequenza della CPU).