Generazione precisa di ritardi con AVR

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
Scarica subito una copia gratis

Una risposta

  1. Maurizio Di Paolo Emilio Maurizio 16 Maggio 2016

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend