In diesem praktischen Artikel schauen wir uns die Verbindung von zwei Kommunikationspartnern per UART, und anschließend per RS485 (Breadboard-Aufbau) an. Von Interesse sind dabei für uns vor allem die RXD und TXD Pins, wobei wir auch zusätzlich für RS485 den RTS Pin als GPIO nutzen könnten, um den Treiber auf den Bus aufzuschalten (nicht in diesem Artikel). RTS und CTS sind im vorigen Artikel beschrieben worden, und dienen der Hardware Flusskontrolle für die Kommunikation, falls man das möchte. Als Betriebssystem dient ein aktuelles Raspbian Stretch.
UART: Vorbereitung des Pis
Der Raspberry Pi hat, wie bereits im vorigen Artikel erwähnt, zwei UARTs - den PL011 und den miniUART.
Die UARTs stehen als alternative Funktionen von folgenden GPIO Pins am SoC, sowie an Pi's zur Verfügung:
GPIO (BCM#) |
Raspberry Pi 3B+ GPIO Pin |
Compute Module Pin |
Funktion |
GPIO Bank 0 - am 40 Pin GPIO Header |
|||
GPIO 14 |
8 |
CM 51 |
TXD0 (ALT0) / TXD1 (ALT5) |
GPIO 15 |
10 |
CM 53 |
RXD0 (ALT0) / RXD1 (ALT5) |
GPIO 16 |
36 |
CM 57 |
CTS0 (ALT3) / CTS1 (ALT5) |
GPIO 17 |
11 |
CM 59 |
RTS0 (ALT3) / RTS1 (ALT5) |
GPIO Bank 1 - intern am Pi verfügbar |
|||
GPIO 30 |
nicht verfügbar |
CM 34 |
CTS0 (ALT3) / CTS1 (ALT5) |
GPIO 31 |
CM 36 |
RTS0 (ALT3) / RTS1 (ALT5) |
|
GPIO 32 |
CM 46 |
TXD0 (ALT3) / TXD1 (ALT5) |
|
GPIO 33 |
CM 48 |
RXD0 (ALT3) / RXD1 (ALT5) |
|
|
|||
GPIO 36 |
nicht verfügbar |
CM 58 |
TXD0 (ALT2) |
GPIO 37 |
CM 60 |
RXD0 (ALT2) |
|
GPIO 38 |
CM 64 |
RTS0 (ALT2) |
|
GPIO 39 |
CM 66 |
CTS0 (ALT2) |
|
|
|||
GPIO 40 |
nicht verfügbar |
CM 70 |
TXD1 (ALT5) |
GPIO 41 |
CM 72 |
RXD1 (ALT5) |
|
GPIO 42 |
CM 76 |
RTS1 (ALT5) |
|
GPIO 43 |
CM 78 |
CTS1 (ALT5) |
Es handelt sich dabei um die GPIO Pins am SoC des Raspberry Pi. Am Compute Module stehen auch die GPIO Pins von GPIO Bank 1 zur Verfügung, an den "handelsüblichen" Raspberry Pis (Pi 3 Model B+, etc.) nur die Pins von GPIO Bank 0. Die anderen Pins werden vom Pi intern benutzt, um verschiedene Komponenten anzuschließen.
Der PL011 ist dabei TXD0 / RXD0 / RTS0 / CTS0, und der miniUART TXD1 / RXD1 / RTS1 / CTS1.
Wie man sieht gibt es zwei "Blöcke" von Pins, an denen die Funktionen austauschbar als Alternativen zur Verfügung stehen. Genau das hat die Raspberry Pi Foundation sich beim Design von Pi 3B+, etc. zu Nutzen gemacht - und den Bluetooth intern in der GPIO Bank 1 über den "guten" UART PL011 angeschlossen. Dank Software-Konfigurierbarkeit können wir ihn uns aber auf die normalen, am Pi GPIO Port zur Verfügung stehenden Pins zurückholen. Mehr dazu gleich mehr.
Das Bild zeigt die für uns relevanten Pins am Raspberry Pi, bei den 40 Pin Modellen steht zusätzlich CTS zur Verfügung, an jedem jemals hergestellten Pi kann man aber den UART über TXD / RXD mit Software Flow Control nutzen.
Es gibt unter Linux folgende Devices:
- /dev/ttyS0 - miniUART (standardmäßig)
- /dev/ttyAMA0 - PL011 UART (standardmäßig)
- /dev/serial0 - ein Symlink, der immer auf den default UART zeigt.
- /dev/serial1 - falls ein zweiter UART aktiviert ist, zeigt der Symlink darauf.
Der PL011 ist bei allen Systemen der Standard UART (/dev/serial0), außer bei den Pi's mit WLAN (3B, 3B+, 3A+, Pi Zero W, Pi Zero WH) - hier wird er benutzt um den Bluetooth-Teil anzubinden. Bei diesen Pi's steht standardmäßig der miniUART unter /dev/serial0 zur Verfügung.
Standardmäßig ist außerdem eine Linux Console über den "Haupt-UART" des Systems vorgesehen. Diese würde uns bei der Kommunikation stören, und muss daher abgeschaltet werden.
Das funktioniert wie folgt:
sudo nano /boot/cdmline.txt
hier muss der Teil mit console=serial0,115200 gelöscht werden (kann ähnlich ausschauen).
Da wir den PL011 verwenden wollen, müssen wir bei Pi 3B / 3B+ / 3A+ & der Zero Reihe Bluetooth abschalten (optional gäbe es auch die Möglichkeit die zwei UARTs zu tauschen, da der miniUART aber u.a. an die Taktrate des VideoCores fixiert ist bringt das Nachteile und zusätzlichen Konfigurationsaufwand mit sich). Wir gehen wie folgt vor:
sudo nano /boot/config.txt
Hier wird folgende Zeile ganz am Ende eingefügt:
dtoverlay=pi3-disable-bt
Diese Zeile vertauscht in der Softwarekonfiguration die Pins, so dass wir jetzt über die uns zugänglichen Pins am Raspberry Pi (siehe Pinout oben) den PL011 UART nutzen können.
Außerdem ist es wichtig den Systemservice zu disablen, der mit Bluetooth kommuniziert (da er sonst weiter über die Pins kommunizieren versuchen würde):
sudo systemctl disable hciuart
Das sollte ausgeben: "Removed /etc/systemd/system/multi-user.target.wants/hciuart.service".
Jetzt ist es an der Zeit, den Pi neu zu starten:
sudo reboot
UART: Loopback
In diesem ersten einfachen Test verbinden wir TXD und RXD miteinander. Das was der Pi sendet, wird auch von ihm empfangen. Falls Sie mit Flow Control und Parity nichts anfangen können, empfehle ich Ihnen unseren Artikel zu den Grundlagen des UARTs zu lesen.
Um das zu testen benötigen wir noch ein Programm:
sudo apt-get update
sudo apt-get install picocom
Anschließend starten wir minicom, bspw. per SSH:
picocom -b 9600 -d 8 -f n -p e /dev/serial0
-b: Baudrate ( 9600 bit/s )
-d: Data bits in every character ( 8 )
-f: Flow Control (n = kein Flow Control)
-p: Parity (e = even parity)
am Ende geben wir das Gerät an, in unserem Fall die serielle Hauptschnittstelle /dev/serial0
picocom sendet unsere Tasteneingaben an "die Gegenstelle", und gibt die Antworten der "Gegenstelle" aus.
Da unsere Gegenstelle wir selbst sind, wird die Tastatureingabe am Bildschirm einfach wiedergegeben - ich habe Hello World! und den Rest des Texts eingegeben.
Man kann das einfach überprüfen, indem man das Kabel kurzzeitig aus dem RXD Pin aussteckt - das was man eintippt wird dann nicht mehr angezeigt. Sobald man das Kabel wieder in RXD einsteckt, wird die Ausgabe wieder weitergegeben.
Um eine neue Zeile "einzugeben" muss man Ctrl + J, gefolgt von der Return Taste eingeben.
Normale Kommandos (Ctrl + C) werden an die "Gegenstelle" gegeben. Um picocom zu beenden, muss man daher die Steuertaste, Ctrl + A eingeben, und anschließend Ctrl + X um das Programm zu beenden.
UART: Kommunikation zwischen zwei Pi's
Bonus Tipp: um andere Pi's im Netzwerk zu finden kann folgendes nmap Kommando dienen:
sudo nmap -sP 192.168.1.0/24 | awk '/^Nmap/{ip=$NF}/B8:27:EB/{print ip}'
am zweiten Pi müssen wir ebenfalls die Einstellungen zur Vorbereitung (s.o.) durchführen.
Anschließend schließen wir den TX Pin des ersten Pi's am RX Pin des zweiten Pi's an, und den TX Pin des zweiten Pi's am RX Pin des ersten Pi':
Dieses Mal gibt der erste Pi die Ausgabe vom zweiten Pi aus, und der zweite Pi die Ausgabe vom ersten Pi:
Wichtig ist, dass die Einstellungen von picocom an den Pi's exakt übereinstimmen:
picocom -b 9600 -d 8 -f n -p e /dev/serial0
Ich habe dazu einfach zwei SSH Verbindungen auf den jeweiligen Pi aufgemacht.
Man könnte jetzt beispielsweise Dateien seriell übertragen, oder ein Programm zur seriellen Kommunikation in Python schreiben, ...
Übrigens muss der Gegenpartner der Kommunikation nicht unbedingt ein Pi sein. Oft kann man mit einem Microcontroller über eine serielle Schnittstelle sprechen, beispielsweise dem beliebten ESP8266.
Man sollte immer sicherstellen, dass die Signalpegel des Gegen-UARTs ebenfalls 3,3V sind und nicht 5 V. Sonst könnten die Pins des Pis beschädigt werden.
RS485: ein Aufbau auf dem Breadboard
Und nun zur Königsdisziplin, ein Aufbau von RS485 auf dem Breadboard.
Wir verwenden den SN65HCD1782 von Texas Instruments (bei uns im Shop erhältlich!).
Das Datenblatt kan hier heruntergeladen werden:
http://www.ti.com/product/SN65HVD1782?dcmp=dsproject&hqs=pf
Das PDIP package kann durch seine Beinchen perfekt auf einem Breadboard eingesetzt werden. (Das P in PDIP steht übrigens für Plastic).
Wir benötigen zwei der Chips für eine Kommunikation.
Im Datenblatt ist auf Seite 4 der Pinout angegeben.
Abbildung aus Datenblatt von Texas Instruments
Die Spannungsangabe hier widerspricht der Angabe "Operation with 3.3-V to 5-V Supply Range". Auf jeden Fall haben wir sowieso keine Wahl, wir MÜSSEN den Chip mit 3,3 V versorgen. Außer bei speziellen Chips ist nämlich die Versorgungsspannung üblicherweiße maßgebend für die Pegel an den Logikpins (die wir hier an den Pi anbinden möchten - der nur 3,3V verträgt!).
Der Pin 1 wird durch die Kuhle markiert:
Abbildung aus Datenblatt von Texas Instruments
Schließen Sie jeweils einen Chip pro Pi an:
- pin 5: GND
- pin 8: 3,3V Spannung
- pin 6: "A" - an "A" (pin 6) vom zweiten Chip - nicht kreuzen
- pin 7: "B" - an "B" (pin 7) vom zweiten Chip - nicht kreuzen
- pin 2: receiver enable low - der Receiver ist aktiv, falls er an GND anliegt. GND vom jeweiligen Pi, KEIN gemeinsamer GND!
- pin 4: D, digital Input - wird an TX des jeweiligen Pi's angeschlossen.
- pin 1: R, digital output - wird an den RX des jeweiligen Pi's angeschlossen
- pin 3: DE, driver enable - hier müssen Sie einen der Pi's auswählen. Ich habe mich für pione als aktiven Pi entschieden. der RS485 Transceiver dieses Pis wird mit Pin 3 an 3V3 / VCC angeschlossen (von dem Pi).
Die Jumper müssen nicht unbedingt alle in einer Linie direkt am Chip sein, man kann sie nach hinten hin verteilen, damit es nicht so eng und gedrängt ist.
In unserem Tutorial ist der Receiver immer an - d.h. der Pi hört sich auch selbst beim Senden.
Jetzt können wir picom erneut per SSH an jedem Pi bemühen. Wichtig ist, dass die Einstellungen von picocom an den Pi's exakt übereinstimmen:
picocom -b 9600 -d 8 -f n -p e /dev/serial0
Eingaben bei pitwo sollten verworfen werden, da wir ihn nicht auf dem RS485 Bus aktiviert haben - der UART "schreibt daher ins Leere":
Eingaben auf dem pione sollten hingegen sowohl auf pione wiedergegeben werden, als auch auf pitwo auftauchen:
That's it - die Kommunikation steht!
Jetzt könnte man noch mehr "Sophistication" hereinbringen, und beispielsweise einen GPIO von jedem Pi nutzen, um den Driver Enable pin zu schalten (high, um auf den Bus zu schreiben, und low um die Ausgabe auf den RS485 Bus zu deaktivieren). Dazu sollten die zwei Pis (bzw. Sie mit sich selbst) auf ein Protokoll einigen - wann darf jeder Pi schreiben, damit es keine Kollisionen gibt?
Man kann das beispielsweise über eine Master / Slave Architektur lösen. Es gibt auf dem Bus einen Master, der die Slaves adressiert, und dann dem angesprochenen Slave Zeit zum Antworten gibt. Der Master hört auf den Bus, und falls der Slave innerhalb eines Timeouts nicht antwortet (das erste Byte schickt), hat er das Rederecht verwirkt, und der Master ist wieder dran.
RS485 auf dem Pi ist kein Hexenwerk. Und zufälligerweise haben wir den benötigten Chip im Sortiment :)
Viel Spaß beim Experimentieren.
4 Kommentare
Tom
Wie lang dürfte denn eine Leitung zwischen zwei UART-Schnittstellen werden?
Kann mit jemand aus der Praxis berichten?
Tom
info@solarharz.de
Uwe Schaar
Ein kleiner Fehler hier: sudo nano /boot/cdmline.txt muss cmdline.txt heissen, aber so eine sehr gute Dokumentation. Dankeschön
Max (buyzero.de)
@Janix Ax: 3 Mb/s klingt realistisch.
Gemäß diesem Artikel hat jemand 10 Mb/s hingebracht
https://www.raspberrypi.org/forums/viewtopic.php?t=192447
Der Pi 4 ist für höhere Baudraten die sinnvollste Wahl, meines Erachtens.
Janis Ax
Hi, wie hoch ist denn die maximale Baudrate die der Pi bedenkenlos mitmacht? Ich würde gerne mit diesem Chip ein RS485 Device an den Pi anschließen, dass bis zu 3 Mb/s schafft, die ich auch gerne nutzen würde. Geht dies?