3.17. Бітові потоки та вимірювання імпульсів¶
Деякі пристрої потребують точно відтимінгованих імпульсних шаблонів, а не постійночастотного PWM сигналу. RGB LED WS2812 кодує кожен біт як імпульс певної ширини; ультразвуковий далекомір HC-SR04 відповідає луна-імпульсом, ширина якого – це час польоту в обидва боки; ІЧ-пульт надсилає заголовок, за яким слідують біти даних у вигляді послідовностей увімк./вимк.
Модуль machine має дві функції для такого GPIO з точним таймінгом:
bitstream()надсилає імпульсний потік з окремим таймінгом для бітів0і1.time_pulse_us()вимірює ширину вхідного імпульсу в мікросекундах.
3.17.1. Надсилання бітового потоку¶
machine.bitstream() приймає вивід, кодування, специфікацію таймінгу та байти для відправлення. Найпоширеніше кодування (0) – це high-low імпульсно-тривалісна модуляція: кожен біт – це високий імпульс однієї ширини, за яким слідує низький імпульс іншої, причому біти 0 і 1 мають різний таймінг.
Кодування high-low імпульсно-тривалісною модуляцією: 0 і 1 кожен складається з високої фази, за якою слідує низька, з різною шириною.¶
Канонічний приклад – RGB LED WS2812 (NeoPixel), який очікує біти на 800 кГц з таким таймінгом:
0: 400 нс високий, потім 850 нс низький.1: 800 нс високий, потім 450 нс низький.
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 формує імпульси програмно з запитаною шириною; на достатньо швидких камерах точність таймінгу становить десятки наносекунд.
Попередження
bitstream() вимикає всі переривання на весь час передачі, щоб зберегти точний контроль над таймінгом імпульсів. Тривалість виклику лінійно залежить від кількості байт – при таймінгу WS2812 (близько 10 мкс на байт) відправлення 100 байт зупиняє процесор приблизно на 1 мс, 1000 байт – на 10 мс, а 10000 байт – на повні 100 мс. Більше кількох сотень байт за виклик ризикує викликати помітні зависання – розбивайте довгі оновлення на менші частини, щоб між ними виклик повертався та решта скрипту могла виконуватися.
Примітка
Для керування стрічками WS2812 / NeoPixel зокрема модуль neopixel обгортає bitstream() в інтерфейс вищого рівня, який обробляє перестановку порядку кольорів та масові оновлення стрічки. Вдавайтеся до bitstream() безпосередньо, коли протокол не є WS2812, але все ще відповідає формі high-low PDM.
3.17.2. Вимірювання вхідного імпульсу¶
machine.time_pulse_us() вимірює ширину одного імпульсу на виводі. Він очікує, доки лінія досягне вказаного рівня (початок імпульсу), потім вимірює, як довго лінія залишається на цьому рівні (кінець імпульсу), і повертає тривалість у мікросекундах.
Класичне застосування – ультразвуковий датчик відстані HC-SR04. Камера надсилає тригерний імпульс 10 мкс, потім очікує, доки луна-вивід поверне імпульс, ширина якого – час зворотного польоту звуку:
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)
Третій аргумент – тайм-аут у мікросекундах, що застосовується окремо до «очікування початку імпульсу» і «очікування кінця імпульсу». При тайм-ауті функція повертає від’ємне значення, яке ідентифікує невдалу фазу: -2 якщо імпульс так і не розпочався, -1 якщо він розпочався, але так і не завершився в межах вікна.
Обидві половини тайм-ауту важливі для реальних датчиків. HC-SR04 може витрачати від однієї до двох мілісекунд на початок відлуння, а саме відлуння може тривати десятки мілісекунд для далеких об’єктів. Визначення timeout_us відповідно до необхідного максимального діапазону тримає вимірювання в обмежених рамках.