3.19. UART v kódu

machine.UART obaluje jeden hardwarový UART kanál. Vytvořte instanci s id sběrnice a přenosovou rychlostí; vše ostatní má rozumné výchozí hodnoty:

from machine import UART

uart = UART(3, baudrate=115200)

Parametr id vybírá, který hardwarový UART se použije; hodnota závisí na desce (dostupná čísla sběrnic a přiřazení pinů na dané kameře najdete v Desky OpenMV). Výchozí formát snímku je 8 datových bitů, žádná parita, jeden stop bit – tedy „8N1“, které všichni očekávají.

3.19.1. Zápis a čtení

Výstup UART prochází přes write():

uart.write("hello\n")
uart.write(b"\x01\x02\x03")

write přijímá buď str (zakódovaný jako UTF-8), nebo bytes / bytearray. Vrací se ihned, jakmile jsou bajty zařazeny do TX bufferu; hardware je na pozadí dokončí odeslat.

Čtení probíhá prostřednictvím tří metod, podle toho, co je potřeba:

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() kontroluje RX buffer bez blokování. read() přečte pevný počet bajtů a vrátí None, pokud nejprve vyprší timeout (nastavitelný argumentem timeout v konstruktoru). readline() čte až po další znak nového řádku včetně, což je užitečné pro řádkově orientované protokoly.

Jednoduchá smyčka, která odráží zpět vše, co přijme:

uart = UART(3, baudrate=115200, timeout=100)

while True:
    if uart.any():
        data = uart.read()
        uart.write(data)

read() bez argumentu s délkou čte bajty, dokud přijímací linka nezůstane potichu po nastavený timeout, a poté vrátí vše, co bylo nashromážděno. S timeout=100 vrátí každé zde uvedené volání jednu dávku bajtů – vše, co odesílatel odeslal bez 100ms mezery mezi bajty. Bez timeoutu by volání nemělo žádný signál, že odesílatel skončil, a mohlo by se zaseknout na neurčito.

3.19.2. Binární data se struct

K odesílání celých a desetinných čísel po lince slouží modul struct. Zabaluje hodnoty s pevnou šířkou do objektu bytes pomocí formátovacího řetězce, který určuje pořadí bajtů a typ každého pole:

import struct

uart.write(struct.pack("<lhb", count, temperature_x100, status))

Úvodní "<" volí pořadí bajtů little-endian; "l" je 32bitové celé číslo se znaménkem, "h" je 16bitové celé číslo se znaménkem, "b" je 8bitové celé číslo se znaménkem. Druhá strana rozbalí data pomocí stejného formátovacího řetězce:

payload = uart.read(7)        # 4 + 2 + 1 = 7 bytes
count, temperature_x100, status = struct.unpack("<lhb", payload)

Formátovací řetězec je smlouvou mezi oběma stranami. Jakýkoli nesoulad – špatné pořadí bajtů, špatné velikosti typů, špatné pořadí polí – vede k nesmyslným hodnotám.

3.19.3. Bufferování a čtení při vysokých rychlostech

Dotazovací smyčka, která volá any() a read(), sama o sobě stíhá většinu provozu, pokud hlavní smyčka iteruje dostatečně rychle na to, aby vyprázdnila přijímací buffer dříve, než se zaplní. Když rychlost roste nebo je smyčka zaneprázdněná, hrají roli dvě možnosti konstruktoru.

rxbuf nastavuje velikost softwarového RX bufferu. Výchozí hodnota je několik set bajtů; u senzorů, které vysílají stovky bajtů na dávku, nebo když hlavní smyčka mezi dotazy vykonává dlouhou práci, zvětšení bufferu zabrání zahazování příchozích bajtů, zatímco je smyčka zaneprázdněna jinde:

uart = UART(3, baudrate=115200, timeout=100, rxbuf=4096)

Cokoli, co dorazí, když je buffer plný, se ztratí; nastavte rxbuf tak, aby pokryl nejdelší mezeru mezi vyprázdněními.

Pro trvale vysoké rychlosti čte readinto() data do předem alokovaného bufferu místo toho, aby při každém volání vracela nový objekt bytes:

buf = bytearray(256)

while True:
    n = uart.readinto(buf)
    if n:
        process(buf, n)

Na cestě čtení nedochází k žádné alokaci, což je důležité, když je halda fragmentovaná nebo když by latence alokace jinak překročila časový rozpočet mezi bajty.