3.19. Kodda UART

machine.UART, bir donanım UART kanalını sarmalar. Bir tane oluşturmak için veri yolu kimliğini ve bir baud hızını kullanın; geri kalan her şeyin makul varsayılanları vardır:

from machine import UART

uart = UART(3, baudrate=115200)

id, hangi donanım UART’ının kullanılacağını seçer; değer karta bağlıdır (belirli bir kameradaki kullanılabilir veri yolu numaraları ve pin atamaları için OpenMV Kartları bölümüne bakın). Varsayılan çerçeve biçimi 8 veri biti, parite yok, bir durdurma bitidir – herkesin beklediği “8N1”.

3.19.1. Yazma ve okuma

UART çıkışı write() üzerinden gider:

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

write, ya bir str (UTF-8 olarak kodlanmış) ya da bir bytes / bytearray kabul eder. Baytlar TX arabelleğine sıraya alınır alınmaz hemen geri döner; donanım onları arka planda saat darbeleriyle dışarı vermeyi bitirir.

Okumalar, neye ihtiyaç duyulduğuna bağlı olarak üç yöntemle gerçekleşir:

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(), RX arabelleğini engellemeden kontrol eder. read(), sabit sayıda bayt okur ve zaman aşımı (yapıcıdaki timeout argümanıyla yapılandırılabilir) önce dolarsa None döndürür. readline(), bir sonraki satır sonuna kadar (dâhil) okur; satır tabanlı protokoller için kullanışlıdır.

Aldığı her şeyi yankılayan basit bir döngü:

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

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

Uzunluk argümanı olmayan read(), alma hattı yapılandırılan timeout süresince sessiz kalana kadar bayt okumaya devam eder, ardından biriktirilen her şeyi döndürür. timeout=100 ile buradaki her çağrı, bir patlama bayt döndürür – gönderenin baytlar arasında 100 ms boşluk bırakmadan dışarı verdiği her şey. Zaman aşımı olmadan çağrının gönderenin işinin bittiğine dair bir işareti olmaz ve süresiz olarak askıda kalabilir.

3.19.2. struct ile ikili veri

Tam sayıları ve kayan noktalı değerleri hat üzerinden göndermek struct modülünün işidir. Bayt sırasını ve her alanın tipini adlandıran bir biçim dizesi kullanarak sabit genişlikli değerleri bir bytes nesnesine paketler:

import struct

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

Baştaki "<" küçük endian bayt sırasını seçer; "l" 32 bitlik işaretli bir tam sayı, "h" 16 bitlik işaretli bir tam sayı, "b" 8 bitlik işaretli bir tam sayıdır. Diğer taraf aynı biçim dizesiyle açar:

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

Biçim dizesi iki uç arasındaki sözleşmedir. Herhangi bir uyumsuzluk – yanlış bayt sırası, yanlış tip boyutları, yanlış alan sırası – anlamsız değerler üretir.

3.19.3. Arabelleğe alma ve yüksek hızlı okumalar

any() ve read() çağıran bir yoklama döngüsü, ana döngü alma arabelleğini dolmadan boşaltacak kadar hızlı yineledikçe çoğu trafiğe kendi başına ayak uydurur. Hız yükseldiğinde veya döngü meşgul olduğunda iki yapıcı seçeneği önem kazanır.

rxbuf, yazılım RX arabelleğinin boyutunu ayarlar. Varsayılan birkaç yüz bayttır; patlama başına yüzlerce bayt yayan sensörler için veya ana döngü yoklamalar arasında uzun işler yaptığında, arabelleği büyütmek döngü başka bir yerde meşgulken gelen baytların düşürülmesini önler:

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

Arabellek doluyken gelen her şey kaybolur; rxbuf boyutunu, boşaltmalar arasındaki en uzun boşluğu kapsayacak şekilde ayarlayın.

Sürekli yüksek hızlar için readinto(), her çağrıda yeni bir bytes nesnesi döndürmek yerine önceden ayrılmış bir arabelleğe okur:

buf = bytearray(256)

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

Okuma yolunda hiçbir bellek ayırma gerçekleşmez; bu, yığın parçalanmış olduğunda veya bellek ayırma gecikmesi aksi takdirde baytlar arası zamanlama bütçesini aşacağı zaman önemlidir.