3.17. ビットストリームとパルス測定¶
デバイスによっては、一定周波数のPWM信号ではなく、精密にタイミングを取ったパルスパターンを必要とします。WS2812 RGB LEDは各ビットを特定の幅のパルスとしてエンコードし、HC-SR04超音波測距センサーは幅が往復飛行時間であるエコーパルスで応答し、IRリモコンはヘッダーに続いてデータビットをオンオフのシーケンスとして送ります。
machine モジュールには、この種のタイミング精度が必要なGPIO向けに2つの関数があります。
bitstream()は、0ビットと1ビットで別々のタイミングを使ってパルス列を送信します。time_pulse_us()は、入力されるパルスの幅をマイクロ秒単位で測定します。
3.17.1. ビットストリームの送信¶
machine.bitstream() は、ピン、エンコーディング、タイミング指定、そして送信するバイト列を受け取ります。最も一般的なエンコーディング(0)は ハイ・ロー パルス幅変調です。各ビットはある幅のハイパルスに続いて別の幅のローパルスで構成され、0 ビットと 1 ビットは異なるタイミングを持ちます。
ハイ・ローパルス幅エンコーディング: 0 と 1 はそれぞれ、ハイ期間に続いてロー期間で構成され、幅が異なります。¶
代表的な例はWS2812(NeoPixel)RGB LEDで、800 kHzで次のタイミングのビットを期待します。
0: 400 nsハイ、その後850 nsロー。1: 800 nsハイ、その後450 nsロー。
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は要求された幅でパルスをビットバンギングします。それに十分速いカメラでは、タイミングは数十ナノ秒以内の精度です。
警告
bitstream() は、パルスタイミングを精密に制御し続けるため、送信全体の間すべての割り込みを無効にします。呼び出し時間はバイト数に比例して増えます。WS2812のタイミング(1バイトあたり約10 µs)では、100バイトの送信でCPUが約1ミリ秒、1000バイトで10ミリ秒、10000バイトでまるまる100ミリ秒一時停止します。1回の呼び出しで数百バイトを超えると、目に見えるロックアップを引き起こすおそれがあります。長い更新は小さなチャンクに分割し、各チャンクの間に呼び出しを戻して、スクリプトの残りの部分を実行できるようにしてください。
注釈
特にWS2812 / NeoPixelストリップの駆動については、neopixel モジュールが bitstream() をより高レベルのインターフェースでラップし、カラー順序の入れ替えやストリップの一括更新を処理します。プロトコルがWS2812では ない もののハイ・ローPDMの形に収まる場合は、bitstream() を直接使ってください。
3.17.2. 入力されるパルスの測定¶
machine.time_pulse_us() は、ピン上の単一のパルスの幅を測定します。指定したレベルに線が達するの(パルスの開始)を待ち、その後線がそのレベルにとどまる時間(パルスの終了)を測定し、その持続時間をマイクロ秒単位で返します。
典型的な用途はHC-SR04超音波距離センサーです。カメラは10 µsのトリガーパルスを送り、その後、幅が音の往復時間であるパルスをエコーピンが返すのを待ちます。
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)
3番目の引数はマイクロ秒単位のタイムアウトで、「パルスの開始を待つ」と「パルスの終了を待つ」に別々に適用されます。タイムアウト時、関数はどの段階が失敗したかを示す負の値を返します。パルスが開始しなかった場合は -2、開始したものの時間内に終了しなかった場合は -1 です。
実際のセンサーでは、タイムアウトの両方の半分が重要です。HC-SR04はエコーの開始に1~2ミリ秒かかることがあり、遠い物体ではエコー自体が数十ミリ秒に及ぶこともあります。timeout_us を必要な最大範囲に合わせてサイズ調整することで、測定を有界に保てます。