3.19. UART trong code¶
machine.UART bọc một kênh UART phần cứng. Khởi tạo với id bus và tốc độ baud; mọi thứ khác có giá trị mặc định hợp lý:
from machine import UART
uart = UART(3, baudrate=115200)
id chọn UART phần cứng nào sẽ dùng; giá trị phụ thuộc vào bo mạch (xem Bo mạch OpenMV để biết số bus và chân giao tiếp trên từng cam). Định dạng khung mặc định là 8 bit dữ liệu, không chẵn lẻ, một bit dừng -- "8N1" mà ai cũng mong đợi.
3.19.1. Ghi và đọc¶
Dữ liệu đầu ra UART đi qua write():
uart.write("hello\n")
uart.write(b"\x01\x02\x03")
write chấp nhận str (được mã hóa UTF-8) hoặc bytes / bytearray. Nó trả về ngay khi các byte đã được đưa vào hàng đợi trong bộ đệm TX; phần cứng hoàn tất việc đồng hồ ra trong nền.
Đọc dữ liệu thông qua ba phương thức, tùy thuộc vào nhu cầu:
n = uart.any() # bytes available to read right now
data = uart.read(8) # up to 8 bytes, or None on timeout
line = uart.readline() # bytes ending in '\n', or None on timeout
any() kiểm tra bộ đệm RX mà không chặn. read() đọc một số byte cố định, trả về None nếu hết thời gian chờ (có thể cấu hình qua tham số timeout trong hàm khởi tạo). readline() đọc cho đến và bao gồm ký tự xuống dòng tiếp theo, hữu ích cho các giao thức dựa trên dòng.
Một vòng lặp đơn giản phản hồi lại mọi thứ nhận được:
uart = UART(3, baudrate=115200, timeout=100)
while True:
if uart.any():
data = uart.read()
uart.write(data)
read() không có đối số độ dài tiếp tục đọc byte cho đến khi đường nhận im lặng trong khoảng thời gian timeout đã cấu hình, rồi trả về những gì đã tích lũy được. Với timeout=100, mỗi lần gọi ở đây trả về một loạt byte -- tất cả những gì bên gửi đã truyền ra mà không có khoảng dừng 100 ms giữa các byte. Nếu không có timeout, lệnh gọi sẽ không có tín hiệu cho biết bên gửi đã xong và có thể treo vô thời hạn.
3.19.2. Dữ liệu nhị phân với struct¶
Gửi số nguyên và số thực qua đường dây chính là mục đích của module struct. Nó đóng gói các giá trị độ rộng cố định vào đối tượng bytes bằng chuỗi định dạng đặt tên thứ tự byte và kiểu của từng trường:
import struct
uart.write(struct.pack("<lhb", count, temperature_x100, status))
"<" đứng đầu chọn thứ tự byte little-endian; "l" là số nguyên có dấu 32-bit, "h" là số nguyên có dấu 16-bit, "b" là số nguyên có dấu 8-bit. Phía bên kia giải nén với cùng chuỗi định dạng:
payload = uart.read(7) # 4 + 2 + 1 = 7 bytes
count, temperature_x100, status = struct.unpack("<lhb", payload)
Chuỗi định dạng là hợp đồng giữa hai đầu. Bất kỳ sự không khớp nào -- thứ tự byte sai, kích thước kiểu sai, thứ tự trường sai -- đều tạo ra các giá trị vô nghĩa.
3.19.3. Bộ đệm và đọc tốc độ cao¶
Vòng lặp polling gọi any() và read() có thể theo kịp hầu hết lưu lượng, miễn là vòng lặp chính lặp đủ nhanh để xả bộ đệm thu trước khi đầy. Hai tùy chọn trong hàm khởi tạo quan trọng khi tốc độ tăng cao hoặc vòng lặp bận.
rxbuf đặt kích thước bộ đệm RX phần mềm. Mặc định là vài trăm byte; đối với cảm biến phát ra hàng trăm byte mỗi lần, hoặc khi vòng lặp chính làm việc dài giữa các lần poll, việc mở rộng bộ đệm giúp byte đến không bị mất trong khi vòng lặp đang bận ở nơi khác:
uart = UART(3, baudrate=115200, timeout=100, rxbuf=4096)
Bất kỳ dữ liệu nào đến khi bộ đệm đầy đều bị mất; hãy đặt kích thước rxbuf đủ để bao phủ khoảng dừng dài nhất giữa các lần xả.
Đối với tốc độ cao liên tục, readinto() đọc vào bộ đệm được cấp phát sẵn thay vì trả về đối tượng bytes mới mỗi lần gọi:
buf = bytearray(256)
while True:
n = uart.readinto(buf)
if n:
process(buf, n)
Không có việc cấp phát nào xảy ra trên đường đọc, điều này quan trọng khi heap bị phân mảnh hoặc khi độ trễ cấp phát sẽ vượt quá ngân sách thời gian giữa các byte.