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).