3.12. Membaca sinyal analog dengan ADC

Selama ini kamera membaca sinyal digital -- sebuah pin bernilai 0 atau 1, sebuah sakelar terbuka atau tertutup. Namun sebagian besar sinyal yang dihasilkan sensor di dunia nyata bersifat analog: tegangan kontinu yang berubah secara halus dalam suatu rentang. Fotoresistor menyapu setiap tegangan antara kedua rel saat kecerahan sekitar berubah. Keluaran sensor suhu bergeser beberapa milivolt saat suhu ruangan naik. Keluaran mikrofon naik turun mengikuti suara di sekitarnya.

Sebuah konverter analog-ke-digital (ADC) adalah jembatannya. ADC mengambil sampel tegangan pada sebuah pin dan mengembalikan bilangan bulat yang dapat dibaca Python seperti nilai lainnya.

3.12.1. Kuantisasi

Nilai digital tidak dapat merepresentasikan tegangan kontinu secara tepat. Tugas ADC adalah mengkuantisasi -- membulatkan setiap sampel ke nilai terdekat dari sekumpulan level yang sudah ditentukan. ADC N-bit memiliki 2^N level; konverter 12-bit memiliki 4096 level yang tersebar di seluruh rentang masukannya.

A smooth analog curve plotted against time, overlaid with a stepped digital approximation. Dashed horizontal lines mark the quantization levels; the stepped curve snaps to whichever level is nearest the analog signal at each sample point.

Kuantisasi: setiap sampel sinyal analog (garis penuh) dibulatkan ke salah satu dari sekumpulan level digital yang terbatas (garis putus-putus bertangga).

Tegangan antara dua level yang berdekatan adalah ukuran langkah ADC; nilai yang lebih kecil dari itu akan hilang dalam pembulatan. ADC 12-bit pada rentang 3,3 V memiliki ukuran langkah sekitar 3.3 / 4096 0.8 mV -- cukup kecil sehingga sebagian besar sinyal terlihat kontinu secara efektif dalam perangkat lunak.

3.12.2. Kelas machine.ADC

machine.ADC membungkus satu saluran masukan analog. Buatlah dengan pin yang ingin dibaca, lalu panggil read_u16():

from machine import ADC

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

read_u16() selalu mengembalikan bilangan bulat 16-bit tak bertanda antara 0 dan 65535. Resolusi ADC asli bervariasi per board (12-bit pada STM32, bergantung port di tempat lain); hasilnya disejajarkan ke kiri dalam 16 bit sehingga detail perangkat keras tidak bocor ke Python -- nilai 65535 adalah skala penuh tanpa memandang chipnya.

Tegangan referensi -- masukan yang berkorespondensi dengan skala penuh -- bergantung pada board. Periksa Papan OpenMV untuk nilai pada kamera Anda. Tegangan di atas referensi akan terbaca sebagai skala penuh (dan dapat merusak pin jika melebihi tegangan masukan maksimum absolut).

3.12.2.1. Mengonversi hitungan ke tegangan

Pemetaan dari hitungan ke tegangan bersifat linear, dengan hitungan skala penuh yang memetakan tepat ke Vref:

voltage = counts × Vref / 65535

Dalam kode:

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

3.12.3. Pembagi tegangan

Dua resistor yang dihubungkan seri antara rel tegangan dan ground membentuk sebuah pembagi tegangan. Node di antara keduanya berada pada tegangan yang ditentukan oleh rasio kedua resistor:

A voltage divider. Vin at the top connects through R1 to a node tapped off as V_out, which then connects through R2 to ground.

Pembagi tegangan: R1 dan R2 yang dihubungkan seri menurunkan Vin menjadi V_out.

V_out = Vin × R2 / (R1 + R2)

Resistor yang sama memberikan setengah tegangan rel; R2 yang jauh lebih kecil dari R1 menempatkan sadapan mendekati ground; R2 yang jauh lebih besar menempatkannya mendekati rel.

Rumus ini mengasumsikan tidak ada beban lain yang menarik arus signifikan dari V_out. Pin ADC berimpedansi tinggi (megaohm, nanoampere) dan dengan mudah memenuhi syarat itu, sehingga pembagi yang mengumpan ADC berperilaku sesuai rumus.

3.12.4. Potensiometer

Sebuah potensiometer adalah satu komponen fisik yang pada dasarnya merupakan pembagi tegangan, dengan penghapus geser yang memindahkan sadapan di antara dua ujungnya. Memutar tombol mengubah R1 dan R2 bersama-sama sembari menjaga jumlah keduanya (total resistansi pot) tetap konstan.

A potentiometer wired between 3.3 V and ground. The wiper is tapped off to an ADC pin.

Potensiometer yang diwiring sebagai sumber tegangan manual untuk ADC: 3,3 V di satu ujung, ground di ujung lain, penghapus ke pin.

Pot adalah perangkat masukan kanonik untuk mencoba ADC. Sambungkan satu ujung ke 3.3 V, ujung lainnya ke ground, dan penghapus ke pin berkemampuan ADC; memutar tombol menyapu penghapus melalui setiap tegangan antara kedua rel.

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. Membaca tegangan lebih tinggi dengan pembagi

Tegangan di atas Vref akan memaku ADC pada skala penuh dan dapat merusak masukan jika melebihi rating maksimum absolut. Untuk membaca sumber yang lebih tinggi -- baterai, keluaran sensor yang melampaui Vref -- turunkan skalanya dengan pembagi tegangan tetap sebelum mencapai pin:

A voltage divider scaling a high V_in down to an ADC pin. R1 runs from V_in down to a junction, which is tapped off horizontally to the ADC pin; R2 continues from the junction down to ground.

Menurunkan skala sumber tegangan tinggi agar sesuai ADC: R1 dan R2 membentuk pembagi tegangan tetap yang sadapannya mengumpan pin ADC.

Pilih R1 dan R2 agar tegangan yang dibagi tetap berada dalam rentang ADC pada tegangan masukan tertinggi yang Anda harapkan:

V_adc = V_in × R2 / (R1 + R2)

Untuk V_in = 12 V maksimum dan referensi 3,3 V, rasio R2 / (R1 + R2) harus paling besar 3.3 / 12 0.275. Pilihan umum dengan sedikit headroom adalah R1 = 33 , R2 = 10 . Rasinya adalah 10 / 43 0.233, sehingga V_adc mencapai puncak sekitar 12 × 0.233 2.79 V -- dengan aman di bawah Vref.

Untuk memulihkan V_in asli dari bacaan ADC, balikkan rumus pembagi:

V_in = V_adc × (R1 + R2) / R2

Dalam kode:

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

Beberapa catatan praktis:

  • Pembagi menarik arus V_in / (R1 + R2) secara terus-menerus. Dengan R1 + R2 = 43 dan V_in = 12 V, itu sekitar 280 µA -- biasanya dapat diabaikan, tetapi jika sumbernya bertenaga baterai pertimbangkan resistor yang lebih besar (100 kΩ hingga 1 MΩ) untuk mengurangi konsumsi daya saat idle.

  • Toleransi resistor (biasanya ±1% atau ±5%) langsung memengaruhi akurasi pengukuran. Dua resistor ±5% dapat memberikan kesalahan kasus terburuk sekitar ±10% pada V_in yang dipulihkan.

  • Impedansi sumber pembagi bergabung dengan kapasitansi liar untuk memfilter masukan secara low-pass. Untuk sinyal yang berubah cepat hal ini penting; untuk pemeriksaan tegangan baterai, tidak.