3.19. UART i kod¶
machine.UART omsluter en hårdvaru-UART-kanal. Skapa en med buss-id och en baudhastighet; allt annat har rimliga standardvärden:
from machine import UART
uart = UART(3, baudrate=115200)
id väljer vilken hårdvaru-UART som ska användas; värdet beror på kortet (se OpenMV-kort för tillgängliga bussnummer och stifttilldelningar på en given kamera). Standardbitramsformatet är 8 databitar, ingen paritet, en stoppbit – det ”8N1” som alla förväntar sig.
3.19.1. Skriva och läsa¶
UART-utdata går genom write():
uart.write("hello\n")
uart.write(b"\x01\x02\x03")
write accepterar antingen en str (kodad som UTF-8) eller en bytes / bytearray. Den återvänder omedelbart när bytena har köats i TX-bufferten; hårdvaran klockar färdigt ut dem i bakgrunden.
Läsningar sker genom tre metoder, beroende på vad som behövs:
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() kontrollerar RX-bufferten utan att blockera. read() läser ett fast antal byte och returnerar None om timeouten (konfigurerbar via argumentet timeout i konstruktorn) löper ut först. readline() läser fram till och inklusive nästa radslut, användbart för radbaserade protokoll.
En enkel loop som ekar tillbaka allt den tar emot:
uart = UART(3, baudrate=115200, timeout=100)
while True:
if uart.any():
data = uart.read()
uart.write(data)
read() utan längdargument fortsätter läsa byte tills mottagningsledningen är tyst under den konfigurerade timeout, och returnerar sedan det som ackumulerats. Med timeout=100 returnerar varje anrop här en skur av byte – allt som sändaren klockade ut utan ett 100 ms gap mellan byten. Utan en timeout skulle anropet inte ha någon signal om att sändaren är klar och kunde hänga sig på obestämd tid.
3.19.2. Binärdata med struct¶
Att skicka heltal och flyttal över ledningen är vad modulen struct är till för. Den packar värden med fast bredd till ett bytes-objekt med hjälp av en formatsträng som anger byteordningen och typen för varje fält:
import struct
uart.write(struct.pack("<lhb", count, temperature_x100, status))
Det inledande "<" väljer little-endian-byteordning; "l" är ett 32-bitars heltal med tecken, "h" är ett 16-bitars heltal med tecken, "b" är ett 8-bitars heltal med tecken. Den andra sidan packar upp med samma formatsträng:
payload = uart.read(7) # 4 + 2 + 1 = 7 bytes
count, temperature_x100, status = struct.unpack("<lhb", payload)
Formatsträngen är kontraktet mellan de två ändarna. Varje avvikelse – fel byteordning, fel typstorlekar, fel fältordning – ger nonsensvärden.
3.19.3. Buffring och läsningar med hög hastighet¶
En pollningsloop som anropar any() och read() hänger med i det mesta av trafiken på egen hand, så länge huvudloopen itererar tillräckligt snabbt för att tömma mottagningsbufferten innan den fylls. Två konstruktoralternativ spelar roll när hastigheten ökar eller loopen är upptagen.
rxbuf anger storleken på mjukvarans RX-buffert. Standardvärdet är några hundra byte; för sensorer som sänder hundratals byte per skur, eller när huvudloopen utför långa arbeten mellan pollningar, hindrar en större buffert inkommande byte från att tappas medan loopen är upptagen någon annanstans:
uart = UART(3, baudrate=115200, timeout=100, rxbuf=4096)
Allt som anländer medan bufferten är full går förlorat; dimensionera rxbuf för att täcka det längsta gapet mellan tömningarna.
För ihållande höga hastigheter läser readinto() in i en förallokerad buffert i stället för att returnera ett nytt bytes-objekt vid varje anrop:
buf = bytearray(256)
while True:
n = uart.readinto(buf)
if n:
process(buf, n)
Ingen allokering sker på läsvägen, vilket spelar roll när heapen är fragmenterad eller när allokeringslatensen annars skulle pressa förbi tidsbudgeten mellan byten.