3.17. กระแสบิตและการวัดพัลส์¶
บางอุปกรณ์ต้องการรูปแบบพัลส์ที่กำหนดเวลาอย่างแม่นยำแทนที่จะเป็นสัญญาณ PWM ความถี่คงที่ LED RGB แบบ WS2812 เข้ารหัสแต่ละบิตเป็นพัลส์ที่มีความกว้างเฉพาะ เซนเซอร์วัดระยะ HC-SR04 ตอบด้วยพัลส์ echo ที่ความกว้างคือเวลาการบินไป-กลับ รีโมต IR ส่งส่วนหัวตามด้วยบิตข้อมูลเป็นลำดับเปิด-ปิด
โมดูล machine มีสองฟังก์ชันสำหรับ GPIO ที่กำหนดเวลาแม่นยำแบบนี้:
bitstream()ส่งชุดพัลส์พร้อมเวลาแยกต่างหากสำหรับบิต0และ1time_pulse_us()วัดความกว้างของพัลส์ขาเข้าเป็นไมโครวินาที
3.17.1. การส่งกระแสบิต¶
machine.bitstream() รับพิน การเข้ารหัส ข้อกำหนดเวลา และไบต์ที่จะส่ง การเข้ารหัสที่พบบ่อยที่สุด (0) คือการมอดูเลตระยะเวลาพัลส์แบบ high-low แต่ละบิตคือพัลส์ high ความกว้างหนึ่งตามด้วยพัลส์ low อีกความกว้างหนึ่ง โดยบิต 0 และ 1 มีเวลาที่แตกต่างกัน
การเข้ารหัสระยะเวลาพัลส์แบบ high-low: บิต 0 และ 1 แต่ละตัวประกอบด้วยเฟส high ตามด้วยเฟส low โดยมีความกว้างที่แตกต่างกัน¶
ตัวอย่างมาตรฐานคือ LED RGB แบบ WS2812 (NeoPixel) ซึ่งคาดหวังบิตที่ 800 kHz พร้อมเวลาเหล่านี้:
0: high 400 ns จากนั้น low 850 ns1: 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 ให้กับระยะที่ต้องการสูงสุดช่วยให้การวัดมีขอบเขต