24. Lektion: UART

Aus Attraktor Wiki

Wechseln zu: Navigation, Suche

Dieses Kapitel wird im Kurs nicht behandelt. Ich beabsichtige dazu einen Vortrag auf einem Elektronik-Stammtisch (1.Montag im Monat) zu halten.

Es würde zu umfangreich werden. Es müssten sonst andere, m.E. interessantere Teile entfallen.

Was ist ein UART?

UART steht für Universal Asynchronous Receiver Transmitter. Es handelt sich hierbei um die wohl älteste Schnittstelle in der Computerwelt. Sie wurde z.B. schon bei den Fernschreibern eingesetzt. Ursprünglich war sie für de Datenübertragung im Telefonnetz entwickelt worden.
Es gibt 2 Normen für diese serielle Schnittstelle:

  • V.24 von der ITU-T (Internatioale Fernmeldebehörde)
  • RS232 von der EIA (Electronic Industries Association)

inzwischen sind diese Normen identisch.

RS232

Uart timing.svg.png
Das Bild zeigt das Timing sehr anschaulich.

  • Der Ruhezustand ist 1
  • Die Übertragung eines Bytes wird mit einem Startbit (0) eingeleitet.
  • Dann folgen die Datenbits (5...9).
  • Anschließend kann ein optionales Paritybit gesendet werden.
  • Beendet wird die Übertragung eines Bytes mit dem Stopbit (1)
    • Das Stopbit kann 1, 1.5 oder 2 Bit lang sein.

Die Übertragungsgeschwindigkeit wird in Baud (Bits/Sekunde) angegeben.

Übliche Bitraten
Bitrate Bitdauer
50 bit/s 20,0 ms
110 bit/s 9,09 ms
150 bit/s 6,67 ms
300 bit/s 3,33 ms
1.200 bit/s 833 µs
2.400 bit/s 417 µs
4.800 bit/s 208 µs
9.600 bit/s 104 µs
19.200 bit/s 52,1 µs
38.400 bit/s 26,0 µs
57.600 bit/s 17,4 µs
115.200 bit/s 8,68 µs
230.400 bit/s 4,34 µs
460.800 bit/s 2,17 µs
921.600 bit/s 1,08 µs
2.000.000 bit/s 500 ns
3.000.000 bit/s 333 ns

Pegel

Die Spannungspegel sind wie folgt zugeordnet:

  • Logisch 0 - Space = +12V
  • Logisch 1 - Mark = -12V

Die Spannung kann 3...15V betragen.

In der Microcontrollertechnik wird der Aufwand der positiven und negativen Spannungen nicht realisiert. Hier wird die Betriebsspannung (5V, 3V3) als Logisch 1 und GND als Logisch 0 verwendet. Das wird als TTL bezeichnet, in Anlehung an die digitale TTL Famile, die mit 5 Volt arbeitet.

Synchron/Asynchron

Synchron

Bei einer synchronen Übertragung werden Daten und Takt parallel übertragen, so dass die Daten immer mit dem Takt synchron sind. Selbst bei langen Übertragungen werden die Daten immer zum richtigen Zeitpunkt abgetastet. Beispiele hier für sind SPI und I2C.

Asynchron

Bei der asynchronen Übertragung wird kein Takt übertragen. Deshalb muss das Timing von Sender und Empfänger sehr genau sein. Da sich ein Auseinanderlaufen des Timings bei Sender und Empfänger nicht vermeiden lässt, muss bei der asynchronen Übertragung immer wieder eine Synchronisierung zwischen Sender und Empfänger stattfinden. Dazu dient das Startbit. Wenn es vom Empfänger dedektiert wird beginnt sein Timing bei Null. Die Übereinstimmung vom Sender- und Empfängertiming muss dann nur noch << 8% sein.

Die Klasse UART in Micropython

Die Klasse UART befindet sich im Modul machine. Sie enthält folgende Methoden:

>>> dir(machine.UART)
['__class__', '__name__', 'any', 'read', 'readinto', 'readline', 'write', '__bases__', '__dict__', 'CTS', 'INV_RX', 'INV_TX', 'RTS', 
'deinit', 'flush', 'init', 'sendbreak', 'txdone']
>>> 

Eine Instanz erzeugen

machine.UART(id, ...)
Hiermit wird eine Instanz der Klasse UART erzeugt. Es können folgende Parameter übergeben werden:
baudrate
is the clock rate.
bits
is the number of bits per character, 7, 8 or 9.
parity
is the parity, None, 0 (even) or 1 (odd).
stop
is the number of stop bits, 1 or 2.

Weitere Schlüsselwort Parameter sind:

tx
specifies the TX pin to use.
rx
specifies the RX pin to use.
rts
specifies the RTS (output) pin to use for hardware receive flow control.
cts
specifies the CTS (input) pin to use for hardware transmit flow control.
txbuf
specifies the length in characters of the TX buffer.
rxbuf
specifies the length in characters of the RX buffer.
timeout
specifies the time to wait for the first character (in ms).
timeout_char
specifies the time to wait between characters (in ms).
invert
specifies which lines to invert.
    • 0 will not invert lines (idle state of both lines is logic high).
    • UART.INV_TX will invert TX line (idle state of TX line now logic low).
    • UART.INV_RX will invert RX line (idle state of RX line now logic low).
    • UART.INV_TX | UART.INV_RX will invert both lines (idle state at logic low).
UART.init(baudrate=9600, bits=8, parity=None, stop=1, *, ...)
Ändert die Einstellungen einer vorhandenen Instanz.
UART.deinit()
Schaltet die UART-Instanz aus. Sie lässt sich mit init() nicht wieder einschalten. Sie muss neu angelegt werden.

