3.12. Odczyt sygnałów analogowych za pomocą ADC

Do tej pory kamera odczytywała sygnały cyfrowe – pin jest albo 0, albo 1, przełącznik jest otwarty lub zamknięty. Większość sygnałów pochodzących z rzeczywistych sensorów ma charakter analogowy: jest to ciągłe napięcie, które płynnie zmienia się w pewnym zakresie. Fotorezystor przechodzi przez wszystkie napięcia między szynami zasilania w miarę zmian jasności otoczenia. Wyjście sensora temperatury dryfuje o kilka miliwoltów, gdy pomieszczenie się nagrzewa. Wyjście mikrofonu rośnie i opada wraz z otaczającym go dźwiękiem.

Przetwornik analogowo-cyfrowy (ADC) jest pomostem między tymi światami. Próbkuje napięcie na pinie i zwraca liczbę całkowitą, którą Python może odczytać jak każdą inną wartość.

3.12.1. Kwantyzacja

Wartość cyfrowa nie może dokładnie odwzorować ciągłego napięcia. Zadaniem ADC jest kwantyzacja – przypisanie każdej próbki do najbliższego z ustalonego zbioru poziomów. N-bitowy ADC ma 2^N poziomów; przetwornik 12-bitowy ma ich 4096 rozłożonych w zakresie wejściowym.

Gładka krzywa analogowa wykreślona w funkcji czasu, na którą nałożono schodkową aproksymację cyfrową. Przerywane linie poziome oznaczają poziomy kwantyzacji; krzywa schodkowa przeskakuje do poziomu najbliższego sygnałowi analogowemu w każdym punkcie próbkowania.

Kwantyzacja: każda próbka sygnału analogowego (linia ciągła) jest zaokrąglana do jednego ze skończonego zbioru poziomów cyfrowych (schodkowa linia przerywana).

Napięcie pomiędzy dwoma sąsiednimi poziomami to rozdzielczość kroku (step size) ADC; cokolwiek mniejszego znika w zaokrągleniu. 12-bitowy ADC w zakresie 3,3 V ma krok wynoszący około 3.3 / 4096 0.8 mV – na tyle drobny, że w oprogramowaniu większość sygnałów wygląda praktycznie na ciągłe.

3.12.2. Klasa machine.ADC

machine.ADC obejmuje jeden analogowy kanał wejściowy. Utwórz jej instancję z pinem, który chcesz odczytywać, a następnie wywołaj read_u16():

from machine import ADC

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

read_u16() zawsze zwraca 16-bitową liczbę całkowitą bez znaku z zakresu od 0 do 65535. Natywna rozdzielczość ADC zależy od płytki (12 bitów na STM32, zależnie od portu w innych przypadkach); wynik jest wyrównany do lewej w obrębie 16 bitów, dzięki czemu szczegóły sprzętowe nie przenikają do Pythona – wartość 65535 oznacza pełną skalę niezależnie od układu.

Napięcie odniesienia – wejście odpowiadające pełnej skali – zależy od płytki. Sprawdź Płytki OpenMV, aby poznać wartość dla swojej kamery. Wszystko powyżej napięcia odniesienia jest odczytywane jako pełna skala (i może uszkodzić pin, jeśli przekroczy bezwzględne maksymalne napięcie wejściowe).

3.12.2.1. Przeliczanie zliczeń na napięcie

Odwzorowanie zliczeń na napięcie jest liniowe, przy czym zliczenia pełnej skali odpowiadają dokładnie Vref:

voltage = counts × Vref / 65535

W kodzie:

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

3.12.3. Dzielniki napięcia

Dwa rezystory połączone szeregowo między szyną napięcia a masą tworzą dzielnik napięcia. Węzeł między nimi przyjmuje napięcie wyznaczone przez stosunek obu rezystorów:

Dzielnik napięcia. Vin na górze łączy się przez R1 z węzłem odprowadzanym jako V_out, który następnie łączy się przez R2 z masą.

Dzielnik napięcia: R1 i R2 połączone szeregowo skalują Vin w dół do V_out.

V_out = Vin × R2 / (R1 + R2)

