3.17. Aliran bit dan pengukuran pulsa¶
Beberapa perangkat membutuhkan pola pulsa yang ditentukan waktu secara presisi, bukan sinyal PWM frekuensi konstan. LED RGB WS2812 mengenkode setiap bit sebagai pulsa dengan lebar tertentu; ranger ultrasonik HC-SR04 merespons dengan pulsa gema yang lebarnya adalah waktu penerbangan pulang-pergi; remote IR mengirim header diikuti oleh bit data sebagai urutan on-off.
Modul machine memiliki dua fungsi untuk jenis GPIO yang presisi waktu ini:
bitstream()mengirim rangkaian pulsa dengan timing terpisah untuk bit0dan1.time_pulse_us()mengukur lebar pulsa masuk dalam mikrodetik.
3.17.1. Mengirim aliran bit¶
machine.bitstream() mengambil pin, encoding, spesifikasi timing, dan byte yang akan dikirim. Encoding paling umum (0) adalah modulasi durasi pulsa high-low: setiap bit adalah pulsa high dengan satu lebar diikuti oleh pulsa low dengan lebar lainnya, dengan bit 0 dan 1 memiliki timing yang berbeda.
Encoding modulasi durasi pulsa high-low: bit 0 dan 1 masing-masing terdiri dari fase high diikuti oleh fase low, dengan lebar yang berbeda.¶
Contoh kanonik adalah LED RGB WS2812 (NeoPixel), yang mengharapkan bit pada 800 kHz dengan timing berikut:
0: 400 ns high, kemudian 850 ns low.1: 800 ns high, kemudian 450 ns low.
from machine import Pin, bitstream
pin = Pin("P7", Pin.OUT)
# (high_0, low_0, high_1, low_1) in nanoseconds
timing = (400, 850, 800, 450)
# one LED: GRB order, three bytes per LED (red shown here)
bitstream(pin, 0, timing, b"\x00\xff\x00")
MCU melakukan bit-bang pulsa pada lebar yang diminta; pada kamera yang cukup cepat, timing akurat hingga dalam puluhan nanodetik.
Peringatan
bitstream() menonaktifkan semua interupsi selama seluruh transmisi agar dapat menjaga kontrol presisi atas timing pulsa. Durasi panggilan bertambah secara linier dengan jumlah byte -- pada timing WS2812 (sekitar 10 µs per byte), mengirim 100 byte menjeda CPU selama sekitar 1 ms, 1000 byte selama 10 ms, dan 10000 byte selama 100 ms penuh. Apa pun yang melebihi beberapa ratus byte per panggilan berisiko menyebabkan lock-up yang terasa -- pecah pembaruan panjang menjadi chunk yang lebih kecil, dengan panggilan yang kembali di antara setiap chunk agar sisa skrip dapat berjalan.
Catatan
Untuk menggerakkan strip WS2812 / NeoPixel khususnya, modul neopixel membungkus bitstream() dalam antarmuka tingkat tinggi yang menangani pengacakan urutan warna dan pembaruan strip massal. Gunakan bitstream() secara langsung ketika protokolnya bukan WS2812 tetapi masih cocok dengan bentuk PDM high-low.
3.17.2. Mengukur pulsa masuk¶
machine.time_pulse_us() mengukur lebar satu pulsa pada sebuah pin. Ia menunggu garis mencapai level yang ditentukan (awal pulsa), kemudian mengukur berapa lama garis tetap pada level tersebut (akhir pulsa), dan mengembalikan durasi dalam mikrodetik.
Penggunaan klasik adalah sensor jarak ultrasonik HC-SR04. Kamera mengirim pulsa trigger 10 µs, kemudian menunggu pin gema mengembalikan pulsa yang lebarnya adalah waktu pulang-pergi suara:
import time
from machine import Pin, time_pulse_us
trigger = Pin("P7", Pin.OUT, value=0)
echo = Pin("P8", Pin.IN)
while True:
trigger.value(1)
time.sleep_us(10)
trigger.value(0)
width = time_pulse_us(echo, 1, timeout_us=30_000)
if width > 0:
# sound at ~343 m/s; round trip / 2 / 343 = distance (m)
distance_cm = (width * 343) / 2 / 10_000
print(distance_cm, "cm")
time.sleep_ms(100)
Argumen ketiga adalah timeout dalam mikrodetik, diterapkan secara terpisah pada "tunggu pulsa mulai" dan "tunggu pulsa berakhir". Saat timeout, fungsi mengembalikan nilai negatif yang mengidentifikasi fase mana yang gagal: -2 jika pulsa tidak pernah dimulai, -1 jika dimulai tetapi tidak pernah berakhir dalam jendela waktu.
Kedua bagian timeout penting untuk sensor nyata. HC-SR04 dapat membutuhkan satu hingga dua milidetik untuk memulai gemanya, dan gema itu sendiri dapat berlangsung puluhan milidetik untuk objek yang jauh. Mengatur ukuran timeout_us ke jangkauan maksimum yang dibutuhkan menjaga pengukuran tetap terbatas.