3.17. Bitové proudy a měření pulzů

Některá zařízení potřebují přesně časované vzory pulzů spíše než PWM signál o konstantní frekvenci. RGB LED WS2812 kóduje každý bit jako pulz určité šířky; ultrazvukový dálkoměr HC-SR04 odpovídá pulzem ozvěny, jehož šířka je doba letu tam a zpět; IR dálkové ovládání posílá hlavičku následovanou datovými bity jako sekvence zapnuto-vypnuto.

Modul machine má pro tento druh časově přesného GPIO dvě funkce:

  • bitstream() posílá sled pulzů se samostatným časováním pro bity 0 a 1.

  • time_pulse_us() měří šířku příchozího pulzu v mikrosekundách.

3.17.1. Odesílání bitového proudu

machine.bitstream() přijímá pin, kódování, specifikaci časování a bajty k odeslání. Nejběžnější kódování (0) je modulace šířky pulzu typu high-low: každý bit je vysoký pulz jedné šířky následovaný nízkým pulzem jiné šířky, přičemž bity 0 a 1 mají odlišná časování.

Dva nad sebou naskládané průběhy. Horní zobrazuje bit 0: krátký vysoký pulz (high_0) následovaný delší nízkou periodou (low_0). Dolní zobrazuje bit 1: delší vysoký pulz (high_1) následovaný kratší nízkou periodou (low_1).

Kódování šířky pulzu typu high-low: 0 i 1 se každý skládají z vysoké fáze následované nízkou fází, s odlišnými šířkami.

Kanonickým příkladem je RGB LED WS2812 (NeoPixel), která očekává bity na 800 kHz s těmito časováními:

  • 0: 400 ns vysoko, poté 850 ns nízko.

  • 1: 800 ns vysoko, poté 450 ns nízko.

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 generuje pulzy softwarovým bit-bangingem v požadovaných šířkách; na kamerách dostatečně rychlých je časování přesné na desítky nanosekund.

Varování

bitstream() zakáže po celou dobu přenosu všechna přerušení, aby si udržel přesnou kontrolu nad časováním pulzů. Doba trvání volání roste lineárně s počtem bajtů – při časování WS2812 (asi 10 µs na bajt) odeslání 100 bajtů pozastaví CPU přibližně na 1 ms, 1000 bajtů na 10 ms a 10000 bajtů na celých 100 ms. Cokoli nad několik set bajtů na volání riskuje znatelná zaseknutí – rozdělte dlouhé aktualizace na menší části, přičemž se volání mezi jednotlivými částmi vrátí, aby mohl běžet zbytek skriptu.

Poznámka

Speciálně pro řízení pásků WS2812 / NeoPixel obaluje modul neopixel funkci bitstream() do rozhraní vyšší úrovně, které řeší přeházení pořadí barev a hromadné aktualizace pásku. Po bitstream() sáhněte přímo, když protokol není WS2812, ale stále zapadá do tvaru PDM typu high-low.

3.17.2. Měření příchozího pulzu

machine.time_pulse_us() měří šířku jediného pulzu na pinu. Čeká, až vodič dosáhne zadané úrovně (začátek pulzu), poté změří, jak dlouho vodič na této úrovni zůstane (konec pulzu), a vrátí dobu trvání v mikrosekundách.

Klasickým použitím je ultrazvukový senzor vzdálenosti HC-SR04. Kamera vyšle 10µs spouštěcí pulz, poté čeká, až pin ozvěny vrátí pulz, jehož šířka je doba letu zvuku tam a zpět:

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)

Třetím argumentem je časový limit v mikrosekundách, aplikovaný samostatně na „čekání na začátek pulzu“ a „čekání na konec pulzu“. Při vypršení limitu funkce vrací zápornou hodnotu identifikující, která fáze selhala: -2, pokud pulz nikdy nezačal, -1, pokud začal, ale v rámci okna nikdy neskončil.

Pro skutečné senzory záleží na obou polovinách časového limitu. HC-SR04 může spuštění své ozvěny trvat jednu až dvě milisekundy a samotná ozvěna může být pro vzdálené objekty desítky milisekund dlouhá. Nastavení timeout_us na maximální potřebný dosah udržuje měření ohraničené.