L’integrazione di segnali analogici nel mondo digitale dei microcontrollori rappresenta una delle sfide più affascinanti e complesse per i progettisti elettronici. Un segnale analogico è una grandezza che può assumere infiniti valori all'interno di un determinato intervallo, riflettendo la natura continua dei fenomeni fisici come la temperatura, la pressione o l'intensità luminosa. Al contrario, un segnale digitale è invece costituito da una sequenza di valori discreti, che possono essere letti da strumenti di misura digitali, i quali ne mostrano il valore direttamente in forma numerica. La necessità di interfacciare questi due mondi richiede componenti specifici: l'ADC (Analog to Digital Converter) per la lettura e il DAC (Digital to Analog Converter) per la generazione di segnali. Molti utenti si chiedono se, disponendo di un Arduino Uno R3 con Atmega328P con al suo interno un codice, sia possibile convertire il segnale PWM in analogico (0-5 volt) senza ricorrere a filtri passivi. Spesso la risposta risiede nell'adozione di un DAC integrato già pronto, specialmente quando si ricerca una precisione che vada oltre gli standard nativi dei microcontrollori a 8 bit.

Fondamenti della conversione analogico-digitale e risoluzione
Per comprendere l'importanza di un DAC a 16 bit, è fondamentale analizzare come Arduino gestisce internamente i segnali analogici in ingresso. Quindi un segnale analogico, per poter essere letto da un circuito digitale, necessita di una conversione. I pin analogici di Arduino sono siglati ANALOG IN e, nella Arduino Uno Rev. 3, sono collegati a un convertitore interno a 10 bit. La risoluzione di questo processo determina la precisione con cui il microcontrollore "vede" la realtà. Partendo per esempio da un’alimentazione di 5 V, la risoluzione sarà di 5V/1024, ovvero 0,004883 V, mentre il range andrà da 0 V a 0,004883 x 1023, ossia 4,995 V.
Quando analizziamo un segnale reale, potremmo trovarci di fronte a una sequenza di tensioni come 1,3V - 2,6V - 0,7V - 1,8V - 4,4V - 2,2V - 3,9V - 2,5V - 3,3V - 4,7V. Un sistema a bassa risoluzione (ad esempio a 2 bit, che offre solo 4 livelli) trasformerebbe questi valori in approssimazioni grossolane come 2V - 3V - 1V - 2V - 4V - 3V - 4V - 3V - 4V - 4V. A questo punto codifichiamo tali valori, mediante la trasformazione in codice binario; sappiamo che quattro livelli di tensione o comunque quattro valori sono rappresentabili con due bit, che nel nostro caso rappresentano la risoluzione dello schema di conversione che stiamo applicando. Così i nostri dieci valori analogici iniziali diventano altrettanti valori digitali espressi nel formato binario a due cifre, che sono 01 - 10 - 00 - 01 - 11 - 10 - 11 - 10 - 11 - 11. È evidente che con un DAC a 16 bit, la granularità del segnale in uscita sarebbe immensamente superiore, permettendo di ricostruire onde sonore o segnali di controllo con una fedeltà non raggiungibile dai sistemi standard.
TUTTO CIO' CHE DEVI SAPERE SULLA FREQUENZA DI CAMPIONAMENTO!
L'architettura SAR e i limiti della tecnologia AVR
L’ADC utilizzato dai microcontrollori AVR è del tipo SAR (acronimo di Successive Approximation Register, cioè Registro ad Approssimazioni Successive). Questo meccanismo funziona attraverso un confronto iterativo: si confronta la tensione in ingresso con una tensione di riferimento generata internamente. Si ripete il procedimento con la stessa logica per tutti i bit del DAC, nel caso dell’ATmega328P in totale sono 10, e alla fine il registro SAR contiene il valore digitale della nostra tensione analogica. Sebbene questo sistema sia efficace per letture di sensori comuni, mostra i suoi limiti quando si passa alla generazione di segnali analogici complessi.
Molti utenti confondono il segnale PWM con una vera uscita analogica. Arduino dispone di sei pin digitali (3, 5, 6, 9, 10, e 11 che corrispondono ai pin fisici: 5, 11, 12, 15, 16 e 17) che, all’occorrenza, possono svolgere il ruolo di generatori PWM (Pulse Width Modulation) mediante il comando analogWrite. Tuttavia, un dac eun circuito che ha in ingresso un numero su n bit e da in uscita una tensione (o una corrente). Un segnale PWM invece e` un segnale a due livelli che trasporta una informazione analogica codificata dalla lunghezza dell'impulso. Anche l'uscita PWM a 8 bit di arduino è seriale ed relativamente lenta, se ben ricordo impiega 1/400 Hz = 2,5 millisecondi ad aggiornarla. Per chi necessita di una conversione pura, l'uso di un DAC esterno a 16 bit diventa l'unica via percorribile per evitare i limiti di velocità e la "sporcizia" elettrica tipica del PWM.
Tensioni di riferimento e stabilità del sistema
Un fattore critico nella precisione sia dell'ADC che di un eventuale DAC è la tensione di riferimento. Per adattare il range di misura, Arduino rende disponibile un pin chiamato ARef (corrispondente al pin fisico 21 dell’ATmega328P) e di un comando software analogReference(); vediamo a cosa servono e come si usano. ARef è la tensione di riferimento usata dall’ADC per impostare la scala di misura, ovvero il valore in tensione corrispondente al valore 1024. Nel caso dell’alimentazione a 5 V abbiamo: 5 V/1024 = 0,004883 V, cioè ogni punto della scala 1-1023 corrisponde a 4,88 mV (lo 0 ovviamente vale 0 V).
Tuttavia, l'alimentazione USB o dei regolatori economici spesso non è stabile. In questo caso la risoluzione diventa 1,1V/1024=0,0011V, cioè ogni punto della scala 1-1023 corrisponde a 1,1 mV se si utilizza il riferimento interno. Esistono poi degli specifici integrati regolatori, stabilissimi, in grado di fornire delle tensioni fisse, da usare proprio in casi come questi. In questo esempio utilizzeremo un integrato regolatore di precisione per fornire 3,3V come riferimento all’ADC; questi 3,3V saranno anche il fondo scala dell’ADC, cioè la tensione per la quale il microcontrollore fornirà come misura il valore 1023. Anche in questo caso siamo svincolati dal valore dell’alimentazione di Arduino (salvo i casi della famiglia “mini”, in quanto in tal caso il fondo scala è fissato dai 3,3 V che, evidentemente, stiamo fornendo al microcontrollore tramite il pin ARef).

Protocolli seriali e comunicazione con DAC esterni a 16 bit
Quando si decide di utilizzare un DAC esterno a 16 bit, la scelta del bus di comunicazione è vitale. Sono bus seriali tutti e due, ma diversi: parliamo di I2C e SPI, o in casi specifici di I2S. Le schede Arduino con MCU a 32 bit (per esempio Arduino o Genuino Zero, MKRZero o MKR1000 con un SAMD21, e ovviamente una pletora di compatibili) sono in grado di gestire l'I2S a velocita' "da audio" ma ho paura che gli AVR no. L'I2S è un protocollo specifico per il trasporto di dati audio digitali, ideale per DAC ad alta fedeltà.
Per i modelli basati su AVR come l'Uno, si ricorre solitamente a DAC che comunicano via I2C o SPI. Se attaccando l'alimentazione esplode vuol dire che hanno sbagliato la polarità o il cablaggio, quindi la massima attenzione è d'obbligo. Un'alternativa interessante è stata vista in alcuni progetti in cui hanno attaccato il bus di un Raspberry Pi a un Raspberry Pico (RP2040) che si programma con Arduino (o microPython). Non e' la risposta alla domanda che avevi posto, ma un suggerimento per una potenziale via alternativa per gestire flussi di dati più pesanti, tipici di una risoluzione a 16 bit.
Condizionamento del segnale: partitori e protezione dei pin
Spesso ci troviamo a dover interfacciare segnali che non rientrano nel range 0-5V. Finora abbiamo “usato” Arduino in condizioni ideali, cioè applicando agli ingressi analogici solo tensioni inferiori a quella di riferimento e ci sono molte situazioni in cui questa condizione ideale è assolutamente possibile: per esempio con sensori che operano con una tensione di alimentazione di 5 V; ma cosa succede quando siamo costretti a lavorare con tensioni analogiche decisamente superiori, come ad esempio i canonici 12 V o anche 24 V di molti sensori?
Introduciamo questo primo esempio dicendo che applicare a un pin analogico un segnale con valore di tensione maggiore di quello di riferimento significa con ogni probabilità “bruciare” il micro; per questa ragione tale segnale va assolutamente ridotto in ampiezza. Questo è appunto il canonico caso applicativo in cui si ricorre all’utilizzo del partitore resistivo fisso. Con questi tre valori possiamo ricavarci il valore globale del partitore resistivo e quindi della R da applicare in serie al segnale analogico. Se non si vuole rinunciare ad ottenere un valore ben preciso che prescinda da quelli commerciali, al posto della RSensore fissa si può adottare un trimmer, possibilmente del tipo multigiri, che sarà usato con funzione di reostato, cioè di resistenza variabile, per ottenere il valore desiderato.
Inoltre, per la sicurezza dei componenti, quando si lavora con sensori alimentati a tensioni maggiori della VCC (non ha importanza invece il valore di ARef), per prevenire possibili guasti, è buona norma usare un diodo Zener, di valore leggermente superiore alla tensione di riferimento, con il catodo sul pin di Arduino ed l’anodo a GND, con una resistenza in serie per limitare la corrente.

Interfacciamento con sensori analogici e resistivi
La corretta lettura di un sensore è il primo passo per una conversione DAC accurata in un sistema di controllo feedback. Nel caso dei sensori di tipo resistivo, essi devono essere inseriti in un circuito, il cosiddetto “partitore resistivo variabile” che, alimentato esternamente, è in grado di generare una tensione più o meno proporzionale alla variazione del valore resistivo del sensore; in poche parole, inserendo un sensore passivo in un idoneo circuito alimentato, lo si trasforma in un sensore attivo che, come tale, può essere letto direttamente dal pin analogico di Arduino.
Un esempio classico è il termistore NTC. Ogni tipo di NTC ha delle specifiche che sono fondamentalmente il valore in ohm in relazione alla temperatura; in genere viene espresso il valore in ohm ad una temperatura di 25°C. Per meglio comprendere questi concetti, un NTC modello TDC 310 può operare in un range di temperatura da -20°C a +120°C, con un range ohmico che va rispettivamente da 90 kΩ a 380Ω. Creando un grafico di comparazione ci si rende subito conto che, seppur sia riscontrabile una certa proporzionalità inversa tra di essi, di fatto non c’è una linearità che possa essere usata in una formula matematica semplice senza compensazioni software.
Stabiliamo di usare come resistenza di pull-down una 10 kΩ e alimentiamo a 5 V il partitore costituito dall’NTC e dalla pull-down; nello specifico questa scelta è dettata dal fatto che il data-sheet di questo sensore riporta che il valore di resistenza a 25°C è appunto di 10 kΩ, quindi a questa temperatura ci aspettiamo un segnale di ampiezza pari a metà dell’alimentazione. Naturalmente darà un risultato diverso ad ogni temperatura in quanto RSensore è un valore variabile. In altri casi, come con l'LM35, il sensore è collegabile direttamente ad un pin analogico di Arduino, in quanto, per leggere temperature positive è alimentabile con una tensione di alimentazione uguale a quella di Arduino. In questo caso non serve un convertitore ma un amplificatore in tensione, in grado di portare il segnale almeno a 5÷10 millivolt (mV) per °C che sono direttamente misurabili dall’ADC di Arduino.
TUTTO CIO' CHE DEVI SAPERE SULLA FREQUENZA DI CAMPIONAMENTO!
Ottimizzazione della precisione: filtri e oversampling
Purtroppo Arduino, almeno nei modelli base testati da noi, non possiede sistemi di filtraggio hardware avanzati integrati, e l’unico applicabile è il filtro sull’ARef. Per migliorare la qualità della lettura e, di riflesso, l'accuratezza del segnale che andremo a generare con un DAC a 16 bit, possiamo ricorrere a tecniche software come l'oversampling. La tecnica consiste nell’acquisire 4^n sample, ove n è il numero di bit da guadagnare, sommarli e dividerli per 2^n. Questo approccio permette di aumentare virtualmente la risoluzione dell'ADC, riducendo il rumore di fondo.
Se dobbiamo invece gestire un segnale digitale proveniente da sensori che generano due livelli logici, ma a volte hanno tensioni di funzionamento maggiori rispetto ai 5 V di Arduino, dobbiamo agire con cautela. Anche qui conosciamo sia la tensione del segnale analogico che quella di riferimento per l’ADC; decidiamo di usare come pull-down una resistenza da 10 kΩ. Se ad esempio dobbiamo ridurre un segnale da 12V a 5V, stavolta decidiamo di usare un resistore di pull-down da 3,3 kΩ. Il valore commerciale più prossimo a 6.600 ohm è 6,8 kΩ, almeno il primo valore immediatamente superiore, per garantire che la tensione non superi mai i 5V sicuri.
Scelta del DAC a 16 bit e integrazione finale
Arrivati al punto di dover scegliere un DAC da 16 bit integrato, sorgono dubbi legittimi: devo necessariamente utilizzare un DAC da 8bit o da 10bit? La risposta dipende dall'applicazione. Se l'obiettivo è produrre audio di alta qualità o tensioni di riferimento per strumenti di laboratorio, i 16 bit sono indispensabili. La risoluzione di Arduino dipende proprio dalla struttura dell'Atmega328P o dal codice al suo interno? La risoluzione dell'ADC interno è fissa a 10 bit per via hardware, mentre il PWM è tipicamente a 8 bit. Un DAC esterno, invece, permette di superare queste barriere fisiche.
Un'uscita a 10 bit ha 1024 valori distinti, mentre una a 16 bit ne ha 65.536. Questa differenza è abissale quando si cerca di eliminare i gradini di tensione nel segnale di uscita. Per implementare correttamente un DAC a 16 bit come il PCM5102 (I2S) o il MCP4725 (che è a 12 bit, ma spesso usato come scalino intermedio) o modelli più professionali della Texas Instruments o Analog Devices, è necessario studiare bene il datasheet. Nel caso del sensore che farà la parte della resistenza di sensore, l’unico valore da calcolare sarà quello di pull-down per bilanciare il range dinamico.
Bisogna avere almeno il buon senso di chiedere e vedere che strada prende il post nei forum di supporto, poiché spesso le soluzioni alternative come l'uso di microcontroller a 32 bit o l'aggiunta di integrati dedicati risolvono problemi che il semplice Atmega328P non può gestire efficientemente da solo. La conversione di un segnale PWM in un segnale analogico pulito 0-5V senza filtro RC richiede obbligatoriamente un DAC che riceva il valore numerico tramite bus seriale e lo trasformi in una tensione costante e precisa.

tags: #arduino #convertitore #dac #16 #bit