MCP3202 è un convertitore A/D a 12 bit con circuito di sample & hold incorporato prodotto da Microchip. È provvisto di due canali d’ingresso che possono essere usati come due ingressi single-ended separati o come un solo ingresso (pseudo) differenziale. Quest’ultimo tipo di collegamento è utile per eliminare piccoli disturbi di modo comune, dell’ordine di 100 mV, possibili in ambienti rumorosi. La non linearità differenziale è minore di ±1 LSB, mentre la non linearità integrale è minore di ±1 LSB per la versione MCP3202B. Il convertitore utilizza il metodo SAR (Successive Approximation Register) che permette di ottenere la risoluzione di 12 bit con una velocità di campionamento relativamente elevata. In particolare, se alimentato a 5 V, il tasso di conversione massimo è pari a 100 Ksps, mentre scende a 50 Ksps alla tensione d’alimentazione minima di 2.7 V. La tensione d’alimentazione funge anche da tensione di riferimento per il convertitore, Vref. Così, la corrispondenza tra il codice in uscita ed il valore della tensione in ingresso Vin, è data dalla formula seguente:
Interfacciamento SPI
MCP3202 è utilizzato congiuntamente ad un microcontrollore con cui si collega tramite un’interfaccia SPI. Com’è noto, questa è un’interfaccia seriale sincrona particolarmente semplice da utilizzare e veloce: MCP3202 supporta una velocità di clock massima di 1.8 MHz, se alimentato a 5V. Nel grafico in figura 1 possiamo vedere un esempio di comunicazione tra il convertitore ed un microcontrollore PIC. L’interfaccia SPI del micro è configurata nel cosiddetto Mode 1,1: il segnale di clock è idle a livello alto e la trasmissione di un bit avviene sul fronte di discesa del clock. La comunicazione è iniziata dal micro che emette un primo byte costituito da 7 bit bassi e da un bit di Start: i 7 bit iniziali sono necessari per mantenere l’allineamento su 8 bit (infatti il modulo SPI dei PIC trasmette gruppi di 8 bit alla volta). Segue un byte contenente i bit seguenti
- SGL/DIFF : 1 se gli ingressi del MCP3202 sono single ended, 0 se differenziali.
- ODD/SIGN: nel caso d’ingressi single-ended lo 0 seleziona l’ingresso CH0, l’1 l’ingresso CH1. Per ingressi differenziali, 0 indica che CH0 è l’ingresso + e CH1 l’ingresso -, l’inverso se il bit è posto ad 1.
- MSBF: se posto ad 1, MCP3202 emetterà il risultato della conversione a partire dal MSB, se a 0 lo emetterà una prima volta a partire dal MSB e successivamente anche a partire dal LSB.
L’esempio in figura 1 è relativo al caso di MSBF=1. Dopo aver ricevuto il bit MSBF, MCP3202 emetterà un bit a zero, quindi inizierà ad emettere il risultato della conversione, MSB first. Alla fine del secondo byte, quindi, il modulo di ricezione del micro avrà ricevuto i primi 4 bit del risultato. I successivi 8 impulsi di clock del micro servono per ricevere il terzo byte che conterrà gli 8 bit restanti della conversione.
Misurare tensioni positive con MCP3202
Nel caso più semplice, il convertitore è utilizzato come raffigurato nello schema elettrico di figura 2. MCP3202 è alimentato con la stessa tensione stabilizzata a 5V che alimenta il microcontrollore PIC18F2550. Poiché lo stadio d’ingresso utilizza una tensione di alimentazione singola (single supply), sarà possibile misurare tensioni Vin tra 0 e 5 V, cui corrisponderanno dei codici di uscita compresi tra 0 e 4095. Un circuito del genere presenta però due svantaggi: non è possibile misurare tensioni d’ingresso negative e non c’è una corrispondenza 1:1 tra il codice in uscita e la tensione Vin. Quest’ultimo problema in particolare comporta una leggera complicazione del firmware, come vedremo nel programma d’esempio. Chiaramente, inoltre, la precisione della misura dipende anche dalla precisione della tensione d’alimentazione.
Misura di tensioni bipolari
Nel caso in cui fosse necessario misurare tensioni sia positive che negative, come ad esempio quelle prodotte da un generatore audio, si può ricorrere al circuito raffigurato in figura 3. In questo caso, è utilizzato l’integrato LM4040-4.1 per generare una tensione di riferimento di 4.096V. Questo integrato è disponibile con una precisione fino allo 0.1%: con questo valore di tensione inoltre il convertitore A/D fornirà un codice d’uscita pari ad 1 LSB per 1 mV di ingresso. Ciò semplifica i calcoli del firmware e ci permette di ottenere la precisione massima di conversione. Per poter misurare sia tensioni positive che negative, si utilizza l’amplificatore operazionale IC4, un TL081 o equivalente. L’operazionale è alimentato tramite una tensione duale di ±5 V: la tensione di riferimento viene divisa per 4 dal partitore costituito dalle due resistenze di precisione R5 ed R6, in modo da fornire all’ingresso non invertente un offset di tensione che verrà sommato alla tensione da misurare. In particolare, la tensione d’uscita dell’operazionale sarà data da:
In pratica, nel procedimento di taratura, una volta cortocircuitato l’ingresso Vin del canale, dovremo ruotare il trimmer R3 per ottenere in uscita dall’operazionale una tensione pari a Vref/2 = 2.048 V. Così una tensione d’ingresso compresa tra ±2.048 V sarà convertita tra 0 e 4.096 V.
Un esempio con PIC18
Nel listato 1 è riportato parte del codice del programma d’esempio. Il programma è stato sviluppato tramite l’IDE MPLAB ed il compilatore C18 di Microchip. Sono state usate anche le funzioni di libreria per la gestione del modulo SPI fornite con il compilatore. Nella procedura main() sono dichiarate le variabili che conterranno i risultati delle conversioni: notiamo che è usata la compilazione condizionale in modo da poter utilizzare il codice sia con il collegamento a tensione singola che duale. Se la costante MCP_SS è definita, sarà compilata la versione per tensione singola, altrimenti quella a tensione duale. Il codice prosegue con le inizializzazioni delle porte del PIC, viene quindi inizializzato il modulo SPI. Nel loop infinito successivo, si esegue la lettura dei due canali di MCP3202: un ciclo di lettura è iniziato dall’attivazione del pin CS, dopodichè è emesso il primo byte di controllo (contenente il bit di start) da parte del PIC. Il secondo byte emesso contiene i bit di controllo SGL, ODD e MSBF che abbiamo descritto in precedenza. Alla fine dell’emissione di questo byte, il buffer di lettura del PIC conterrà i primi 4 bit risultanti dalla conversione del canale CH0: questi bit (opportunamente mascherati) saranno copiati nella variabile MSB_AD_CH. L’istruzione successiva legge il terzo byte tramite la funzione ReadByte() copiandolo in LSB_AD_CH: questo conterrà i restanti 8 bit della conversione. Si disattiva CS terminando così la comunicazione. Il risultato a 12 bit è ricavato componendo i due gruppi di bit in AD_CH:
AD_CH = ((unsigned int) MSB_AD_CH << 8) + LSB_AD_CH;
Il codice seguente differisce a seconda che sia stata scelta l’alimentazione singola o duale. Nel primo caso, AD_CH sarà moltiplicato per un valore costante V_CONST pari a Vref/4096, con Vref espressa in mV. Questo è pari al valore dell’LSB. Quindi la tensione misurata del canale sarà:
Vin_CH[i] = AD_CH * V_CONST;
Si noti che in questo caso è necessaria una moltiplicazione per un float, cosa che introduce un ritardo nei calcoli. Nel caso di alimentazione duale, il valore di AD_CH è innanzitutto cambiato di segno (l’operazionale d’ingresso infatti inverte la tensione Vin), quindi è sommato alla costante V_OFFS pari alla tensione di offset di 2048 mV:
Vin_CH[i] = -AD_CH + V_OFFS;
Il ciclo successivo compie le stesse operazioni per il canale CH1 e così via.
#include <p18cxxx.h> // definizioni per i PIC18 #include <spi.h> #include “MCP3202.h” // Config Bits, defines // Togliere il commento se SINGLE SUPPLY //#define MCP_SS void main(void) { char i = 0; // contatore // MSB ed LSB conversione A/D MCP3202 unsigned char MSB_AD_CH, LSB_AD_CH; // 12 bit conversione A/D MCP3202 unsigned int AD_CH; #ifdef MCP_SS float Vin_CH[2]; // Vin CHx float V_CONST; // LSB = Vref/4096 mV V_CONST = 1.220703; // 5000/4096 #else int Vin_CH[2]; // Vin CHx int V_OFFS=2048; //OFFSET per tensioni bipolari #endif /*** INIZIALIZZAZIONI PIC ***/ PORTA = 0; PORTB = 0; PORTC = 0; TRISA = 0B00000000; // PORTA TRISB = 0B00000000; // PORTB TRISC = 0B00000000; // PORTC /*** inizializza l’SPI ***/ // disattiva CS CS_MCP3202 = 1; // SDO Idle SDO = 0; //configura SPI per MCP3202 (Mode 1,1) //CKP=1, CKE=0 //SMP=0 // freq. clock SPI = Fosc/64 OpenSPI(SPI_FOSC_64, MODE_11, SMPMID); // loop scrittura/lettura verso MCP3202 while (1) { for (i=0; i<2; i++) { // attiva CS CS_MCP3202 = 0; // emette il primo byte: Start WriteSPI(0B00000001); // secondo byte: Single Ended, CH i, MSB First if (i==0) WriteSPI(0B10100000); // CH0 else WriteSPI(0B11100000); // CH1 // legge i 4 MSB del risultato MSB_AD_CH = (0x0F & SSPBUF); // legge gli 8 LSB del risultato LSB_AD_CH = (ReadSPI()); // disattiva CS CS_MCP3202 = 1; // compone i 12 bit del risultato.. AD_CH = ((unsigned int) MSB_AD_CH << 8) + LSB_AD_CH; // ..e lo elabora #ifdef MCP_SS //*** SINGLE SUPPLY // Vin = AD_CH*Vref/4096 Vin_CH[i] = AD_CH * V_CONST; #else //*** DUAL SUPPLY // Vin = -AD_CH + V_OFFS Vin_CH[i] = -AD_CH + V_OFFS; #endif //*** altre elaborazioni del risultato //... } // fine for } // fine while(1) } // fine main()
Listato 1 |
Sappiamo l’importanza degli ADC, un’interfaccia tra mondo fisico e digitale. Un interessante codice da esportare in altre occasioni di design con mcu.