Guida - ssalvatori

annuncio pubblicitario
Guida alla Sesta Esercitazione
curata da Ilaria Casale
Obiettivi
Dopo aver svolto questa esercitazione si:
 conosceranno le caratteristiche generali di un ADC;
 sarà appreso come utilizzare l'ADC, integrato nel micro, come voltmetro
per misurare la tensione al suo ingresso.
Generalità sugli ADC (Analog to Digital Converter) e
sui DAC(Digita to Analog Converter)
DAC: dispositivo che consente di ricevere un numero digitale, scritto in binario,
e fornisce in uscita una grandezza elletrica proporzionale a questo (esiste una
relazione lineare tra ingresso e uscita).
Generalmente i DAC hanno l’uscita in corrente.
ADC: dispositivo che consente di ricevere una tensione di ingresso e fornire un
numero digitale in uscita (l’inverso del DAC).
Lo scopo è, osservando il numero in uscita e conoscendo la dinamica d’ingresso
del convertitore, ricavare proprio il valore di tensione di ingresso dell’ADC.
Viene quindi utilizzato come strumento di misura.
La dinamica dei convertitori può riferirsi all'uscita oppure all'ingresso.
Se si parla della dinamica in termini di Volt, il fondo scala (F.S.) potrebbe
essere unipolare, quindi andare da 0 a F.S., oppure bipolare e variare tra –F.S. e
+F.S.
Per l'ADC integrato nell'LPC1769 della scheda LPCXpresso la dinamica è 0 – 3.3
V.
N.B. 3.3 V non è la tensione di alimentazione del dispositivo, ma la sua
tensione di riferimento.
La tensione di ingresso di un ADC è un segnale continuo, può assumere infiniti
valori, la cui dinamica è stabilita dal fondo scala.
Al contrario l’uscita è discreta trattandosi di numeri digitali.
Ciò che ne consegue è una caratteristica a gradini. I punti intermedi di
questi, nel caso ideale, sono tutti allineati su una retta passante o per l’origine
del grafico o per –F.S.
Qui sotto è riportato il caso di una dinamica bipolare (da –F.S. a +F.S.).
 Quando l’ingresso è –F.S. il codice dell’uscita è 000.
 Quando si è a metà dinamica, essendo in questo caso bipolare e a 3 bit,
l’uscita corrispondente è il numero 4 (011).
 A +FS corrisponde il numero 7 (111), il massimo.
1
Caratteristica ingresso-uscita di un ADC
Viceversa, un DAC in ingresso riceve dei numeri digitali, quindi si hanno solo
dei valori interi sull’asse delle ascisse.
In corrispondenza si hanno sempre dei valori interi della tensione d’uscita.
Da ciò ne consegue che la caratteristica è formata da punti.
Anche in questo caso la dinamica può essere bipolare o unipolare, ma stavolta
ci si riferisce all’uscita.
Caratteristica ingresso-uscita di un DAC :
2
Sempre in riferimento alla dinamica, i bit che fornisce l’ADC (ma il discorso vale
anche per il DAC) possono avere 2 significati:

Numeri interi: I pesi vanno da 20 a 2n-1

