3.17. Flujos de bits y medición de pulsos¶
Algunos dispositivos necesitan patrones de pulsos temporizados con precisión en lugar de una señal PWM de frecuencia constante. Un LED RGB WS2812 codifica cada bit como un pulso de un ancho específico; un telémetro ultrasónico HC-SR04 responde con un pulso de eco cuyo ancho es el tiempo de vuelo de ida y vuelta; un mando a distancia por infrarrojos envía una cabecera seguida de bits de datos como secuencias de encendido y apagado.
El módulo machine tiene dos funciones para este tipo de GPIO de temporización precisa:
bitstream()envía un tren de pulsos con una temporización distinta para los bits0y1.time_pulse_us()mide el ancho de un pulso entrante en microsegundos.
3.17.1. Enviar un flujo de bits¶
machine.bitstream() toma un pin, una codificación, una especificación de temporización y los bytes a enviar. La codificación más común (0) es la modulación por duración de pulso alto-bajo: cada bit es un pulso alto de un ancho seguido de un pulso bajo de otro, con los bits 0 y 1 teniendo temporizaciones distintas.
La codificación por duración de pulso alto-bajo: un 0 y un 1 constan cada uno de una fase alta seguida de una fase baja, con anchos distintos.¶
El ejemplo canónico es el LED RGB WS2812 (NeoPixel), que espera bits a 800 kHz con estas temporizaciones:
0: 400 ns en alto, luego 850 ns en bajo.1: 800 ns en alto, luego 450 ns en bajo.
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")
El MCU genera los pulsos por bit-banging a los anchos solicitados; en las cámaras lo bastante rápidas, la temporización es precisa hasta dentro de decenas de nanosegundos.
Advertencia
bitstream() deshabilita todas las interrupciones durante toda la transmisión para poder mantener un control preciso de la temporización de los pulsos. La duración de la llamada crece linealmente con el número de bytes: a la temporización del WS2812 (unos 10 µs por byte), enviar 100 bytes pausa la CPU durante aproximadamente 1 ms, 1000 bytes durante 10 ms y 10000 bytes durante unos 100 ms completos. Cualquier cosa más allá de unos pocos cientos de bytes por llamada corre el riesgo de bloqueos perceptibles: divide las actualizaciones largas en fragmentos más pequeños, con la llamada retornando entre cada fragmento para que el resto del script pueda ejecutarse.
Nota
Para controlar tiras WS2812 / NeoPixel en particular, el módulo neopixel envuelve bitstream() en una interfaz de más alto nivel que se encarga del reordenamiento del orden de los colores y de las actualizaciones masivas de la tira. Recurre directamente a bitstream() cuando el protocolo no sea WS2812 pero aun así encaje en una forma PDM alto-bajo.
3.17.2. Medir un pulso entrante¶
machine.time_pulse_us() mide el ancho de un único pulso en un pin. Espera a que la línea alcance el nivel especificado (el inicio del pulso), luego mide cuánto tiempo permanece la línea en ese nivel (el final del pulso) y devuelve la duración en microsegundos.
El uso clásico es un sensor de distancia ultrasónico HC-SR04. La cámara envía un pulso de disparo de 10 µs y luego espera a que el pin de eco devuelva un pulso cuyo ancho es el tiempo de ida y vuelta del sonido:
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)
El tercer argumento es el tiempo de espera en microsegundos, aplicado por separado a «esperar a que comience el pulso» y «esperar a que termine el pulso». Al agotarse el tiempo de espera, la función devuelve un valor negativo que identifica qué fase falló: -2 si el pulso nunca comenzó, -1 si comenzó pero nunca terminó dentro de la ventana.
Ambas mitades del tiempo de espera importan para sensores reales. Un HC-SR04 puede tardar de uno a dos milisegundos en iniciar su eco, y el eco en sí puede durar decenas de milisegundos para objetos lejanos. Dimensionar timeout_us al alcance máximo necesario mantiene la medición acotada.