3.12. Leggere segnali analogici con l’ADC¶
Finora la camera ha letto segnali digitali: un pin è 0 oppure 1, un interruttore è aperto o chiuso. La maggior parte dei segnali provenienti da sensori del mondo reale è invece analogica: una tensione continua che varia in modo regolare entro un certo intervallo. Una fotoresistenza attraversa tutte le tensioni tra le alimentazioni al variare della luminosità ambientale. L’uscita di un sensore di temperatura si sposta di qualche millivolt mentre una stanza si scalda. L’uscita di un microfono sale e scende con il suono che lo circonda.
Un convertitore analogico-digitale (ADC) è il ponte tra i due mondi. Campiona la tensione su un pin e restituisce un intero che Python può leggere come qualsiasi altro valore.
3.12.1. Quantizzazione¶
Un valore digitale non può rappresentare esattamente una tensione continua. Il compito dell’ADC è quantizzare, ovvero ricondurre ogni campione al livello più vicino di un insieme fisso di livelli. Un ADC a N bit ha 2^N livelli; un convertitore a 12 bit ne ha 4096 distribuiti lungo il suo intervallo di ingresso.
Quantizzazione: ogni campione del segnale analogico (linea continua) viene arrotondato a uno di un insieme finito di livelli digitali (linea tratteggiata a gradini).¶
La tensione tra due livelli adiacenti è il passo di quantizzazione dell’ADC; qualsiasi cosa più piccola di questo valore si perde nell’arrotondamento. Un ADC a 12 bit su un intervallo di 3,3 V ha un passo di circa 3.3 / 4096 ≈ 0.8 mV, abbastanza fine perché la maggior parte dei segnali appaia di fatto continua nel software.
3.12.2. La classe machine.ADC¶
machine.ADC incapsula un singolo canale di ingresso analogico. Costruiscila con il pin che vuoi leggere, poi chiama read_u16():
from machine import ADC
adc = ADC("P6")
value = adc.read_u16()
print(value)
read_u16() restituisce sempre un intero a 16 bit senza segno compreso tra 0 e 65535. La risoluzione nativa dell’ADC varia a seconda della scheda (12 bit su STM32, specifica della porta altrove); il risultato è allineato a sinistra su 16 bit così che il dettaglio hardware non trapeli in Python: un valore di 65535 corrisponde al fondo scala indipendentemente dal chip.
La tensione di riferimento, ovvero l’ingresso che corrisponde al fondo scala, dipende dalla scheda. Consulta la Schede OpenMV per il valore relativo alla tua camera. Qualsiasi tensione superiore al riferimento viene letta come fondo scala (e può danneggiare il pin se supera la tensione di ingresso massima assoluta).
3.12.2.1. Convertire i conteggi in tensione¶
La conversione dai conteggi alla tensione è lineare, con i conteggi di fondo scala che corrispondono esattamente a Vref:
voltage = counts × Vref / 65535
In codice:
VREF = 3.3 # cam-dependent; see the quickref
counts = adc.read_u16()
voltage = counts * VREF / 65535
print(voltage, "V")
3.12.3. Partitori di tensione¶
Due resistori in serie tra un’alimentazione e massa formano un partitore di tensione. Il nodo tra i due si trova a una tensione determinata dal rapporto tra i due resistori:
Un partitore di tensione: R1 e R2 in serie riducono Vin a V_out.¶
V_out = Vin × R2 / (R1 + R2)
Resistori uguali danno metà della tensione di alimentazione; un R2 molto più piccolo di R1 porta il prelievo vicino a massa; un R2 molto più grande lo porta vicino all’alimentazione.
La formula presuppone che nient’altro assorba una corrente apprezzabile da V_out. Un pin ADC è ad alta impedenza (megaohm, nanoampere) e soddisfa facilmente questa condizione, quindi un partitore che alimenta un ADC si comporta come previsto dalla formula.
3.12.4. Potenziometri¶
Un potenziometro è un singolo componente fisico che è esattamente un partitore di tensione, dotato di un cursore scorrevole che sposta il prelievo tra i due estremi. Ruotando la manopola si modificano R1 e R2 insieme, mantenendo costante la loro somma (la resistenza totale del potenziometro).
Un potenziometro cablato come sorgente di tensione manuale per l’ADC: 3,3 V a un estremo, massa all’altro, cursore al pin.¶
Un potenziometro è il dispositivo di ingresso per eccellenza per provare l’ADC. Collega un estremo a 3.3 V, l’altro a massa e il cursore a un pin compatibile con l’ADC; ruotando la manopola il cursore attraversa tutte le tensioni tra le alimentazioni.
import time
from machine import ADC
pot = ADC("P6")
VREF = 3.3
while True:
counts = pot.read_u16()
voltage = counts * VREF / 65535
print(voltage, "V")
time.sleep_ms(100)
3.12.5. Leggere tensioni più elevate con un partitore¶
Una tensione superiore a Vref porterà l’ADC al fondo scala e può danneggiare l’ingresso se supera il valore massimo assoluto. Per leggere una sorgente più alta, come una batteria o l’uscita di un sensore che eccede Vref, riducila con un partitore di tensione fisso prima che raggiunga il pin:
Riduzione di una sorgente ad alta tensione per adattarla all’ADC: R1 e R2 formano un partitore di tensione fisso il cui prelievo alimenta il pin ADC.¶
Scegli R1 e R2 in modo che la tensione partita rimanga entro l’intervallo dell’ADC alla massima tensione di ingresso prevista:
V_adc = V_in × R2 / (R1 + R2)
Per un valore massimo V_in = 12 V e un riferimento di 3,3 V, il rapporto R2 / (R1 + R2) deve essere al più 3.3 / 12 ≈ 0.275. Una scelta comune con un po” di margine è R1 = 33 kΩ, R2 = 10 kΩ. Il rapporto è 10 / 43 ≈ 0.233, quindi V_adc raggiunge al massimo circa 12 × 0.233 ≈ 2.79 V, comodamente al di sotto di Vref.
Per ricavare la V_in originale da una lettura dell’ADC, inverti la formula del partitore:
V_in = V_adc × (R1 + R2) / R2
In codice:
from machine import ADC
R1 = 33_000
R2 = 10_000
VREF = 3.3
adc = ADC("P6")
counts = adc.read_u16()
v_adc = counts * VREF / 65535
v_in = v_adc * (R1 + R2) / R2
print(v_in, "V")
Alcune note pratiche:
Il partitore assorbe
V_in / (R1 + R2)in modo continuo. ConR1 + R2 = 43 kΩeV_in = 12 V, sono circa 280 µA: di solito trascurabili, ma se la sorgente è alimentata a batteria valuta resistori più grandi (da 100 kΩ a 1 MΩ) per ridurre l’assorbimento a riposo.La tolleranza dei resistori (tipicamente ±1 % o ±5 %) si ripercuote direttamente sull’accuratezza della misura. Due resistori al ±5 % possono dare alla
V_inricavata un errore nel caso peggiore di circa ±10 %.L’impedenza di sorgente del partitore si combina con qualsiasi capacità parassita filtrando l’ingresso come un passa-basso. Per i segnali che variano rapidamente questo conta; per il controllo della tensione di una batteria no.