3.17. กระแสบิตและการวัดพัลส์

บางอุปกรณ์ต้องการรูปแบบพัลส์ที่กำหนดเวลาอย่างแม่นยำแทนที่จะเป็นสัญญาณ PWM ความถี่คงที่ LED RGB แบบ WS2812 เข้ารหัสแต่ละบิตเป็นพัลส์ที่มีความกว้างเฉพาะ เซนเซอร์วัดระยะ HC-SR04 ตอบด้วยพัลส์ echo ที่ความกว้างคือเวลาการบินไป-กลับ รีโมต IR ส่งส่วนหัวตามด้วยบิตข้อมูลเป็นลำดับเปิด-ปิด

โมดูล machine มีสองฟังก์ชันสำหรับ GPIO ที่กำหนดเวลาแม่นยำแบบนี้:

  • bitstream() ส่งชุดพัลส์พร้อมเวลาแยกต่างหากสำหรับบิต 0 และ 1

  • time_pulse_us() วัดความกว้างของพัลส์ขาเข้าเป็นไมโครวินาที

3.17.1. การส่งกระแสบิต

machine.bitstream() รับพิน การเข้ารหัส ข้อกำหนดเวลา และไบต์ที่จะส่ง การเข้ารหัสที่พบบ่อยที่สุด (0) คือการมอดูเลตระยะเวลาพัลส์แบบ high-low แต่ละบิตคือพัลส์ high ความกว้างหนึ่งตามด้วยพัลส์ low อีกความกว้างหนึ่ง โดยบิต 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).

การเข้ารหัสระยะเวลาพัลส์แบบ high-low: บิต 0 และ 1 แต่ละตัวประกอบด้วยเฟส high ตามด้วยเฟส low โดยมีความกว้างที่แตกต่างกัน

ตัวอย่างมาตรฐานคือ LED RGB แบบ WS2812 (NeoPixel) ซึ่งคาดหวังบิตที่ 800 kHz พร้อมเวลาเหล่านี้:

  • 0: high 400 ns จากนั้น low 850 ns

  • 1: high 800 ns จากนั้น low 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 พัลส์ที่ความกว้างที่ร้องขอ บนกล้องที่เร็วพอ เวลาจะแม่นยำในระดับสิบนาโนวินาที

Warning

bitstream() ปิดใช้งานอินเทอร์รัปต์ทั้งหมดตลอดการส่งทั้งหมดเพื่อให้ควบคุมเวลาพัลส์ได้อย่างแม่นยำ ระยะเวลาการเรียกขึ้นกับจำนวนไบต์แบบเชิงเส้น ที่เวลา WS2812 (ประมาณ 10 µs ต่อไบต์) การส่ง 100 ไบต์หยุด CPU ประมาณ 1 ms, 1000 ไบต์ 10 ms และ 10000 ไบต์ 100 ms เต็ม สิ่งใดที่เกินหลายร้อยไบต์ต่อการเรียกเสี่ยงต่อการค้างที่เห็นได้ชัด ให้แบ่งการอัปเดตยาวๆ เป็นชิ้นเล็กๆ โดยให้การเรียกกลับมาระหว่างแต่ละชิ้นเพื่อให้สคริปต์ส่วนอื่นทำงานได้

Note

สำหรับการขับ WS2812 / NeoPixel strip โดยเฉพาะ โมดูล neopixel จะห่อ bitstream() ไว้ในอินเทอร์เฟซระดับสูงที่จัดการการสลับลำดับสีและการอัปเดต strip จำนวนมาก ใช้ bitstream() โดยตรงเมื่อโปรโตคอล ไม่ใช่ WS2812 แต่ยังคงอยู่ในรูปแบบ PDM แบบ high-low

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 อาจใช้เวลาหนึ่งถึงสองมิลลิวินาทีในการเริ่ม echo และ echo เองอาจยาวหลายสิบมิลลิวินาทีสำหรับวัตถุที่อยู่ไกล การกำหนดขนาด timeout_us ให้กับระยะที่ต้องการสูงสุดช่วยให้การวัดมีขอบเขต