Soluzioni FIXED-POINT per AVR

Prima regola: “non usare aritmetica in virgola mobile con un AVR a meno che non sia strettamente necessario”. L’aritmetica in virgola mobile è deleteria per le applicazioni con i micro AVR sia in termini di tempo di esecuzione del programma, sia in termini di occupazione delle risorse. In questa trattazione verrà illustrato come effettuare una moltiplicazione tra numeri fixed-point in meno di 60 microsecondi e, in casi particolari, anche in meno di 20 microsecondi con cicli istruzione di 4MHz. Come fare? La maggior parte delle operazioni in virgola mobile possono essere effettuate usando numeri interi: il  punto decimale è solo una convenzione che risiede nel cervello del programmatore. I numeri interi sono molto facili da gestire in assembler/assembly e per di più il loro uso velocizza l’esecuzione del programma rispetto all’uso di aritmetica non intera.

Conversione lineare

Si consideri  il caso in cui un convertitore A/D a 8 bit operi la conversione di un segnale analogico nel range 0-2.55V ritornando come risultato un intero compreso tra 0x00 e 0xFF. Se il risultato  deve essere visualizzato su un display LCD, la conversione sarà semplicissima: basterà convertire l’intero ottenuto dalla conversione in una stringa ASCII decimale (tra 000 e 255) quindi inserire il punto decimale a destra della prima cifra più significativa. Si consideri ora il caso in cui al convertitore A/D sia applicato un segnale da 0 a 5V. Per ottenere il valore corretto il risultato della conversione andrebbe moltiplicato per il  fattore 500/255 ovvero 1.9608. Il trucco per fare questa operazione senza perdere di accuratezza è quello di moltiplicare e dividere per 256 il fattore moltiplicativo. La moltiplicazione per 256 dà come risultato 256*500/255=501.96. Approssimando a 502, l’errore è dell’ordine dello 0,008% valore accettabile per il convertitore A/D in esame. La divisione per 256 è una operazione piuttosto semplice in quanto 256 è 8 una potenza di 2 (2 =256) quindi la divisione si limita a ignorare  il byte meno significativo del numero da dividere. Per la moltiplicazione per 502 si considerano i seguenti registri: R1 contiene il moltiplicando (il  risultato della conversione), R4:R3:R2 il moltiplicatore (502), R7:R6:R5  il risultato.  I passi da seguire sono i seguenti:

  • si verifica se il moltiplicando è 0 (in tal caso il risultato è 0);
  • se il moltiplicando è diverso da zero viene fatto un shift a destra (LSR) con carry inserendo 0 nel bit più significativo;
  • se il carry è 1 si aggiunge il moltiplicatore (che vale 502 al primo step, 1024 al secondo step e così via). Se il carry era zero non viene aggiunto il moltiplicatore e si passa allo step successivo;
  • viene fatto uno shift a sinistra di R2 (inserendo 0 in coda) usando l’istruzione LSL. Il bit 7 viene messo nel carry. Ora si opera uno shift a sinistra di 1 bit di R3 con carry dunque il contenuto del carry va nel bit 0 di R3 e il bit 7 di R3 va nel carry. Lo stesso per R4;
  • si ripetono le operazioni dal punto 1. Alla fine della procedura il risultato della moltiplicazione per 502 si trova in R7:R6:R5 per cui la divisione per 256 può essere fatta ignorando R5. Non resta ora che convertire  il risultato in una stringa ASCII e aggiungere  il punto decimale dopo la prima cifra più significativa.

 

 

Una risposta

  1. Maurizio Di Paolo Emilio Maurizio 16 ottobre 2016

Scrivi un commento