Numeri frazionari: I pesi vanno da 2-n a 2n-1
Al dispositivo (ADC) arriva una tensione di riferimento di 3.3, nel caso
unipolare, quindi FS=3.3. La caratteristica per ragioni di simmetria inizia con un
mezzo gradino.
Quando in uscita si ha il codice 0000 si ha cosi, in corrispondenza, una funzione
intorno a un certo intervallo dopo lo zero.
Se si avesse infatti il gradino iniziale proprio sullo zero tale intervallo andrebbe
a finire su valori di tensione negativi (ciò non rispetterebbe la dinamica
d’ingresso unipolare).
Ciò che si avrebbe teoricamente in uscita, da un ADC a n bit, se arrivasse una
tensione di ingresso esattamente pari a F.S., nel caso di 4 bit sarebbe 10000. Al
massimo della dinamica corrisponde in uscita, trovandosi ancora sull’ultimo
gradino, un numero che l’ADC stesso non è in grado di rappresentare (essendo
a 4 bit).
Nella pratica in corrispondenza a F.S. l'ADC satura al valore 2n-1.
Per conoscere la risoluzione in riferimento all’ingresso, ovvero sapere
l’intervallo in Volt che l’ADC può distinguere, si ha il rapporto LSB (Least
Significant Bit, valore indicato dal datasheet):
3
In cui 1/2n rappresenta la risoluzione di un ADC a n bit (avendo questo 2n
codici possibili).
Il dispositivo utilizzato in questo corso ha un F.S. di 3.3 V ed è a 12 bit, perciò la
sua risoluzione è inferiore a 1 mV.
L’ADC per ovvie ragioni sfrutta il processo di campionamento.
Campiona il segnale tempo continuo che si ha in ingresso con un determinato
periodo e quindi una determinata frequenza che deve essere almeno due volte
maggiore alla massima frequenza proprio del segnale di ingresso.
Tali campioni saranno convertiti in formato numerico.
Per evitare il fenomeno di Aliasing si filtra il segnale d’ingresso nella banda di
interesse.
In generale, prima di un ADC (non nel nostro caso in quanto si misurano
grandezze che variano molto lentamente) è necessario un filtro passabasso per escludere tutte le frequenze oltre la banda di Nyquist.
Inoltre un ADC necessita anche della presenza di un circuito Sample
(campionamento) and Hold (mantenimento):
Buffer di ingresso, interruttore,
condensatore, buffer d’uscita.
Quando l’interruttore è chiuso
(campionamento) il buffer di ingresso fa si
che la tensione ai capi del condensatore sia
pari a quella di ingresso.
Nel momento in cui l’interruttore viene aperto (mantenimento), il
condensatore, con impedenze molto elevate, mantiene la memoria dell’ultimo
valore assunto (della tensione ai suoi capi).
Idealmente quindi il condensatore non si scarica dando quindi la possibilità
all’ADC in serie a tale circuito di effettuare la conversione di una tensione
costante.
Un'altra informazione necessaria, indicata nel datasheet di un ADC è la
rumorosità, in particolare riferita all’ingresso.
Esempio: Noise = 33 µVrms (rms indica il valore efficace). Tale valore non varia
al variare della risoluzione.
Si intuisce che qualunque segnale al di sotto di 33 µV viene mascherato dal
rumore interno del circuito analogico di ingresso. Quindi l'LSB non potrà essere
inferiore a 33 µV.
Se si divide il F.S. per 33µV e se ne calcola il logaritmo in base 2. In questo caso
si ottiene il valore di 16 bit che rappresenta la massima risoluzione dell'ADC
che sia priva di rumore (ed infatti viene indicata come Noise-Free Resolution,
che una delle caratteristiche indicate nel datasheet).
4
Esercitazione con l'ADC
Schema elettrico che indica i blocchi collegati, il numero dei pin utilizzati con
i rispettivi nomi:
Si osserva che, per utilizzare il codice Lab6a_testADC, che si analizzerà in
seguito, il pin 20 della strip è utilizzato per far giungere al canale 5 (ADC.05)
dell’ADC una tensione analogica.
L’ADC montato nel LPC1769 è a 8 canali, con un multiplexer a 8 ingressi.
Per simulare un segnale analogico da fornire in ingresso si fa una partizione
della tensione 3.3 V attraverso un trimmer da 50 kΩ (ma va bene anche anche
un qualunque trimmer di valore dell'ordine del kΩ o decine di kΩ.
Con il trimmer collegato come indicato nello schema di figura si riesce a
sfruttare l’intera dinamica di ingresso dell’ADC che va da 0 a 3.3 V. In questo
modo sarà possibile visualizzare, in corrispondenza, tutti i numeri che vanno da
0 a 4095 (uscita dell'ADC).
La figura qui sotto mostra un possibile schema di montaggio.
Si noti la presenza di un condensatore da 100 nF ai capi della tensione di
alimentazione dell'LCD. Questo è necessario per limitare il rumore indotto dalle
commutazioni durante la comunicazione con l’LCD.
Molti circuiti integrati presentano in prossimità condensatori di circa 100 nF,
per cortocircuitare a massa le variazioni rapide sulla tensione di alimentazione.
5
Esercizio 1:
Importare il progetto “Lab6a_testADC” per verificare come utilizzare l'ADC:

lanciare il programma e ruotare il cursore del trimmer da 50 kΩ in modo
da visualizzare un valore intorno a 2000 (circa a metà corsa);

si dovrebbe osservare che la cifra meno significativa non è stabile;

inserire un breakpoint nel punto indicato nel codice e, lanciando più volte
il programma (con Resume), osservare di quanto varia il numero
visualizzato sull'LCD;

accedendo alla scheda “Variables”, modificare il valore della variabile n
per aumentare il numero di acquisizione su cui fare le medie e poter
avere sull'LCD un numero visualizzato più stabile;

compilare una tabella del tipo riportato qui sotto.

Quant'è l'aumento della “risoluzione” col numero di acquisizioni di cui si
fa la media?
In questo progetto sono presenti due nuovi file, ADC.h e ADC.c, in cui sono
inserite le funzioni di gestione proprio dell’ADC.
Nel file ADC.c si osserva inizialmente la sua funzione di inizializzazione:
Nel main.c a viene passato a questa il parametro 5, perché come già riferito in
tale progetto si utilizza ADC0.5, o meglio il quinto canale dell’ADC.
Un'altra funzione utilizzata nel main.c è:
Permette di acquisire il numero convertito dall’ADC che varia quindi tra 0 e
4095.
6
Nel codice tale numero è assegnato a una costante a 32 bit (CHANNEL) :
.
Si osserva quindi il ciclo for all’interno di quello infinito:
Per i che va da 0 a 2n (i shiftato a sinistra
di n), si accumulano in adcData 2n
acquisizioni consecutive.
Si utilizza quindi la variabile adcData, inizialmente posta a 0, come
accumulatore, precisamente a ogni ciclo for si accumula in questa il numero
che viene dall’ADC, addizionando di volta in volta i nuovi campioni.
Volendo fare la media si deve dividere il valore ottenuto per il numero di
campioni, 2n.
Tutto ciò è contenuto nel ciclo infinito, che in ultimo fa sì che il risultato venga
visualizzato sul Display, a 4 cifre:
Effettuando il Debug di tale codice, con n=0 (si tratta quindi del risultato delle
acquisizioni successive ad ogni ciclo while che l’ADC restituisce) si nota che la
cifra meno significativa non è stabile, questo perché non lo è la tensione di
riferimento.
In questo caso per aumentare il rapporto segnale rumore si effettuano delle
medie.
Infatti cambiando il valore di n, si effettua una media di quel numero che
mediamente è proprio la tensione di uscita dal trimmer, con sovrapposto un
rumore additivo casuale, che mediamente è zero.
Facendo più medie si riesce a filtrare tale rumore.
Eseguito il Debug e inserito un breakpoint alla fine del codice (indicato anche
dai commenti) il programma si arresta ad ogni conversione.
Ciò che si visualizza è un numero stabile.
Invece ogni volta che si preme il tasto Resume, si visualizza sul Display un
numero che varia continuamente (a causa del rumore).
Osservando che quando n=0 il valore varia di circa 3 o 4 unità, per evitare di
arrestare il Debug, cambiare il suo valore e riprogrammare, è possibile tramite
la scheda Variables, modificare direttamente il valore di n. Il Debugger di
conseguenza inserisce quest’ultimo nella corrispondente locazione RAM, senza
cambiare il codice.
7
Esercizio 2:
Copiare e incollare Lab6a_testADC e rinominare la copia in
“Lab6b_Voltmetro”;

Modificare il progetto in modo da visualizzare il valore di tensione in
ingresso a ADC0.5 sapendo che la tensione massima è pari a 3.3 V e
quella minima 0 V.

La tensione deve essere visualizzata nel formato:
Vin: #.### V
Nota: la funzione Write_ndigitsval inserisce degli spazi al posto degli zeri non
significativi. Duplicare la funzione e rinominare la copia Write_ndigitsval0 in
modo che con essa si possa visualizzare un numero decimale a più cifre in cui
siano comunque visibili anche gli zeri non significativi.
La modifica da effettuare al codice precedente, oltre a imporre n=5 per avere
quindi 32 acquisizioni, è l’aggiunta delle seguenti funzioni alla fine del ciclo
infinito:
La terza istruzione è per trasformare il numero adcData in millivolt. Per questo
il valore del fondo scala è 3300 (mV).
Si deve fare attenzione a non andare oltre, con il risultato dell’operazione, alla
risoluzione del microprocessore. Essendo adcData al massimo 4095,
moltiplicato per 3300 assicura questa condizione (non andare oltre la
rappresentazione a 32 bit, cioè poco oltre 4 miliardi).
Se si facesse la divisione per 4095 prima della moltiplicazione si perderebbe
risoluzione, anzi il risultato sarebbe 0.
Il valore ottenuto dalla prima moltiplicazione viene quindi shiftato di 12 bit,
ovvero diviso per 4095.
Si noti che l’operazione:
corrisponde a LSB*adcData.
Infine, essendo il risultato in millivolt, si divide per 1000 per ottenere i Volt.
Nella quarta istruzione si vuole ottenere e visualizzare la parte decimale della
divisione per 1000, la parte frazionaria.
Si noti che la funzione qui usata non è Write_ndigitsval, che avrebbe fatto
visualizzare ad esempio “2. 5 V” e non “2.005 V”.
8
Si è infatti copiata e incollata tale funzione nel file HD44780.c, per crearne una
nuova denominata
Per poter effettuare la modifica, si deve analizzare la definizione già esistente:
Questa funzione riceve il numero che si vuole visualizzare (intero) sul display a
n cifre, assegnato alla variabile locale dummyVal.
La variabile ten_base, anch’essa locale, viene inizializzata a 1.
A ndigits viene sempre assegnato, con la chiamata della funzione un valore.
Perciò la condizione di predecremento nel primo ciclo while non fa altro che
prendere il valore iniziale, sottrarre 1 e poi valutare se il risultato è vero o falso.
Per ndigits volte, ten_base viene moltiplicato per 10.
Il risultato finale non è altro che 10ndigits.
Questo perché il processore non è in grado di eseguire le potenze, si
dovrebbero importare delle librerie matematiche, non trattandosi di una
potenza di 2 non si potrebbe infatti eseguire semplicemente uno shift.
Si vuole visualizzare un numero a ndigits cifre, la cui più significativa è ottenuta
dal valore di dummyVal diviso 10ndigits (ad esempio se si dividesse per mille si
otterrebbe il valore delle migliaia).
Nel secondo ciclo while, essendo le cifre sul display rappresentate dalla più
alla meno significativa, il numero iniziale (in dummyVal) lo si divide per
ten_base che se ad esempio fosse 107 fornirebbe le decine di milioni (essendo
la divisione intera).
Il risultato viene assegnato alla variabile digit.
Inoltre, con le ultime due istruzioni, si prende il resto della divisione per 10
milioni, per escludere la cifra più significativa.
Dovendo comunicare quanto fatto ten_base deve essere divisa per 10. Ora
infatti è proprio 2^(ndigits-1).
Si procede il tal modo fino a che ten_base non arriva a zero.
9
Il compito del ciclo if è valutare che digit sia pari a 0, quando ciò non è
verificato, la cifra va sicuramente scritta, significativa o non significativa che
sia.
Non appena si trova una cifra diversa da 0, vuol dire che gli zeri non
significativi sono terminati.
La variabile leading_zeroes_flag, anch’essa inizialmente posta a 1, rimane a
tale valore (flag alzata) fino a che la condizione dell’if non risulta vera.
Se leading_zeroes_flag sta a 1 (quindi ci si trova nella parte non significativa) e
si sta oltre le unità (in quanto se il numero fosse zero, almeno l’unità anche se
pari a 0 andrebbe visualizzata) allora va inserito uno spazio.
In riferimento alla terzultima istruzione:
NB. In C ciò che è scritto prima del simbolo “?” rappresenta la condizione di un
if, ciò che si trova tra “?” e “:” è l’istruzione da eseguire qualora la condizione
fosse verificata. Infine la parte di istruzione che segue il simbolo “:” (else) è ciò
che va eseguito qualora la condizione non fosse verificata.
Per ottenere la nuova funzione Write_ndigitsval0, va cancellato il ciclo if e
proprio la quartultima istruzione, sostituendola semplicemente con l’operazione
relativa all’else (“:”), ovvero:
10
Scarica