3.17. Bitströme und Pulsmessung¶
Manche Geräte benötigen präzise getaktete Pulsmuster statt eines PWM-Signals mit konstanter Frequenz. Eine WS2812-RGB-LED kodiert jedes Bit als Puls einer bestimmten Breite; ein HC-SR04-Ultraschall-Entfernungsmesser antwortet mit einem Echopuls, dessen Breite der Hin- und Rücklaufzeit entspricht; eine IR-Fernbedienung sendet einen Header gefolgt von Datenbits als An-Aus-Sequenzen.
Das machine-Modul hat zwei Funktionen für diese Art von zeitpräziser GPIO:
bitstream()sendet einen Pulszug mit separater Zeitsteuerung für0- und1-Bits.time_pulse_us()misst die Breite eines eingehenden Pulses in Mikrosekunden.
3.17.1. Senden eines Bitstroms¶
machine.bitstream() nimmt einen Pin, eine Kodierung, eine Zeitspezifikation und die zu sendenden Bytes entgegen. Die häufigste Kodierung (0) ist die High-Low-Pulsdauermodulation: Jedes Bit ist ein High-Puls einer Breite gefolgt von einem Low-Puls einer anderen Breite, wobei 0- und 1-Bits unterschiedliche Zeitsteuerungen haben.
Die High-Low-Pulsdauer-Kodierung: eine 0 und eine 1 bestehen jeweils aus einer High-Phase gefolgt von einer Low-Phase, mit unterschiedlichen Breiten.¶
Das kanonische Beispiel ist die WS2812 (NeoPixel)-RGB-LED, die Bits mit 800 kHz und diesen Zeitsteuerungen erwartet:
0: 400 ns high, dann 850 ns low.1: 800 ns high, dann 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")
Der MCU erzeugt die Pulse per Bit-Banging mit den geforderten Breiten; auf Kameras, die schnell genug dafür sind, ist die Zeitsteuerung auf einige zehn Nanosekunden genau.
Warnung
bitstream() deaktiviert für die gesamte Übertragung alle Interrupts, damit es die präzise Kontrolle über die Pulszeitsteuerung behalten kann. Die Aufrufdauer skaliert linear mit der Anzahl der Bytes – bei WS2812-Zeitsteuerung (etwa 10 µs pro Byte) pausiert das Senden von 100 Bytes die CPU für rund 1 ms, 1000 Bytes für 10 ms und 10000 Bytes für volle 100 ms. Alles über ein paar hundert Bytes pro Aufruf birgt das Risiko spürbarer Aussetzer – teilen Sie lange Aktualisierungen in kleinere Abschnitte auf, wobei der Aufruf zwischen jedem Abschnitt zurückkehrt, damit der Rest des Skripts laufen kann.
Bemerkung
Speziell zum Ansteuern von WS2812-/NeoPixel-Strips kapselt das neopixel-Modul bitstream() in einer übergeordneten Schnittstelle, die das Umsortieren der Farbreihenfolge und die Massenaktualisierung von Strips übernimmt. Greifen Sie direkt zu bitstream(), wenn das Protokoll nicht WS2812 ist, aber dennoch in eine High-Low-PDM-Form passt.
3.17.2. Messen eines eingehenden Pulses¶
machine.time_pulse_us() misst die Breite eines einzelnen Pulses an einem Pin. Sie wartet, bis die Leitung den angegebenen Pegel erreicht (Beginn des Pulses), misst dann, wie lange die Leitung auf diesem Pegel bleibt (Ende des Pulses), und gibt die Dauer in Mikrosekunden zurück.
Der klassische Anwendungsfall ist ein HC-SR04-Ultraschall-Entfernungssensor. Die Kamera sendet einen 10-µs-Triggerpuls und wartet dann darauf, dass der Echo-Pin einen Puls zurückgibt, dessen Breite der Hin- und Rücklaufzeit des Schalls entspricht:
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)
Das dritte Argument ist der Timeout in Mikrosekunden, der separat auf „auf den Beginn des Pulses warten“ und „auf das Ende des Pulses warten“ angewendet wird. Bei einem Timeout gibt die Funktion einen negativen Wert zurück, der angibt, welche Phase fehlgeschlagen ist: -2, wenn der Puls nie begonnen hat, -1, wenn er begonnen, aber nie innerhalb des Fensters geendet hat.
Beide Hälften des Timeouts sind für reale Sensoren wichtig. Ein HC-SR04 kann ein bis zwei Millisekunden brauchen, um sein Echo zu starten, und das Echo selbst kann bei weit entfernten Objekten mehrere zehn Millisekunden lang sein. timeout_us auf die maximal benötigte Reichweite zu dimensionieren, hält die Messung begrenzt.