Równe rezystory dają połowę napięcia szyny; R2 znacznie mniejszy niż R1 umieszcza punkt odprowadzenia blisko masy; R2 znacznie większy umieszcza go blisko szyny.

Wzór zakłada, że nic innego nie pobiera zauważalnego prądu z V_out. Pin ADC ma wysoką impedancję (megaomy, nanoampery) i z łatwością spełnia to założenie, więc dzielnik zasilający ADC zachowuje się tak, jak przewiduje wzór.

3.12.4. Potencjometry

Potencjometr to pojedynczy fizyczny element, który stanowi dokładnie dzielnik napięcia, z przesuwnym ślizgaczem przemieszczającym punkt odprowadzenia między dwoma końcami. Obracanie pokrętła zmienia jednocześnie R1 i R2, utrzymując ich sumę (całkowitą rezystancję potencjometru) na stałym poziomie.

Potencjometr podłączony między 3,3 V a masą. Ślizgacz jest odprowadzony do pinu ADC.

Potencjometr podłączony jako ręczne źródło napięcia dla ADC: 3,3 V na jednym końcu, masa na drugim, ślizgacz do pinu.

Potencjometr to kanoniczne urządzenie wejściowe do wypróbowania ADC. Podłącz jeden koniec do 3.3 V, drugi do masy, a ślizgacz do pinu obsługującego ADC; obracanie pokrętła przesuwa ślizgacz przez wszystkie napięcia między szynami.

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. Odczyt wyższych napięć za pomocą dzielnika

Napięcie powyżej Vref ustawi ADC na pełnej skali i może uszkodzić wejście, jeśli przekroczy bezwzględną wartość maksymalną. Aby odczytać wyższe źródło – baterię, wyjście sensora wykraczające poza Vref – przeskaluj je w dół za pomocą stałego dzielnika napięcia, zanim dotrze do pinu:

Dzielnik napięcia skalujący wysokie V_in w dół do pinu ADC. R1 prowadzi od V_in w dół do węzła, który jest odprowadzany poziomo do pinu ADC; R2 biegnie dalej od węzła w dół do masy.

Skalowanie źródła wysokiego napięcia tak, aby pasowało do ADC: R1 i R2 tworzą stały dzielnik napięcia, którego punkt odprowadzenia zasila pin ADC.

Dobierz R1 i R2 tak, aby podzielone napięcie pozostawało w zakresie ADC przy najwyższym spodziewanym napięciu wejściowym:

V_adc = V_in × R2 / (R1 + R2)

Dla maksymalnego V_in = 12 V i napięcia odniesienia 3,3 V stosunek R2 / (R1 + R2) musi wynosić co najwyżej 3.3 / 12 0.275. Częstym wyborem z niewielkim zapasem jest R1 = 33 , R2 = 10 . Stosunek wynosi 10 / 43 0.233, więc V_adc osiąga maksymalnie około 12 × 0.233 2.79 V – bezpiecznie poniżej Vref.

Aby odzyskać oryginalne V_in z odczytu ADC, odwróć wzór dzielnika:

V_in = V_adc × (R1 + R2) / R2

W kodzie:

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

Kilka praktycznych uwag:

  • Dzielnik pobiera w sposób ciągły V_in / (R1 + R2). Przy R1 + R2 = 43 i V_in = 12 V to około 280 µA – zwykle pomijalne, ale jeśli źródło jest zasilane bateryjnie, rozważ większe rezystory (od 100 kΩ do 1 MΩ), aby ograniczyć pobór w stanie spoczynku.

  • Tolerancja rezystorów (zwykle ±1 % lub ±5 %) bezpośrednio wpływa na dokładność pomiaru. Dwa rezystory ±5 % mogą dać odzyskanemu V_in błąd w najgorszym przypadku rzędu ±10 %.

  • Impedancja źródłowa dzielnika łączy się z dowolną pojemnością pasożytniczą, dolnoprzepustowo filtrując wejście. W przypadku szybko zmieniających się sygnałów ma to znaczenie; w przypadku sprawdzania napięcia baterii nie ma.