3.12. Läsa analoga värden med ADC:n

Hittills har kameran läst digitala signaler – ett stift är antingen 0 eller 1, en strömbrytare är öppen eller sluten. De flesta signaler som kommer från verkliga sensorer är analoga: en kontinuerlig spänning som varierar jämnt över ett visst intervall. En fotoresistor sveper genom varje spänning mellan matningsskenorna när omgivningens ljusstyrka ändras. Utsignalen från en temperatursensor driver några millivolt när ett rum värms upp. Utsignalen från en mikrofon stiger och faller med ljudet runt omkring den.

En analog-till-digital-omvandlare (ADC) är bryggan. Den samplar spänningen på ett stift och returnerar ett heltal som Python kan läsa som vilket annat värde som helst.

3.12.1. Kvantisering

Ett digitalt värde kan inte representera en kontinuerlig spänning exakt. ADC:ns uppgift är att kvantisera – snäppa varje sampel till den närmaste av en fast uppsättning nivåer. En N-bitars ADC har 2^N nivåer; en 12-bitars omvandlare har 4096 av dem utspridda över sitt inspänningsintervall.

En jämn analog kurva plottad mot tiden, överlagrad med en stegvis digital approximation. Streckade horisontella linjer markerar kvantiseringsnivåerna; den stegvisa kurvan snäpper till den nivå som är närmast den analoga signalen vid varje samplingspunkt.

Kvantisering: varje sampel av den analoga signalen (heldragen) avrundas till en av en ändlig uppsättning digitala nivåer (stegvis streckad linje).

Spänningen mellan två intilliggande nivåer är ADC:ns stegstorlek; allt mindre än så försvinner i avrundningen. En 12-bitars ADC över ett intervall på 3,3 V har en stegstorlek på ungefär 3.3 / 4096 0.8 mV – tillräckligt fint för att de flesta signaler ska se i praktiken kontinuerliga ut i mjukvaran.

3.12.2. Klassen machine.ADC

machine.ADC omsluter en analog ingångskanal. Konstruera den med det stift du vill läsa, och anropa sedan read_u16():

from machine import ADC

adc = ADC("P6")
value = adc.read_u16()
print(value)

read_u16() returnerar alltid ett 16-bitars heltal utan tecken mellan 0 och 65535. ADC:ns nativa upplösning varierar mellan kort (12-bitars på STM32, port-specifik i övrigt); resultatet vänsterjusteras in i 16 bitar så att hårdvarudetaljen inte läcker in i Python – ett värde på 65535 motsvarar fullt utslag oavsett chip.

Referensspänningen – ingången som motsvarar fullt utslag – beror på kortet. Kontrollera OpenMV-kort för värdet på din kamera. Allt över referensen läses som fullt utslag (och kan skada stiftet om det överskrider den absoluta maximala inspänningen).

3.12.2.1. Omvandla räknarvärden till spänning

Mappningen från räknarvärden till spänning är linjär, där räknarvärdet vid fullt utslag mappas exakt till Vref:

voltage = counts × Vref / 65535

I kod:

VREF = 3.3  # cam-dependent; see the quickref
counts = adc.read_u16()
voltage = counts * VREF / 65535
print(voltage, "V")

3.12.3. Spänningsdelare

Två resistorer i serie mellan en spänningsskena och jord bildar en spänningsdelare. Noden mellan dem ligger på en spänning som bestäms av förhållandet mellan de två resistorerna:

En spänningsdelare. Vin överst ansluter genom R1 till en nod som tas ut som V_out, vilken sedan ansluter genom R2 till jord.

En spänningsdelare: R1 och R2 i serie skalar ner Vin till V_out.

V_out = Vin × R2 / (R1 + R2)

Lika stora resistorer ger halva skenans spänning; R2 mycket mindre än R1 placerar uttaget nära jord; R2 mycket större placerar det nära skenan.

Formeln förutsätter att inget annat drar nämnvärd ström från V_out. Ett ADC-stift är högimpediant (megohm, nanoampere) och uppfyller detta enkelt, så en delare som matar en ADC beter sig som formeln förutsäger.

3.12.4. Potentiometrar

En potentiometer är en enda fysisk komponent som är precis en spänningsdelare, med en glidande släpkontakt som flyttar uttaget mellan de två ändarna. Att vrida på ratten ändrar R1 och R2 tillsammans samtidigt som deras summa (potentiometerns totala resistans) hålls konstant.

En potentiometer kopplad mellan 3,3 V och jord.  Släpkontakten tas ut till ett ADC-stift.

En potentiometer kopplad som en manuell spänningskälla för ADC:n: 3,3 V i ena änden, jord i den andra, släpkontakten till stiftet.

En potentiometer är standardingångsenheten för att prova ADC:n. Koppla ena änden till 3.3 V, den andra till jord och släpkontakten till ett ADC-kapabelt stift; att vrida på ratten sveper släpkontakten genom varje spänning mellan skenorna.

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. Läsa högre spänningar med en delare

En spänning över Vref låser ADC:n vid fullt utslag och kan skada ingången om den överskrider det absoluta maxvärdet. För att läsa en högre källa – ett batteri, en sensorutsignal som sträcker sig bortom Vref – skala ner den med en fast spänningsdelare innan den når stiftet:

En spänningsdelare som skalar ner en hög V_in till ett ADC- stift. R1 går från V_in ner till en förgrening, som tas ut horisontellt till ADC-stiftet; R2 fortsätter från förgreningen ner till jord.

Skala en högspänningskälla för att passa ADC:n: R1 och R2 bildar en fast spänningsdelare vars uttag matar ADC-stiftet.

Välj R1 och R2 så att den delade spänningen håller sig inom ADC:ns intervall vid den högsta inspänning du förväntar dig:

V_adc = V_in × R2 / (R1 + R2)

För en maximal V_in = 12 V och en referens på 3,3 V måste förhållandet R2 / (R1 + R2) vara högst 3.3 / 12 0.275. Ett vanligt val med lite marginal är R1 = 33 , R2 = 10 . Förhållandet är 10 / 43 0.233, så V_adc toppar vid ungefär 12 × 0.233 2.79 V – säkert under Vref.

För att återskapa den ursprungliga V_in från en ADC-avläsning, invertera delarformeln:

V_in = V_adc × (R1 + R2) / R2

I kod:

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")

Några praktiska anmärkningar:

  • Delaren drar kontinuerligt V_in / (R1 + R2). Med R1 + R2 = 43 och V_in = 12 V är det ungefär 280 µA – vanligtvis försumbart, men om källan är batteridriven bör du överväga större resistorer (100 kΩ till 1 MΩ) för att minska viloströmmen.

  • Resistorernas tolerans (vanligtvis ±1 % eller ±5 %) går direkt in i mätnoggrannheten. Två ±5 %-resistorer kan ge den återskapade V_in ett värsta-fall-fel på ungefär ±10 %.

  • Delarens källimpedans kombineras med eventuell strökapacitans och lågpassfiltrerar ingången. För snabbt föränderliga signaler spelar det roll; för en kontroll av batterispänning gör det det inte.