Praktische Kommunikation per UART und RS485 am Raspberry Pi

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.

UART Pinout am Raspberry Pi mit 40 Pin Header

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:

UART crossover anschluss von zwei Pis

Wichtig ist, dass die Einstellungen von picocom an den Pi's exakt übereinstimmen:

picocom -b 9600 -d 8 -f n -p e /dev/serial0

picocom uart kommunikation am raspberry pi

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.

Texas Instruments SN65HCD1782 Pinout

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.

RS485 auf dem Breadboard zwischen zwei Pis

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.

Further Reading

Hands onKommunikationMinicomPi zu pi kommunikationPraktischRs485Serielle schnittstelleTexas instrumentsTutorialUart

3 comments

Uwe Schaar

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)

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

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?

Leave a comment

All comments are moderated before being published