Der RasPi unterstützt über die integrierten UARTs serielle Datenübertragungen. Unser Zweiteiler erklärt die Schnittstelle und demonstriert die Technik am Raspberry Pi.
Die serielle Schnittstelle gehört neben dem Parallel-Port zu den Dinosauriern der Computerwelt. Einstmals essenziell, um Maus und Drucker anzubinden, findet man die Buchsen heute nur noch an für spezielle Aufgaben vorbereiteten Rechnern.
Beim Raspberry Pi ist die Technik allerdings nicht in Vergessenheit geraten. Auf der Platine des Mini-Rechners befinden sich dafür zwei Schaltungen, die über die GPIO-Pins zugänglich sind: der PL011-UART und den Mini-UART. Dieser Artikel erklärt die Grundlagen sowie die Hintergründe der seriellen Kommunikation und beschreibt, wie man diese Pins ansteuert und einen RS-485-Transceiver daran anbindet.
Im Folgenden ist immer wieder die Rede von Empfänger und Sender. Die Kommunikation geschieht meistens (außer bei Halbduplex-RS-485) bidirektional, das heißt: Beide Partner arbeiten gleichzeitig als Sender und Empfänger. Dabei erfolgt die Kommunikation im sogenannten Vollduplex-Modus. Alle folgenden Beschreibungen gelten also für beide Kommunikationspartner, nur eben jeweils in unterschiedlichen Richtungen. Es genügt daher, sich nur eine Seite der Kommunikation anzusehen, da die andere genau gleich läuft, nur in die Gegenrichtung.
Grundlagen
Bei serieller Kommunikation nutzt das System eine einzelne Datenleitung, um seriell Daten zu übermitteln. Die einzelnen Bits werden nacheinander, also in Serie, übermittelt. Die Alternative dazu wäre eine parallele Kommunikation wie etwa bei den früher benutzten Parallel-Ports für Drucker. Die meisten modernen Schnittstellen arbeiten seriell (beispielsweise USB, SPI, I2C, SATA oder CAN), da es bei höheren Geschwindigkeiten sehr schwierig wäre, parallele Pins zu synchronisieren. Serielle Kommunikation bietet zudem den Vorteil, dass die Technik mit weniger Leitungen auskommt, was die Kabel dünner und günstiger macht.
In Computern liegen die Daten intern als Bytes vor. 1 Byte besteht aus 8 Bits und kann damit 256 mögliche Werte annehmen, von 0 bis 255. Anhand der ASCII-Tabelle [1] ordnet das System dann jedem Zeichen einen Bit-Wert zu. Einige Werte stehen für nicht druckbare Zeichen (etwa Leerzeichen, Tabulatoren oder Zeilenumbrüche), andere für Sonderzeichen und Umlaute. Für die Zeichen ab dem Wert 128 gibt es mehrere Codepages, über die sich dann beispielsweise kyrillische Buchstaben darstellen lassen.
UTF-8 nutzt hingegen 1 bis 4 Bytes zum Kodieren eines Zeichens. Es ist zu ASCII abwärtskompatibel: Die Zeichen 0 bis 127 entsprechen dem ASCII-Encoding. In anderen Worten: Ein Computer verarbeitet keine Zeichen, sondern Bits und Bytes. Die Grundeinheit stellt dabei das aus 8 Bits zusammengesetzte Byte dar.
Die Datenübertragung über die serielle Schnittstelle geschieht Bit für Bit in Blöcken von jeweils einem Byte. Die Aufgabe eines UARTs im Raspberry Pi, einem Mikrocontroller, einem PC oder Arduino besteht darin, die Daten aus dem Byte in Bits umzuwandeln und nacheinander zu senden.
Dabei kommt typischerweise je Richtung eine Sendeleitung zum Einsatz. Der UART besitzt einen Sendeteil (TX für Transmit) und einen Empfangsteil (RX für Receive). Die serielle Kommunikation über einen UART verwendet im Gegensatz zu SPI und I2C keine zusätzliche Clock-Leitung für den Sendetakt. Auf der Gegenseite empfängt der UART der Gegenseite die einzelnen Bits und setzt sie wieder zu einem Byte zusammen.
Abbildung 1 zeigt die Sendesequenz, die Bits 0 bis 7 (also insgesamt 8 Bits) werden nacheinander übertragen. Dazu kommen noch jeweils ein Start- und ein Stoppbit. Dabei handelt es sich um das sogenannte Data Framing. Das Start- und Stoppbit rahmen die Nutzdaten (das zu übertragende Byte) dabei ein. Das Startbit ist immer 0 beziehungsweise LOW, das Stoppbit immer 1 respektive HIGH. Das geschieht bei jedem einzelnen Byte, das über die Leitung geht.
Abbildung 1: Der Datenframe einer seriellen Datenübertragung. Das Start- und Stoppbit markieren Anfang und Ende des Segments. (Bild: Wikipedia, CC-BY-SA)
Die beiden Bits signalisieren dem Empfänger, wann gesendet wird beziehungsweise wann keine Kommunikation mehr erfolgt und wann die Leitung unterbrochen ist (siehe Kasten “Break Detection”). Zudem kann der Empfänger auf diese Weise sicher mehrere hintereinander gesendete Zeichen unterscheiden, und es wird verhindert, dass sich Sender und Empfänger desynchronisieren.
Break Detection
Auf dem Raspberry Pi ist nur der PL011-UART zur Break Detection imstande. Da der Mini-UART das Stoppbit nicht prüft, würde er bei einer defekten Leitung fälschlicherweise 0x00 ausgeben, da er wiederholt LOW von der unterbrochenen Leitung liest. Details dazu liefert das Handbuch des BCM2835-Chips auf den Seiten 10 bis 11 [4].
Als Relikt aus der Telegrafie liegt der Standardzustand im Leerlauf ohne Kommunikation beim UART auf HIGH, das heißt auf einer logischen 1. Der UART zieht also auf Senderseite den GPIO-Pin (TX) des Raspberry Pi auf +3,3 Volt. Dieser Pin ist normalerweise mit dem Eingangspin (RX) auf der Empfängerseite verbunden, sodass hier dauerhaft +3,3 Volt anliegen. Wird die Leitung unterbrochen, liegt also am RX-Pin der Empfängerseite dauerhaft eine logische 0 beziehungsweise GND an, kann der UART der Empfängerseite das feststellen und dem System melden.
Wenn der Sender ein Byte übertragen möchte, zieht er die Leitung auf GND und sendet somit das Startbit. Danach übermittelt das System nacheinander die einzelnen Bits: Nullen als LOW (die Leitung liegt auf GND) und Einsen als HIGH (beim RasPi liegt dann an der Leitung +3,3 Volt an). Anschließend zieht der Sender zum Übermitteln des Stoppbits die Leitung wieder auf HIGH (+3,3 Volt), den Ursprungszustand. Die Kombination aus den gesendeten Bits mitsamt Start- und Stoppbit nennt sich Frame.
Dieses Verfahren stellt sicher, dass in der Übertragung zumindest ein Übergang zwischen LOW und HIGH erfolgt. Würde man eine lange Reihe von Nullen übertragen, wären das ohne die Start- und Stoppbits alles Zustände mit 0 Volt. Dann könnte es passieren, dass Sender und Empfänger sich desynchronisieren. Der Sender würde beispielsweise 800 Nullen senden, der Empfänger jedoch nur 798 zählen, da er nicht genau feststellen könnte, wann sie jeweils anfangen, und er sich ausschließlich auf seine eingebaute Uhr verlassen müsste. Durch das Start- und Stoppbit kann der Empfänger sich immer wieder synchronisieren, mindestens ein Übergang der Leitung pro gesendetem Byte ist garantiert.






