3.17. Tokovi bitova i mjerenje impulsa

Nekim uređajima trebaju precizno vremenski mjereni obrasci impulsa umjesto PWM signala konstantne frekvencije. WS2812 RGB LED kodira svaki bit kao impuls određene širine; HC-SR04 ultrazvučni daljinomjer odgovara odjekom čija je širina vrijeme povratnog leta; IR daljinski upravljač šalje zaglavlje praćeno podatkovnim bitovima kao nizove uključeno-isključeno.

machine modul ima dvije funkcije za ovu vrstu vremenski preciznog GPIO-a:

  • bitstream() šalje niz impulsa sa zasebnim tempiranjem za 0 i 1 bitove.

  • time_pulse_us() mjeri širinu dolaznog impulsa u mikrosekundama.

3.17.1. Slanje toka bitova

machine.bitstream() uzima pin, kodiranje, specifikaciju tempiranja i bajtove za slanje. Najuobičajenije kodiranje (0) je modulacija trajanja impulsa visoko-nisko: svaki bit je visoki impuls jedne širine praćen niskim impulsom druge, pri čemu 0 i 1 bitovi imaju različita tempiranja.

Dva poredana valna oblika. Gornji prikazuje 0 bit:  kratak visoki impuls (high_0) praćen duljim niskim periodom (low_0). Donji prikazuje 1 bit: dulji visoki impuls (high_1) praćen kraćim niskim periodom (low_1).

Kodiranje trajanja impulsa visoko-nisko: 0 i 1 svaki se sastoje od visoke faze praćene niskom fazom, s različitim širinama.

Kanonski primjer je WS2812 (NeoPixel) RGB LED, koji očekuje bitove na 800 kHz s ovim tempiranjima:

  • 0: 400 ns visoko, zatim 850 ns nisko.

  • 1: 800 ns visoko, zatim 450 ns nisko.

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 bit-banga impulse na traženim širinama; na kamerama dovoljno brzim za to tempiranje je točno do unutar desetaka nanosekundi.

Upozorenje

bitstream() onemogućuje sve prekide za cijelo trajanje prijenosa kako bi mogao zadržati preciznu kontrolu nad tempiranjem impulsa. Trajanje poziva raste linearno s brojem bajtova – pri WS2812 tempiranju (oko 10 µs po bajtu), slanje 100 bajtova pauzira CPU za otprilike 1 ms, 1000 bajtova za 10 ms, a 10000 bajtova za punih 100 ms. Sve preko nekoliko stotina bajtova po pozivu riskira primjetna zaglavljivanja – razbijte duga ažuriranja na manje dijelove, s pozivom koji se vraća između svakog dijela kako bi se ostatak skripte mogao izvršiti.

Napomena

Za pogon WS2812 / NeoPixel traka posebno, neopixel modul obavija bitstream() u sučelje više razine koje rukuje preraspodjelom redoslijeda boja i skupnim ažuriranjima trake. Posegnite izravno za bitstream() kada protokol nije WS2812, ali se i dalje uklapa u oblik visoko-nisko PDM.

3.17.2. Mjerenje dolaznog impulsa

machine.time_pulse_us() mjeri širinu jednog impulsa na pinu. Čeka da linija dosegne navedenu razinu (početak impulsa), zatim mjeri koliko dugo linija ostaje na toj razini (kraj impulsa) i vraća trajanje u mikrosekundama.

Klasična primjena je HC-SR04 ultrazvučni senzor udaljenosti. Kamera šalje 10 µs okidni impuls, zatim čeka da pin odjeka vrati impuls čija je širina vrijeme povratnog puta zvuka:

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)

Treći argument je vremensko ograničenje u mikrosekundama, primijenjeno zasebno na „čekaj da impuls počne” i „čekaj da impuls završi”. Pri isteku vremena funkcija vraća negativnu vrijednost koja identificira koja je faza zakazala: -2 ako impuls nikada nije počeo, -1 ako je počeo, ali nikada nije završio unutar prozora.

Obje polovice vremenskog ograničenja važne su za stvarne senzore. HC-SR04 može trebati jednu do dvije milisekunde da pokrene svoj odjek, a sam odjek može biti dug desetke milisekundi za daleke objekte. Dimenzioniranje timeout_us na maksimalni potreban domet drži mjerenje ograničenim.