3.17. Bitstromen en pulsmeting¶
Sommige apparaten hebben nauwkeurig getimede pulspatronen nodig in plaats van een PWM-signaal met constante frequentie. Een WS2812 RGB-led codeert elk bit als een puls van een specifieke breedte; een HC-SR04 ultrasone afstandsmeter antwoordt met een echopuls waarvan de breedte de retourvliegtijd is; een IR-afstandsbediening verzendt een header gevolgd door databits als aan-uit-sequenties.
De machine-module heeft twee functies voor dit soort timingnauwkeurige GPIO:
bitstream()verzendt een pulsreeks met een aparte timing voor0- en1-bits.time_pulse_us()meet de breedte van een binnenkomende puls in microseconden.
3.17.1. Een bitstroom verzenden¶
machine.bitstream() neemt een pin, een codering, een timingspecificatie en de te verzenden bytes. De meest voorkomende codering (0) is hoog-laag pulsduurmodulatie: elk bit is een hoge puls van de ene breedte gevolgd door een lage puls van een andere, waarbij 0- en 1-bits verschillende timings hebben.
De hoog-laag pulsduurcodering: een 0 en een 1 bestaan elk uit een hoge fase gevolgd door een lage fase, met verschillende breedtes.¶
Het canonieke voorbeeld is de WS2812 (NeoPixel) RGB-led, die bits op 800 kHz verwacht met deze timings:
0: 400 ns hoog, dan 850 ns laag.1: 800 ns hoog, dan 450 ns laag.
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")
De MCU bit-bangt de pulsen op de gevraagde breedtes; op cams die er snel genoeg voor zijn is de timing nauwkeurig tot op enkele tientallen nanoseconden.
Waarschuwing
bitstream() schakelt alle interrupts uit gedurende de hele transmissie, zodat het de pulstiming nauwkeurig onder controle kan houden. De aanroepduur schaalt lineair met het aantal bytes – bij WS2812-timing (ongeveer 10 µs per byte) pauzeert het verzenden van 100 bytes de CPU ongeveer 1 ms, 1000 bytes 10 ms en 10000 bytes een volle 100 ms. Alles boven enkele honderden bytes per aanroep riskeert merkbare bevriezingen – splits lange updates op in kleinere brokken, waarbij de aanroep tussen elk brok terugkeert zodat de rest van het script kan draaien.
Notitie
Specifiek voor het aansturen van WS2812-/NeoPixel-strips verpakt de neopixel-module bitstream() in een interface op hoger niveau die het herschikken van de kleurvolgorde en bulk-strip-updates afhandelt. Gebruik bitstream() rechtstreeks wanneer het protocol geen WS2812 is maar toch in een hoog-laag PDM-vorm past.
3.17.2. Een binnenkomende puls meten¶
machine.time_pulse_us() meet de breedte van een enkele puls op een pin. Het wacht tot de lijn het opgegeven niveau bereikt (het begin van de puls), meet vervolgens hoe lang de lijn op dat niveau blijft (het einde van de puls), en geeft de duur in microseconden terug.
Het klassieke gebruik is een HC-SR04 ultrasone afstandssensor. De camera verzendt een triggerpuls van 10 µs en wacht vervolgens tot de echopin een puls teruggeeft waarvan de breedte de retourtijd van het geluid is:
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)
Het derde argument is de time-out in microseconden, afzonderlijk toegepast op “wacht tot de puls begint” en “wacht tot de puls eindigt”. Bij een time-out geeft de functie een negatieve waarde terug die aangeeft welke fase mislukte: -2 als de puls nooit begon, -1 als hij begon maar nooit eindigde binnen het venster.
Beide helften van de time-out zijn van belang voor echte sensoren. Een HC-SR04 kan één tot twee milliseconden nodig hebben om zijn echo te starten, en de echo zelf kan tientallen milliseconden lang zijn voor verre objecten. Het afstemmen van timeout_us op het maximaal benodigde bereik houdt de meting begrensd.