Geräte über UART verbinden
Was ist UART?
UART ist die Abkürzung für “Universal Asynchronous Receiver / Transmitter”, ein Protokoll für den seriellen Austausch von Daten zwischen zwei Geräten.
Dabei haben beide Geräte die Anschlüsse:
- TX für Senden
- RX für Empfangen
Man verbindet jeweils TX des einen Geräts mit RX des anderen Geräts. Daneben verbindet man GND der beiden Geräte miteinander.
Für eine Verbindung müssen Sender und Empfänger die gleichen Einstellungen haben für:
- Baudrate
- Anzahl der Datenbits
- Stoppbit
- Paritätsbit
Microcontroller wie der Raspi Pico, der ESP32 und der Arduino haben eine oder mehrere UART-Schnittstellen, ebenso der Raspberry Pi. Welchen GPIO-Ports für UART verwendet werden können, kann sieht man in der jeweiligen Pinbelegungs-Übersicht.
An PCs kann man an die USB-Schnittstelle einen USB-UART-Adapter anschließen und über diesen mit einem anderen Gerät kommunizieren.
Serielle Schnittstelle unter Linux mit USB-UART-Adapter
Unter Linux muss man zunächst den Namen der Schnittstelle (die Device-Datei) herausfinden. Hierzu gibt man folgendes vor und nach dem anstecken des Adapters auf der Kommandozeile ein:
$ ls /dev/ttyACM* /dev/ttyUSB* /dev/ttyAMA*
Der Device-Name der nach dem Anstecken dazukommt, ist der richtige. Wichtig ist zudem, daß der aktuelle Nutzer in der Linux-Gruppe dialout
enthalten ist.
Für die Kommunikation über die serielle Schnittstelle gibt es spezielle Programme unter Linux beispielsweise Picocom und Minicom, unter Windows PuTTY.
Nutzung von Picocom unter Linux
Zunächst muss Picocom installiert werden, z.B. mit
$ sudo apt-get install picocom
Der Aufruf von Picocom geht dann wie folgt:
$ picocom -b 9600 -c /dev/ttyUSB0
Dabei wird mit dem Parameter -b die Baudrate angegeben, mit -c das lokale Echo angeschaltet, dass heisst, dass Eingaben im Terminal auch dort angezeigt werden. /dev/tty/USB0 ist die wie oben ermittelte Device-Datei.
Eingaben in Picocom werden nun über die serielle Schnittstelle an die Gegenstelle gesendet, Daten die von der Gegenstelle gesendet werden, werden in Picocom angezeigt.
Mit den Optionen imap, omap und emap kann man festlegen, ob bestimmte Zeichen Sonderzeichen nach dem Empfang, vor dem Versand oder für die lokale Anzeige geändert werden (zum Beispiel CR LF oder DEL BS). Details dazu findet man in der Manpage.
Picocom kann dadurch beendet werden, dass man Strg
gedrückt hält und nacheinander a
und x
drückt.
UART Programmierung in Micropython
In Micropython kann man UART nutzen, in dem man ein Objekt der Klasse UART erzeugt. Details sind hier beschrieben: https://docs.micropython.org/en/latest/library/machine.UART.html
Beim Erzeugen des Objekts der Klasse UART gibt man die ID und die Baudrate und ggf. die genutzten Pins an. Beim Raspi Pico gibt es beispielsweise zwei UART-Schnittstellen, UART0 und UART1. UART0 kann an die Pins 0/1 (default), 12/13 oder 16/17 angeschlossen werden, UART1 an die Pins 4/5 oder 8/9. Folgendes Programm erzeugt ein Objekt für UART1 an den Pins 0 und 1 und ein Objekt für UART1 an den Pins 4 und 5.
from machine import UART, Pin
uart0 = UART(0, 9600)
uart1 = UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5))
Weiterer optionaler Parameter ist timeouot
der Timeout in ms, der standardmäßig auf 0 steht.
Man kann sich die aktuellen Parameterwerte des UART-Objekts auch anschauen:
print(uart)
UART(0, baudrate=9600, bits=8, parity=None, stop=1, tx=0, rx=1, txbuf=256, rxbuf=256, timeout=10000, timeout_char=2, invert=None)
Zum Senden von Daten nutzt man den write
-Befehl:
uart0.write('Hello world')
Für den Empfang von Daten gibt es die Methode read
, der man optional die Anzahl der zu lesenden Bytes übergeben kann. Gibt man keine Anzahl an, werden soviele Bytes wie möglich gelesen. Das Lesen endet, wenn die angegebene Anzahl der Bytes oder der gesetzte Timeout erreicht wurde. Konnten keine Zeichen gelesen werden, gibt die Methode None
zurück, ansonsten die gelesenen Bytes als Byte-Objekt.
Mit der Methode any
erhält man die Anzahl der Bytes, die gelesen werden können:
print(uart0.any())
Mit folgendem Code werden beispielsweise kontinuierlich einzelne Bytes gelesen und ausgegeben:
while True:
text = uart0.read(1)
if text != None:
print(text)
Mit nachfolgendem Beispielcode werden solange Zeichen über die Schnittstelle eingelesen bis ein bestimmtes Endzeichen (im Beispiel Carriage Return) ankommt.
def read_uart_until(termination_char):
bytes_read = b''
while True:
if uart.any():
bytes_read += (uart.read(1))
try:
string_read = bytes_read.decode('utf-8')
if string_read.endswith(termination_char):
break
except UnicodeError:
# read next byte
pass
sleep(0.01)
return string_read[:-1]
while True:
eingabe = read_uart_until("\r")
print(eingabe)
Hierfür wird in einer Schleife mit der Methode any
geprüft, ob Daten an der Schnittstelle vorliegen. Falls ja wird jeweils ein Bytes gelesen und an die bisherigen Bytes angehängt. Danach wird die Umwandlung in einen String versucht. Ist dies erfolgreich, wird geprüft, ob das letzte Zeichen dem gewählten Endzeichen entspricht. Falls ja wird die Schleife abgebrochen. Ein UnicodeError tritt dann auf, wenn noch nicht alle zu einem Zeichen gehörenden Bytes gelesen wurde, was z.B. bei Umlauten möglich ist. In diesem Fall wird dann gleich das nächste Byte gelesen.
UART am Raspberry Pi
https://www.electronicwings.com/raspberry-pi/raspberry-pi-uart-communication-using-python-and-c
UART Programmierung in Python
https://pyserial.readthedocs.io/en/latest/shortintro.html