3.17. Bit akışları ve darbe ölçümü¶
Bazı cihazlar, sabit frekanslı bir PWM sinyali yerine hassas zamanlamalı darbe desenlerine ihtiyaç duyar. Bir WS2812 RGB LED her biti belirli bir genişlikte bir darbe olarak kodlar; bir HC-SR04 ultrasonik mesafe ölçer, genişliği gidiş-dönüş uçuş süresi olan bir yankı darbesiyle yanıt verir; bir IR uzaktan kumanda, bir başlığın ardından veri bitlerini açık-kapalı diziler olarak gönderir.
machine modülü bu tür zamanlama açısından hassas GPIO için iki fonksiyona sahiptir:
bitstream(),0ve1bitleri için ayrı zamanlamalarla bir darbe dizisi gönderir.time_pulse_us(), gelen bir darbenin genişliğini mikrosaniye cinsinden ölçer.
3.17.1. Bir bit akışı göndermek¶
machine.bitstream() bir pin, bir kodlama, bir zamanlama belirtimi ve gönderilecek baytları alır. En yaygın kodlama (0) yüksek-düşük darbe-süresi modülasyonudur: her bit, bir genişlikte bir yüksek darbenin ardından başka bir genişlikte bir düşük darbedir; 0 ve 1 bitleri farklı zamanlamalara sahiptir.
Yüksek-düşük darbe-süresi kodlaması: bir 0 ve bir 1, her biri bir yüksek aşamanın ardından bir düşük aşamadan oluşur ve farklı genişliklere sahiptir.¶
Kanonik örnek, bu zamanlamalarla 800 kHz’de bitler bekleyen WS2812 (NeoPixel) RGB LED’dir:
0: 400 ns yüksek, ardından 850 ns düşük.1: 800 ns yüksek, ardından 450 ns düşük.
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, darbeleri istenen genişliklerde bit-bang yapar; bunun için yeterince hızlı kameralarda zamanlama onlarca nanosaniye içinde doğrudur.
Uyarı
bitstream(), darbe zamanlaması üzerinde hassas kontrol sürdürebilmek için tüm iletim boyunca tüm kesmeleri devre dışı bırakır. Çağrı süresi bayt sayısıyla doğrusal olarak ölçeklenir – WS2812 zamanlamasında (bayt başına yaklaşık 10 µs), 100 bayt göndermek CPU’yu yaklaşık 1 ms, 1000 bayt 10 ms ve 10000 bayt tam 100 ms duraklatır. Çağrı başına birkaç yüz baytın ötesindeki her şey fark edilir kilitlenmeleri riske atar – uzun güncellemeleri daha küçük parçalara bölün ve betiğin geri kalanının çalışabilmesi için çağrı her parça arasında geri dönsün.
Not
Özellikle WS2812 / NeoPixel şeritlerini sürmek için neopixel modülü, bitstream() fonksiyonunu, renk sırası karıştırmasını ve toplu şerit güncellemelerini yöneten daha üst düzey bir arayüzde sarmalar. Protokol WS2812 değil ancak hâlâ bir yüksek-düşük PDM şekline uyduğunda doğrudan bitstream() fonksiyonuna başvurun.
3.17.2. Gelen bir darbeyi ölçmek¶
machine.time_pulse_us(), bir pin üzerindeki tek bir darbenin genişliğini ölçer. Hattın belirtilen seviyeye ulaşmasını (darbenin başlangıcı) bekler, ardından hattın o seviyede ne kadar kaldığını (darbenin sonu) ölçer ve süreyi mikrosaniye cinsinden döndürür.
Klasik kullanım bir HC-SR04 ultrasonik mesafe sensörüdür. Kamera 10 µs’lik bir tetikleme darbesi gönderir, ardından yankı pininin, genişliği sesin gidiş-dönüş süresi olan bir darbe döndürmesini bekler:
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)
Üçüncü argüman, mikrosaniye cinsinden zaman aşımıdır ve “darbenin başlamasını bekle” ile “darbenin bitmesini bekle” için ayrı ayrı uygulanır. Zaman aşımında fonksiyon, hangi aşamanın başarısız olduğunu tanımlayan negatif bir değer döndürür: darbe hiç başlamadıysa -2, başladıysa ancak pencere içinde hiç bitmediyse -1.
Zaman aşımının her iki yarısı da gerçek sensörler için önemlidir. Bir HC-SR04, yankısını başlatmak için bir ila iki milisaniye alabilir ve yankının kendisi uzak nesneler için onlarca milisaniye uzunluğunda olabilir. timeout_us değerini ihtiyaç duyulan maksimum menzile göre boyutlandırmak, ölçümü sınırlı tutar.