3.12. Analóg jel olvasása az ADC-vel

Eddig a kamera digitális jeleket olvasott – egy láb értéke vagy 0, vagy 1, egy kapcsoló nyitva van vagy zárva. A valós érzékelőkből érkező jelek többsége azonban analóg: folytonos feszültség, amely valamilyen tartományon belül simán változik. Egy fotoellenállás a környezeti fényerő változásával végigfut a tápfeszültségek közötti minden feszültségen. Egy hőmérséklet-érzékelő kimenete néhány millivolttal elcsúszik, ahogy egy szoba felmelegszik. Egy mikrofon kimenete a körülötte lévő hangok hatására emelkedik és süllyed.

Az analóg-digitális átalakító (ADC) jelenti a hidat. Megméri egy láb feszültségét, és olyan egész számot ad vissza, amelyet a Python bármely más értékhez hasonlóan ki tud olvasni.

3.12.1. Kvantálás

Egy digitális érték nem tud pontosan ábrázolni egy folytonos feszültséget. Az ADC feladata a kvantálás – minden mintát a rögzített szintkészlet legközelebbi értékéhez igazít. Egy N bites ADC-nek 2^N szintje van; egy 12 bites átalakítónak 4096 szintje, amely a bemeneti tartományán oszlik el.

Egy sima analóg görbe az idő függvényében ábrázolva, amelyre egy lépcsős digitális közelítés van rávetítve. Szaggatott vízszintes vonalak jelölik a kvantálási szinteket; a lépcsős görbe minden egyes mintavételi pontnál ahhoz a szinthez igazodik, amelyik legközelebb van az analóg jelhez.

Kvantálás: az analóg jel (folytonos) minden mintáját a digitális szintek véges készletének egyikéhez kerekítik (lépcsős szaggatott vonal).

Két szomszédos szint közötti feszültség az ADC lépésköze; minden ennél kisebb érték elvész a kerekítés során. Egy 12 bites ADC 3,3 V-os tartományon körülbelül 3.3 / 4096 0.8 mV lépésközzel rendelkezik – ez elég finom ahhoz, hogy a legtöbb jel szoftverben gyakorlatilag folytonosnak tűnjön.

3.12.2. A machine.ADC osztály

A machine.ADC egyetlen analóg bemeneti csatornát fog be. Hozd létre azzal a lábbal, amelyet olvasni szeretnél, majd hívd meg a read_u16() metódust:

from machine import ADC

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

A read_u16() mindig egy 0 és 65535 közötti előjel nélküli 16 bites egész számot ad vissza. A natív ADC-felbontás kártyánként eltér (STM32-n 12 bit, máshol portfüggő); az eredmény balra igazítva kerül a 16 bitbe, így a hardveres részlet nem szivárog be a Pythonba – a 65535 érték a chiptől függetlenül teljes kitérést jelent.

A referenciafeszültség – az a bemenet, amely a teljes kitéréshez tartozik – a kártyától függ. Ellenőrizd a kamerád értékét a OpenMV kártyák oldalon. A referencia feletti bármilyen érték teljes kitérésként jelenik meg (és károsíthatja a lábat, ha meghaladja az abszolút maximális bemeneti feszültséget).

3.12.2.1. Számértékek átváltása feszültséggé

A számértékekről feszültségre való leképezés lineáris, ahol a teljes kitéréshez tartozó számérték pontosan a Vref értékre képeződik le:

voltage = counts × Vref / 65535

Kódban:

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

3.12.3. Feszültségosztók

Egy tápfeszültség és a föld közé sorba kötött két ellenállás feszültségosztót alkot. A köztük lévő csomópont a két ellenállás arányával beállított feszültségen helyezkedik el:

Egy feszültségosztó. A felül lévő Vin az R1-en keresztül kapcsolódik egy csomóponthoz, amelyről V_out van leágaztatva, és amely ezután az R2-n keresztül kapcsolódik a földhöz.

Egy feszültségosztó: az R1 és R2 sorba kötve a Vin értéket V_out értékre csökkenti.

V_out = Vin × R2 / (R1 + R2)

