3.17. זרמי ביטים ומדידת פולסים

חלק מההתקנים זקוקים לתבניות פולסים מתוזמנות בדיוק ולא לאות PWM בתדר קבוע. נורית LED מסוג WS2812 RGB מקודדת כל ביט כפולס ברוחב מסוים; מד-טווח אולטרסוני HC-SR04 עונה בפולס הד שרוחבו הוא זמן הטיסה הלוך-ושוב; שלט רחוק IR שולח כותרת ואחריה ביטי נתונים כרצפים של דלוק-כבוי.

למודול machine יש שתי פונקציות עבור סוג זה של GPIO מדויק-תזמון:

  • bitstream() שולחת רכבת פולסים עם תזמון נפרד לביטי 0 ו-1.

  • time_pulse_us() מודדת את רוחב הפולס הנכנס במיקרו-שניות.

3.17.1. שליחת זרם ביטים

machine.bitstream() מקבלת פין, קידוד, מפרט תזמון, ואת הבתים לשליחה. הקידוד הנפוץ ביותר (0) הוא אפנון משך-פולס גבוה-נמוך: כל ביט הוא פולס גבוה ברוחב אחד ואחריו פולס נמוך ברוחב אחר, כשלביטי 0 ו-1 יש תזמונים נבדלים.

Two stacked waveforms. The top one shows a 0 bit: a brief high pulse (high_0) followed by a longer low period (low_0). The bottom one shows a 1 bit: a longer high pulse (high_1) followed by a shorter low period (low_1).

קידוד משך-הפולס גבוה-נמוך: 0 ו-1 כל אחד מורכב מפאזה גבוהה ואחריה פאזה נמוכה, ברוחבים נבדלים.

הדוגמה הקנונית היא נורית WS2812 (NeoPixel) RGB LED, המצפה לביטים בתדר 800 kHz עם התזמונים הללו:

  • 0: 400 ns גבוה, ואז 850 ns נמוך.

  • 1: 800 ns גבוה, ואז 450 ns נמוך.

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-bang לפולסים ברוחבים המבוקשים; במצלמות מהירות מספיק לכך התזמון מדויק עד כדי עשרות ננו-שניות.

אזהרה

bitstream() משביתה את כל הפסיקות למשך כל השידור כדי שתוכל לשמור על שליטה מדויקת בתזמון הפולסים. משך הקריאה גדל ליניארית עם מספר הבתים – בתזמון WS2812 (כ-10 µs לבית), שליחת 100 בתים משהה את ה-CPU לכ-1 מ“ש, 1000 בתים ל-10 מ“ש, ו-10000 בתים ל-100 מ“ש מלאות. כל דבר מעבר לכמה מאות בתים לקריאה מסכן תקיעות מורגשות – פצלו עדכונים ארוכים למקטעים קטנים יותר, כשהקריאה חוזרת בין כל מקטע כדי ששאר הסקריפט יוכל לרוץ.

הערה

להנעת רצועות WS2812 / NeoPixel בפרט, מודול neopixel עוטף את bitstream() בממשק ברמה גבוהה יותר שמטפל בערבוב סדר-הצבעים ובעדכוני רצועה בכמות. פנו ל-bitstream() ישירות כשהפרוטוקול אינו WS2812 אך עדיין מתאים לצורת PDM גבוה-נמוך.

3.17.2. מדידת פולס נכנס

machine.time_pulse_us() מודדת את רוחב הפולס היחיד על פין. היא ממתינה שהקו יגיע לרמה שצוינה (תחילת הפולס), ואז מודדת כמה זמן הקו נשאר באותה רמה (סוף הפולס), ומחזירה את המשך במיקרו-שניות.

השימוש הקלאסי הוא חיישן מרחק אולטרסוני HC-SR04. המצלמה שולחת פולס trigger של 10 µs, ואז ממתינה שפין ה-echo יחזיר פולס שרוחבו הוא זמן ההלוך-ושוב של הקול:

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)

הארגומנט השלישי הוא ה-timeout במיקרו-שניות, מוחל בנפרד על ”המתן שהפולס יתחיל“ ו“המתן שהפולס יסתיים“. ב-timeout הפונקציה מחזירה ערך שלילי המזהה איזו פאזה נכשלה: -2 אם הפולס מעולם לא התחיל, -1 אם התחיל אך מעולם לא הסתיים בתוך החלון.

שני חצאי ה-timeout חשובים עבור חיישנים אמיתיים. HC-SR04 יכול לקחת מילי-שנייה עד שתיים כדי להתחיל את ההד שלו, וההד עצמו יכול להיות באורך עשרות מילי-שניות עבור עצמים רחוקים. התאמת timeout_us לטווח המרבי הנדרש שומרת על המדידה תחומה.