Datenfluß Kontrolle

flow gibt an, welche Hardware-Flusssteuerungssignale verwendet werden sollen. Der Wert ist eine Bitmaske.

0
will ignore hardware flow control signals.
UART.RTS
will enable receive flow control by using the RTS output pin to signal if the receive FIFO has sufficient space to accept more data.
UART.CTS
will enable transmit flow control by pausing transmission when the CTS input pin signals that the receiver is running low on buffer space.
UART.RTS | UART.CTS
will enable both, for full hardware flow control.

Methoden zum Datentransfer

UART.any()
Gibt eine ganze Zahl zurück, die die Anzahl der Zeichen zählt, die ohne Blockierung gelesen werden können. Sie gibt 0 zurück, wenn keine Zeichen verfügbar sind, und eine positive Zahl, wenn es Zeichen gibt. Die Methode kann auch dann 1 zurückgeben, wenn mehr als ein Zeichen zum Lesen verfügbar ist.
UART.read([nbytes])
Zeichen lesen. Wenn nbytes angegeben ist, werden maximal so viele Bytes gelesen, andernfalls werden so viele Daten wie möglich gelesen. Es kann früher zurückkehren, wenn eine Zeitüberschreitung erreicht wird. Die Zeitüberschreitung ist im Konstruktor konfigurierbar.
Rückgabewert: ein Byte-Objekt, das die eingelesenen Bytes enthält. Bei Zeitüberschreitung wird nichts zurückgegeben.
UART.readinto(buf[, nbytes])
Liest Bytes in den buf. Wenn nbytes angegeben ist, werden höchstens so viele Bytes gelesen. Andernfalls werden höchstens len(buf) Bytes gelesen. Es kann früher zurückkehren, wenn eine Zeitüberschreitung erreicht wird. Die Zeitüberschreitung ist im Konstruktor konfigurierbar.
Rückgabewert: Anzahl der gelesenen und in buf gespeicherten Bytes oder None bei Timeout.
UART.readline()
Liest eine Zeile, die mit einem Newline-Zeichen endet. Sie kann früher zurückkehren, wenn eine Zeitüberschreitung erreicht wird. Die Zeitüberschreitung ist im Konstruktor konfigurierbar.
Rückgabewert: die gelesene Zeile oder Keine bei Zeitüberschreitung.
UART.write(buf)
Schreibt den Puffer mit Bytes auf den Bus.
Rückgabewert: Anzahl der geschriebenen Bytes oder Keine bei Timeout.
UART.sendbreak()
Senden einer Unterbrechungsbedingung auf dem Bus. Dadurch wird der Bus für eine längere Zeit als für die normale Übertragung eines Zeichens erforderlich auf einen niedrigen Pegel gebracht.
UART.flush()
Waits until all data has been sent. In case of a timeout, an exception is raised. The timeout duration depends on the tx buffer size and the baud rate. Unless flow control is enabled, a timeout should not occur.
    • Note
    • For the rp2, esp8266 and nrf ports the call returns while the last byte is sent. If required, a one character wait time has to be added in the calling script.
UART.txdone()
Tells whether all data has been sent or no data transfer is happening. In this case, it returns True. If a data transmission is ongoing it returns False.
    • Note
    • For the rp2, esp8266 and nrf ports the call may return True even if the last byte of a transfer is still being sent. If required, a one character wait time has to be added in the calling script.
UART.irq()
ist im Pico nicht implementiert.

UART im Raspberry Pi Pico W

In Microcontrollern sind häufig USART's implementiert. Das sind UART's die auch synchrone Übertragungen ermöglichen.
Es gibt im Pico 2 UARTs, UART0 und UART1. Die möglichen Pins für die UARTs zeigen die Tabellen.

Pins für UART0
TX RX
0 1
12 13
16 17
Pins für UART1
TX RX
4 5
8 9

Eine UART-Instanz erzeugen

Die default Einstellungen für UARTs sind:

>>> print(UART(0))
    UART(0, baudrate=115200, bits=8, parity=None, stop=1, tx=0, rx=1, txbuf=256, rxbuf=256, timeout=0,
 timeout_char=1, invert=None)

>>> print(UART(1))
    UART(1, baudrate=115200, bits=8, parity=None, stop=1, tx=4, rx=5, txbuf=256, rxbuf=256, timeout=0,
 timeout_char=1, invert=None)

Eine Instanz von UART hat folgende Eigenschaften:

>>> from machine import UART
>>> uart = UART(0)
>>> print(uart)
    UART(0, baudrate=115200, bits=8, parity=None, stop=1, tx=0, rx=1, txbuf=256, rxbuf=256, timeout=0,
 timeout_char=1, invert=None)

Wie man oben sieht ist die Initialisierung unter Verwendung der Defaultparameter sehr einfach.

Für unsere weiteren Versuche muss immer zuerst folgender Code ausgeführt werden:

import machine
uart0 = machine.UART(0)
uart1 = machine.UART(1)

Senden

Im einfachsten Fall wird einfach ein String zur Übertragung angegeben:

>>> uart0.write('Hallo!')
    6

Zahlen können nicht so einfach übertragen werden. Sie müssen erst in einen String umgewandelt werden:

>>> uart0.write(123456)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: object with buffer protocol required
>>> uart0.write(str(123456))
    6
>>> 

Empfangen

>>> import machine
    uart0 = machine.UART(0)
    uart1 = machine.UART(1)

>>> uart0.write('Hallo!')
    6
>>> uart1.read()
    b'\x00Hallo!'
>>> 

Links: