3.19. UART în cod¶
machine.UART încapsulează un canal UART hardware. Construiți unul cu id-ul magistralei și o rată baud; restul are valori implicite rezonabile:
from machine import UART
uart = UART(3, baudrate=115200)
id selectează care UART hardware se folosește; valoarea depinde de placă (consultați Plăci OpenMV pentru numerele de magistrală disponibile și atribuirile de pini pe o anumită cameră). Formatul implicit al cadrului este de 8 biți de date, fără paritate, un bit de stop – formatul „8N1” pe care toată lumea îl așteaptă.
3.19.1. Scriere și citire¶
Ieșirea UART trece prin write():
uart.write("hello\n")
uart.write(b"\x01\x02\x03")
write acceptă fie un str (codificat ca UTF-8), fie un obiect bytes / bytearray. Returnează imediat ce octeții sunt puși în coada tamponului (buffer) TX; hardware-ul termină de transmis în fundal.
Citirile se fac prin trei metode, în funcție de ce este necesar:
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() verifică tamponul (buffer) RX fără a bloca. read() citește un număr fix de octeți, returnând None dacă timeout-ul (configurabil prin argumentul timeout din constructor) expiră mai întâi. readline() citește până la și inclusiv următoarea linie nouă, fiind util pentru protocoalele bazate pe linii.
O buclă simplă care reflectă tot ce primește:
uart = UART(3, baudrate=115200, timeout=100)
while True:
if uart.any():
data = uart.read()
uart.write(data)
read() fără argument de lungime continuă să citească octeți până când linia de recepție rămâne tăcută pentru durata timeout configurată, apoi returnează tot ce a fost acumulat. Cu timeout=100, fiecare apel de aici returnează o rafală de octeți – tot ce a transmis expeditorul fără o pauză de 100 ms între octeți. Fără un timeout, apelul nu ar avea niciun semnal că expeditorul a terminat și s-ar putea bloca la nesfârșit.
3.19.2. Date binare cu struct¶
Trimiterea de numere întregi și de numere în virgulă mobilă pe fir este exact scopul modulului struct. Acesta împachetează valori cu lățime fixă într-un obiect bytes folosind un șir de format care precizează ordinea octeților și tipul fiecărui câmp:
import struct
uart.write(struct.pack("<lhb", count, temperature_x100, status))
Caracterul "<" de la început alege ordinea octeților little-endian; "l" este un întreg cu semn pe 32 de biți, "h" este un întreg cu semn pe 16 biți, "b" este un întreg cu semn pe 8 biți. Cealaltă parte despachetează cu același șir de format:
payload = uart.read(7) # 4 + 2 + 1 = 7 bytes
count, temperature_x100, status = struct.unpack("<lhb", payload)
Șirul de format este contractul dintre cele două capete. Orice nepotrivire – ordine greșită a octeților, dimensiuni greșite ale tipurilor, ordine greșită a câmpurilor – produce valori absurde.
3.19.3. Tamponarea (buffering) și citirile la rată ridicată¶
O buclă de interogare care apelează any() și read() ține pasul cu majoritatea traficului de una singură, atât timp cât bucla principală iterează suficient de rapid pentru a goli tamponul (buffer) de recepție înainte ca acesta să se umple. Două opțiuni ale constructorului contează atunci când rata crește sau bucla este ocupată.
rxbuf stabilește dimensiunea tamponului (buffer) RX software. Valoarea implicită este de câteva sute de octeți; pentru senzorii care emit sute de octeți pe rafală, sau când bucla principală execută operații lungi între interogări, mărirea tamponului (buffer) împiedică pierderea octeților sosiți cât timp bucla este ocupată în altă parte:
uart = UART(3, baudrate=115200, timeout=100, rxbuf=4096)
Tot ce sosește cât timp tamponul (buffer) este plin se pierde; dimensionați rxbuf astfel încât să acopere cel mai lung interval dintre goliri.
Pentru rate ridicate susținute, readinto() citește într-un tampon (buffer) prealocat în loc să returneze un obiect bytes nou la fiecare apel:
buf = bytearray(256)
while True:
n = uart.readinto(buf)
if n:
process(buf, n)
Pe traseul de citire nu are loc nicio alocare, ceea ce contează atunci când heap-ul este fragmentat sau când latența alocării ar depăși altfel bugetul de temporizare dintre octeți.