Az egyenlő ellenállások a tápfeszültség felét adják; az R1-nél jóval kisebb R2 a leágazást a földhöz közelíti; a jóval nagyobb R2 a tápfeszültséghez közelíti.

A képlet feltételezi, hogy semmi más nem vesz fel számottevő áramot a V_out csomópontból. Egy ADC-láb nagy impedanciájú (megohmok, nanoamperek), és ezt könnyen teljesíti, így egy ADC-t tápláló osztó a képlet által megjósolt módon viselkedik.

3.12.4. Potenciométerek

A potenciométer egyetlen fizikai alkatrész, amely pontosan egy feszültségosztó, csúszó kefével, amely a leágazást a két vég között mozgatja. A gomb elforgatása együtt változtatja az R1 és R2 értékét, miközben az összegüket (a potenciométer teljes ellenállását) állandó értéken tartja.

Egy 3,3 V és a föld közé bekötött potenciométer. A kefe egy ADC-lábra van leágaztatva.

Egy potenciométer az ADC kézi feszültségforrásaként bekötve: 3,3 V az egyik végén, föld a másikon, a kefe a lábra kötve.

A potenciométer a kézenfekvő bemeneti eszköz az ADC kipróbálásához. Kösd az egyik végét a 3.3 V-ra, a másikat a földre, a kefét pedig egy ADC-képes lábra; a gomb elforgatása a kefét végigfuttatja a tápfeszültségek közötti minden feszültségen.

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. Nagyobb feszültségek olvasása osztóval

A Vref feletti feszültség az ADC-t teljes kitérésre kényszeríti, és károsíthatja a bemenetet, ha meghaladja az abszolút maximális értéket. Egy nagyobb forrás olvasásához – egy akkumulátor, egy érzékelő kimenete, amely a Vref fölé terjed – csökkentsd le egy rögzített feszültségosztóval, mielőtt eléri a lábat:

Egy feszültségosztó, amely egy magas V_in értéket egy ADC-lábra csökkent. Az R1 a V_in-től lefelé fut egy csomópontig, amely vízszintesen le van ágaztatva az ADC-lábra; az R2 a csomóponttól folytatódik lefelé a földig.

Egy nagyfeszültségű forrás méretezése az ADC-hez: az R1 és R2 rögzített feszültségosztót alkot, amelynek leágazása az ADC-lábat táplálja.

Válaszd meg úgy az R1 és R2 értékét, hogy az osztott feszültség a várt legnagyobb bemeneti feszültségnél is az ADC tartományán belül maradjon:

V_adc = V_in × R2 / (R1 + R2)

Egy V_in = 12 V maximum és egy 3,3 V-os referencia esetén az R2 / (R1 + R2) aránynak legfeljebb 3.3 / 12 0.275 értékűnek kell lennie. Egy kis ráhagyással gyakori választás az R1 = 33 , R2 = 10 . Az arány 10 / 43 0.233, így a V_adc legfeljebb körülbelül 12 × 0.233 2.79 V-on tetőzik – biztonságosan a Vref alatt.

Az eredeti V_in visszaszámításához egy ADC-leolvasásból fordítsd meg az osztóképletet:

V_in = V_adc × (R1 + R2) / R2

Kódban:

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éhány gyakorlati megjegyzés:

  • Az osztó folyamatosan felvesz V_in / (R1 + R2) áramot. R1 + R2 = 43 és V_in = 12 V esetén ez körülbelül 280 µA – általában elhanyagolható, de ha a forrás akkumulátorról működik, fontold meg nagyobb ellenállások (100 kΩ-tól 1 MΩ-ig) használatát az üresjárati fogyasztás csökkentésére.

  • Az ellenállás tűrése (jellemzően ±1 % vagy ±5 %) közvetlenül kihat a mérési pontosságra. Két ±5 %-os ellenállás a visszaszámított V_in értékben legrosszabb esetben nagyjából ±10 %-os hibát okozhat.

  • Az osztó forrásimpedanciája bármilyen szórt kapacitással együtt aluláteresztő szűrőként hat a bemenetre. Gyorsan változó jeleknél ez számít; egy akkumulátorfeszültség-ellenőrzésnél nem.