Grundlagen · 10 Min. Lesezeit

Was ist UART? TX/RX, Baudrate und serielle Schnittstelle erklärt

Was ist UART? TX/RX über Kreuz, Baudrate, Start- und Stoppbit, zwei Arduinos verbinden, SoftwareSerial, Pegel 5V/3,3V, ESP32 Serial2 und UART am Pico.

Die kurze Antwort auf was ist UART: UART (Universal Asynchronous Receiver-Transmitter) ist die serielle Schnittstelle, über die zwei Geräte mit nur zwei Datenleitungen (TX und RX) und einer gemeinsamen Masse (GND) Byte für Byte Daten austauschen. Jede Zeile, die du im seriellen Monitor siehst, wenn dein Arduino am Computer hängt, kommt über UART. Auch Dutzende Module wie GPS-Empfänger, das Bluetooth-Modul HC-05, das WLAN-Modul ESP-01, das GSM-Modul SIM800L, Fingerabdrucksensoren und MP3-Player sprechen per UART mit dem Arduino.

In diesem Beitrag erklären wir Schritt für Schritt, warum UART keine Taktleitung braucht, was die Baudrate ist, wie ein Byte mit Start-, Daten- und Stoppbits verpackt wird, warum TX und RX über Kreuz verbunden werden, wie zwei Arduinos erst in eine, dann in beide Richtungen kommunizieren, wo die Grenzen von SoftwareSerial liegen, wie du 5-V- und 3,3-V-Boards sicher verbindest, welche drei UARTs der ESP32 hat und welche UART-Pins der Raspberry Pi Pico bietet. Im letzten Teil siehst du, wie du mit Start- und Endezeichen Pakete baust, damit nichts durcheinanderkommt, und die häufigsten Fehler.

CP2102 USB-TTL-Wandler
CP2102 USB-TTL-Wandler: Er macht aus dem USB-Anschluss des Computers einen UART mit den Pins TX, RX und GND; der USB-Chip auf dem Arduino Uno erledigt dieselbe Aufgabe.

Was ist UART und wie funktioniert es?

Entscheidend ist das Wort „asynchron“ im Namen: Bei I2C und SPI wird mit den Daten ein Taktsignal übertragen, bei UART gibt es keine Taktleitung. Stattdessen einigen sich beide Seiten vorab auf eine Geschwindigkeit, die Baudrate. Im Ruhezustand liegt die Leitung auf HIGH (1). Um ein Byte zu senden, zieht der Sender die Leitung für eine Bitdauer auf LOW; das ist das Startbit, das dem Empfänger sagt: „Jetzt mitzählen“. Danach folgen die 8 Datenbits, beginnend mit dem niederwertigsten Bit (LSB), optional ein Paritätsbit, und zum Schluss bleibt die Leitung mindestens eine Bitdauer auf HIGH; das ist das Stoppbit. Die Standardeinstellung beim Arduino ist 8N1: 8 Datenbits, keine Parität, 1 Stoppbit.

BitStartD0D1D2D3D4D5D6D7Stopp
Buchstabe 'A' (0x41 = 0100 0001)0100000101
Pegel der LeitungLOWHIGHLOWLOWLOWLOWLOWHIGHLOWHIGH

Jedes Bit dauert 1 / Baudrate Sekunden. Bei 9600 Baud sind das 104,2 Mikrosekunden; da ein Byte im 8N1-Rahmen 10 Bit hat (Start + 8 Daten + Stopp), lassen sich höchstens 960 Byte pro Sekunde übertragen. Nachdem der Empfänger die fallende Flanke des Startbits erkannt hat, tastet er die Leitung jeweils in der Mitte jedes Bits ab. Auch wenn die beiden Takte leicht voneinander abweichen, werden die Daten richtig gelesen, solange der über 10 Bit aufsummierte Fehler unter einem halben Bit bleibt; deshalb sollte der gesamte Baudratenfehler unter etwa 2–3 % liegen. Mit seinem 16-MHz-Quarz kann der Arduino Uno 115200 Baud nicht exakt erzeugen, die echte Rate weicht um etwa 2,1 % ab; das funktioniert trotzdem, weil es innerhalb der Grenze liegt.

BaudBitdauerMax. Byte pro Sekunde (8N1)Wo wird es genutzt?
9600104,2 µs960NEO-6M GPS, HC-05 Datenmodus, DFPlayer Mini, klassische Einstellung des seriellen Monitors
1920052,1 µs1920Einige Sensoren und ältere Modems
3840026,0 µs3840HC-05 im AT-Befehlsmodus
5760017,4 µs5760Ältere Arduino-Bootloader, Obergrenze für SoftwareSerial
1152008,68 µs11520ESP32 und ESP-01, schnelle Debug-Ausgabe
1000000 und mehr1 µs und weniger100.000+Kurze Board-zu-Board-Verbindungen, schnelles Datenloggen

UART, I2C und SPI im Vergleich

Die drei häufigsten seriellen Verfahren am Arduino sind UART, I2C und SPI. UART arbeitet nur zwischen zwei Geräten, und beide Seiten können jederzeit senden (Vollduplex). I2C sammelt Dutzende Geräte mit Adressen auf denselben zwei Leitungen; SPI ist mit vier Leitungen viel schneller, braucht aber für jedes Gerät einen eigenen Auswahl-Pin. Einzelheiten findest du in den Beiträgen Was ist I2C und Was ist SPI.

MerkmalUARTI2CSPI
Leitungen2 (TX, RX) + GND2 (SDA, SCL) + GND4 (SCK, MOSI, MISO, CS) + GND
TaktleitungKeine (asynchron)JaJa
Anzahl Geräte2 (Punkt-zu-Punkt)Bis 127, per AdresseSo viele wie CS-Pins
Typische Geschwindigkeit9600–115200 Baud100–400 kHz1–80 MHz
Beide Richtungen gleichzeitigJa (Vollduplex)NeinJa
Typische ModuleGPS, Bluetooth, GSM, ESP-01, FingerabdruckOLED, LCD, RTC, BME280SD-Karte, RFID, TFT, LoRa

TX und RX über Kreuz und gemeinsame Masse

Die goldene Regel der UART-Verdrahtung: Der TX-Pin (Senden) eines Geräts kommt an den RX-Pin (Empfangen) des anderen, die Leitungen werden also gekreuzt. Stell es dir wie Mund und Ohr vor: Wo der eine spricht, muss der andere zuhören. Verbindest du TX mit TX, hängen zwei Ausgänge aneinander und es kommen keine Daten an. Die dritte Leitung, GND, gibt beiden Boards dieselbe Spannungsreferenz; ohne sie verlieren „HIGH“ und „LOW“ ihren Sinn, und es kommen nur wirre Zeichen an. Auch wenn die Boards aus getrennten Quellen versorgt werden, muss die Masse verbunden sein.

Arduino ALeitungArduino BHinweis
TX (D11, SoftwareSerial)→RX (D10, SoftwareSerial)Was A sendet, geht zu B
RX (D10, SoftwareSerial)←TX (D11, SoftwareSerial)Die Antwort von B kommt zu A
GND—GNDGemeinsame Masse, Pflicht
5Voptional5VNur wenn nur ein Board über USB versorgt wird
Beim Arduino Uno und Nano hängen die Hardware-UART-Pins D0 (RX) und D1 (TX) zugleich am USB-Chip. Versuchst du hochzuladen, während dort ein Modul angeschlossen ist, scheitert das mit „not in sync“, und im seriellen Monitor vermischen sich die Daten von Modul und Computer. Zieh beim Hochladen die Leitungen an D0/D1 ab oder nutze wie in den Beispielen dieses Beitrags SoftwareSerial auf anderen Pins.

Zwei Arduinos verbinden: in eine Richtung

Arduino Uno
Arduino Uno: Weil sein einziger Hardware-UART (D0/D1) für USB reserviert ist, verbindest du zwei Unos am bequemsten per SoftwareSerial an D10/D11.

Im ersten Beispiel schickt Board A den Wert eines Potentiometers an A0 zehnmal pro Sekunde an Board B, und B stellt damit die Helligkeit der LED an D9 ein. Beide Boards nutzen SoftwareSerial an D10 (RX) und D11 (TX); so bleiben USB-Verbindung und serieller Monitor frei. Weil die Werte mit println() gesendet werden, endet jede Zahl mit den Zeichen „\r\n“ (Zeilenende); daran erkennt der Empfänger, dass die Zahl vollständig ist. Verdrahtung: D11 von A an D10 von B, D10 von A an D11 von B, Masse an Masse.

C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11);    // RX = 10, TX = 11 (diğer karta / to the other board)
4
5void setup() {
6  Serial.begin(9600);           // USB: bilgisayar / computer
7  link.begin(9600);             // iki tarafta aynı baud / same baud on both sides
8}
9
10void loop() {
11  int deger = analogRead(A0);   // potansiyometre 0-1023 / potentiometer 0-1023
12  link.println(deger);          // ör. "512\r\n" / e.g. "512\r\n"
13  Serial.println(deger);
14  delay(100);                   // saniyede 10 ölçüm / 10 readings per second
15}
16
C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11);    // RX = 10, TX = 11
4const int LED_PIN = 9;          // PWM pini / PWM pin
5
6char tampon[8];                 // en fazla 7 karakter + '\0' / up to 7 chars + '\0'
7byte konum = 0;
8
9void setup() {
10  Serial.begin(9600);
11  link.begin(9600);
12  pinMode(LED_PIN, OUTPUT);
13}
14
15void loop() {
16  while (link.available()) {               // gelen her baytı oku / read every incoming byte
17    char c = link.read();
18    if (c == '\n') {                       // satır bitti / line complete
19      tampon[konum] = '\0';
20      int deger = atoi(tampon);
21      analogWrite(LED_PIN, map(deger, 0, 1023, 0, 255));
22      Serial.println(deger);
23      konum = 0;
24    } else if (c != '\r' && konum < sizeof(tampon) - 1) {
25      tampon[konum++] = c;                 // satıra ekle / append to the line
26    }
27  }
28}
29

Zwei Dinge sind im Empfängercode wichtig. Erstens kommen Daten nie „am Stück“: „512“ trifft als drei einzelne Bytes im Abstand von etwa 1 Millisekunde ein. Deshalb sammeln wir die Bytes in einem Puffer und wandeln sie erst beim Zeilenende in eine Zahl um. Zweitens wartet der Code nirgends: Funktionen wie readString() oder parseInt() warten standardmäßig 1 Sekunde, wenn keine Daten kommen, und bremsen dein Programm. Bytes zu lesen, sobald sie ankommen, ist der zuverlässigste und schnellste Weg. Außerdem begrenzen wir die Puffergröße, damit fehlerhafte Daten nicht über das Array-Ende hinaus geschrieben werden.

Kommunikation in beide Richtungen: Befehl und Antwort

In echten Projekten braucht man meist ein Gespräch in beide Richtungen: Ein Board schickt einen Befehl, das andere führt ihn aus und antwortet. Im folgenden Beispiel arbeitet Board A als Brücke: Jedes Zeichen, das du im seriellen Monitor tippst, leitet es an B weiter, und jedes Zeichen von B gibt es aus. Board B versteht die Befehle „LED ON“, „LED OFF“ und „DURUM?“ (Status), antwortet auf jeden und meldet sich zusätzlich von selbst, wenn der Taster an D2 gedrückt wird. Stell im seriellen Monitor das Zeilenende auf Neue Zeile (Newline); daran erkennt B, dass der Befehl zu Ende ist.

C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11);    // RX = 10, TX = 11
4
5void setup() {
6  Serial.begin(9600);
7  link.begin(9600);
8  Serial.println("Komut yaz / type a command: LED ON, LED OFF, DURUM?");
9}
10
11void loop() {
12  if (Serial.available()) link.write(Serial.read());   // bilgisayar -> B kartı / computer -> board B
13  if (link.available()) Serial.write(link.read());     // B kartı -> bilgisayar / board B -> computer
14}
15
C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11);    // RX = 10, TX = 11
4const int LED_PIN = 13;         // kart üstündeki LED / on-board LED
5const int BUTON_PIN = 2;        // buton GND'ye / button to GND
6
7String satir = "";
8int oncekiButon = HIGH;
9
10void komutCalistir(String k) {
11  k.trim();                                  // \r ve boşlukları at / strip \r and spaces
12  if (k == "LED ON") {
13    digitalWrite(LED_PIN, HIGH);
14    link.println("OK LED=1");
15  } else if (k == "LED OFF") {
16    digitalWrite(LED_PIN, LOW);
17    link.println("OK LED=0");
18  } else if (k == "DURUM?") {                // durum sorgusu / status query
19    link.print("LED=");
20    link.print(digitalRead(LED_PIN));
21    link.print(" BUTON=");
22    link.println(digitalRead(BUTON_PIN) == LOW ? 1 : 0);
23  } else {
24    link.print("HATA / unknown: ");
25    link.println(k);
26  }
27}
28
29void setup() {
30  link.begin(9600);
31  pinMode(LED_PIN, OUTPUT);
32  pinMode(BUTON_PIN, INPUT_PULLUP);
33  satir.reserve(32);
34}
35
36void loop() {
37  while (link.available()) {
38    char c = link.read();
39    if (c == '\n') {
40      komutCalistir(satir);
41      satir = "";
42    } else if (satir.length() < 31) {
43      satir += c;
44    }
45  }
46
47  int buton = digitalRead(BUTON_PIN);        // değişince kendiliğinden bildir / report changes unprompted
48  if (buton != oncekiButon) {
49    oncekiButon = buton;
50    link.println(buton == LOW ? "BUTON BASILDI / pressed" : "BUTON BIRAKILDI / released");
51    delay(20);                               // basit debounce / simple debounce
52  }
53}
54

Der Aufruf trim() auf Board B entfernt das \r, das kommt, wenn der serielle Monitor auf „Sowohl NL als auch CR“ steht, sowie überzählige Leerzeichen; so werden Befehle bei beiden Einstellungen erkannt. reserve(32) für das String-Objekt verhindert, dass bei jedem angehängten Zeichen neuer Speicher belegt wird, und verringert die Fragmentierung der 2 KB RAM des Uno. Diese Struktur ist auch die Grundlage, um den Arduino aus einem Python-Programm auf dem Computer anzusprechen; Details im Beitrag Arduino und Python seriell.

Die Grenzen von SoftwareSerial

SoftwareSerial bildet einen UART in Software statt in Hardware nach: Der Prozessor misst das Timing jedes Bits selbst. Das ist sehr praktisch, hat aber seinen Preis. Beim Senden sind die Interrupts für die gesamte Dauer jedes Bytes gesperrt; bei 9600 Baud sind das etwa 1 Millisekunde pro Byte, in der millis() driften, Servo-Impulse zittern und Daten an einer anderen seriellen Schnittstelle verloren gehen können. Es kann immer nur ein SoftwareSerial-Port gleichzeitig empfangen; öffnest du einen zweiten, wählst du mit listen(), welcher zuhört. Auf Boards wie Mega und Leonardo sind als RX nur bestimmte interruptfähige Pins nutzbar.

MerkmalHardware-UART (Serial)SoftwareSerialAltSoftSerial
Pins am UnoD0 (RX), D1 (TX), mit USB geteiltFast jeder Pin (PCINT für RX)Fest: D8 (RX), D9 (TX)
Höchste zuverlässige Rate1–2 MBaud57600 Baud (115200 grenzwertig)Stabil bei mittleren Raten (9600–38400)
CPU-LastSehr gering (Hardwarepuffer)Hoch, beim Senden Interrupts ausMittel, nutzt Timer1
Gleichzeitig senden und empfangenJaNeinJa
Mehrere Ports4 am MegaNur einer empfängt gleichzeitigEin Port
KonflikteHochladen und serieller MonitorTiming-kritische Bibliotheken wie Servo, NeoPixelPWM an D10 und Servo (Timer1)
Nutzt du mehrere UART-Module (z. B. GPS + Bluetooth), nimm statt des Uno einen Arduino Mega mit vier Hardware-UARTs (Serial1–Serial3 zusätzlich zu Serial) oder einen ESP32 mit drei. Beim Leonardo und Pro Micro ist USB getrennt, Serial1 an D0/D1 ist dort also komplett frei.

Pegelanpassung 5 V und 3,3 V

Bei UART entspricht der „HIGH“-Pegel der Betriebsspannung des Boards: 5 V beim Arduino Uno, 3,3 V beim ESP32, Raspberry Pi Pico, ESP-01 und den meisten neueren Modulen. Einen 5-V-TX-Ausgang direkt an einen 3,3-V-RX-Eingang zu hängen, setzt den Eingang einer Überspannung aus und schädigt den Pin mit der Zeit oder sofort; ESP32 und der Pico mit RP2040 sind nicht 5-V-tolerant. Die andere Richtung ist meist unkritisch: Der Uno wertet 3,0 V und mehr als HIGH, liest also einen 3,3-V-TX, aber weil das nah an der Grenze liegt, ist bei langen Leitungen ein Pegelwandler robuster.

VerbindungWas wird gebraucht?Beispiel
Uno TX (5 V) → ESP32 / Pico RX (3,3 V)Spannungsteiler oder Pegelwandler1 kΩ in Reihe + 2 kΩ nach GND: 5 × 2/3 ≈ 3,3 V
ESP32 / Pico TX (3,3 V) → Uno RX (5 V)Meist direktDer Uno wertet über 3,0 V als HIGH
Uno TX → HC-05 RXSpannungsteiler empfohlenDer RX des HC-05 arbeitet mit 3,3-V-Pegel
Uno TX → SIM800L RXSpannungsteilerDer Signalpegel des SIM800L liegt bei etwa 2,8 V
Beide Boards 5 V oder beide 3,3 VDirektUno ↔ Nano, ESP32 ↔ Pico
Ein Spannungsteiler eignet sich nur für einseitige Signale mit niedriger bis mittlerer Geschwindigkeit (etwa bis 115200 Baud). Für bidirektionale oder sehr schnelle Leitungen nimm einen bidirektionalen Pegelwandler auf BSS138-Basis. Die Widerstände berechnest du mit dem Spannungsteiler-Rechner; Pegelwandler erklärt der Beitrag Logikpegelwandler ausführlich.

UART beim ESP32: Serial, Serial1 und Serial2

Der ESP32 hat drei Hardware-UARTs, und das Beste: Dank GPIO-Matrix lassen sich die UART-Pins auf fast jeden beliebigen Pin legen. UART0 (Serial) hängt am USB-Seriell-Chip und dient dem seriellen Monitor. UART2 (Serial2) liegt standardmäßig an GPIO 16 (RX) und 17 (TX). Die alten Standardpins von UART1 (GPIO 9 und 10) sind mit dem Flash-Speicher des Boards verbunden und direkt nicht nutzbar; starte Serial1 deshalb immer mit Pinangabe: begin(baud, SERIAL_8N1, RX, TX). Der folgende Code baut eine Brücke in beide Richtungen zwischen seriellem Monitor und einem Gerät an UART2 (GPS, ein anderer Arduino, ein Sensor); ideal, um die NMEA-Sätze eines GPS-Moduls anzusehen.

UARTArduino-NameStandard RX / TXHinweis
UART0SerialGPIO 3 / GPIO 1Am USB-Seriell-Chip, Hochladen und serieller Monitor
UART1Serial1GPIO 9 / GPIO 10 (Flash, nicht nutzen)In begin() andere Pins angeben, z. B. 25 / 26
UART2Serial2GPIO 16 / GPIO 17Auf WROVER-Boards belegt PSRAM 16/17, andere Pins wählen
C++ (Arduino IDE)
1// ESP32: UART0 = Serial (USB), UART2 = Serial2 (GPIO 16/17)
2const int RXD2 = 16;            // karşı cihazın TX'i buraya / the other device's TX goes here
3const int TXD2 = 17;            // karşı cihazın RX'ine / to the other device's RX
4
5void setup() {
6  Serial.begin(115200);                          // USB Seri Monitör / USB Serial Monitor
7  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);   // baud, çerçeve, RX, TX / baud, frame, RX, TX
8  // UART1'i de istediğin pinlere taşıyabilirsin / UART1 can be moved to any free pins:
9  // Serial1.begin(115200, SERIAL_8N1, 25, 26);
10  Serial.println("UART2 hazir / ready");
11}
12
13void loop() {
14  while (Serial2.available()) Serial.write(Serial2.read());   // UART2 -> USB
15  while (Serial.available()) Serial2.write(Serial.read());    // USB -> UART2
16}
17

Die UARTs des ESP32 schaffen bis 5 MBaud und haben je einen Hardwarepuffer; der Standard-Empfangspuffer ist 256 Byte groß und lässt sich vor begin() mit einem Aufruf wie Serial2.setRxBufferSize(1024) vergrößern. Das ist wichtig bei GPS-Modulen, die Dutzende Sätze pro Sekunde senden, oder GSM-Modulen mit langen Antworten. Da die Pins des ESP32 mit 3,3 V arbeiten, vergiss beim Anschluss eines 5-V-Arduino den Teiler aus dem vorigen Abschnitt nicht. Die Pinbelegung des ESP32 zeigt das Werkzeug Pinout.

UART-Pins des Raspberry Pi Pico und MicroPython

Der Raspberry Pi Pico hat zwei Hardware-UARTs (uart0 und uart1), die sich jeweils auf mehrere Pinpaare legen lassen. In MicroPython kommen REPL und print()-Ausgaben über einen eigenen virtuellen seriellen Port per USB, UART0 ist also komplett frei; anders als beim Arduino musst du beim Hochladen keine Leitungen abziehen. Die Pins des Pico arbeiten mit 3,3 V und sind beim Pico mit RP2040 nicht 5-V-tolerant. Der folgende Code macht auf dem Pico, was Board B beim Arduino gemacht hat: Er liest Zeilen von UART0, schaltet mit „LED ON“ und „LED OFF“ die Onboard-LED und antwortet. Soll er mit dem Brücken-Sketch auf dem Uno sprechen, denk an einen Spannungsteiler in der TX-Leitung des Uno.

UARTTX-PinsRX-PinsMicroPython-Beispiel
uart0GP0, GP12, GP16GP1, GP13, GP17UART(0, 9600, tx=Pin(0), rx=Pin(1))
uart1GP4, GP8GP5, GP9UART(1, 9600, tx=Pin(4), rx=Pin(5))
MicroPython
1from machine import UART, Pin
2import time
3
4uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))   # UART0: GP0 = TX, GP1 = RX
5led = Pin("LED", Pin.OUT)                             # Pico ve Pico W dahili LED / on-board LED
6
7tampon = b""
8while True:
9    if uart.any():
10        tampon += uart.read()                         # gelen baytlar / incoming bytes
11        while b"\n" in tampon:                        # her tam satırı işle / handle each full line
12            satir, tampon = tampon.split(b"\n", 1)
13            try:
14                komut = satir.decode().strip()
15            except UnicodeError:
16                continue                              # bozuk bayt: atla / corrupt byte: skip
17            if komut == "LED ON":
18                led.on()
19                uart.write("OK LED=1\n")
20            elif komut == "LED OFF":
21                led.off()
22                uart.write("OK LED=0\n")
23            else:
24                uart.write("HATA / unknown: " + komut + "\n")
25    if len(tampon) > 64:                              # satır sonu hiç gelmezse taşmayı önle / avoid overflow
26        tampon = b""
27    time.sleep_ms(5)
28

Datenpakete: Start- und Endezeichen

UART ist ein Bytestrom; er weiß nicht, wo etwas anfängt oder aufhört. Schreibt der Sender „23.5,48,812“, kann der Empfänger mittendrin angefangen haben zuzuhören, ein Byte kann durch Störungen verloren gehen, oder zwei Messwerte laufen ineinander. Die Lösung ist ein Paket: Beginnt jedes Paket mit „<“ und endet mit „>“, ignoriert der Empfänger alles bis zum ersten „<“, verarbeitet das Paket beim „>“ und verwirft halbe Pakete dazwischen. Der Sender muss die Werte nur zwischen Serial.print('<'), Kommas und Serial.print('>') ausgeben. Den Empfängercode unten kannst du sofort testen, indem du im seriellen Monitor <23.5,48,812> eingibst.

C++ (Arduino IDE)
1// Paket biçimi / packet format: <sicaklik,nem,isik>  ör. / e.g. <23.5,48,812>
2const byte MAKS = 32;
3char tampon[MAKS];
4byte konum = 0;
5bool paketIcinde = false;                    // '<' görüldü mü? / have we seen '<'?
6
7void paketiIsle(char* p) {
8  char* parca = strtok(p, ",");              // ilk alan / first field
9  if (!parca) return;
10  float sicaklik = atof(parca);
11  parca = strtok(NULL, ",");
12  if (!parca) return;                        // eksik alan: paketi at / missing field: drop
13  int nem = atoi(parca);
14  parca = strtok(NULL, ",");
15  if (!parca) return;
16  int isik = atoi(parca);
17
18  Serial.print("Sicaklik / temp: ");
19  Serial.print(sicaklik, 1);
20  Serial.print("  Nem / humidity: ");
21  Serial.print(nem);
22  Serial.print("  Isik / light: ");
23  Serial.println(isik);
24}
25
26void setup() {
27  Serial.begin(9600);                        // Seri Monitör'den <23.5,48,812> yazarak dene / test from the Serial Monitor
28}
29
30void loop() {
31  while (Serial.available()) {
32    char c = Serial.read();
33    if (c == '<') {                          // yeni paket başladı / a new packet starts
34      paketIcinde = true;
35      konum = 0;
36    } else if (c == '>' && paketIcinde) {    // paket bitti / packet complete
37      tampon[konum] = '\0';
38      paketIcinde = false;
39      paketiIsle(tampon);
40    } else if (paketIcinde) {
41      if (konum < MAKS - 1) tampon[konum++] = c;
42      else paketIcinde = false;              // çok uzun, bozuk: at / too long, corrupt: drop
43    }                                        // paket dışındaki baytlar yok sayılır / bytes outside packets are ignored
44  }
45}
46
VerfahrenBeispielVorteilNachteil
Text mit Zeilenende512\nAm einfachsten, im seriellen Monitor lesbarMitten in der Zeile ist der Anfang unklar
Start- und Endezeichen<23.5,48,812>Fängt sich nach Synchronverlust selbst< und > sind in den Daten tabu
Text mit Prüfsumme (wie NMEA)$GPGGA,...*47Beschädigte Pakete werden erkanntEtwas mehr Rechnung und Code
Binärpaket0xAA, Länge, Daten, CRCAm kürzesten und schnellstenSchwer zu lesen und zu debuggen

In gestörter Umgebung oder bei langen Leitungen kannst du noch einen Schritt weitergehen und eine Prüfsumme anhängen. Das von GPS-Modulen genutzte NMEA-Format ist ein gutes Beispiel: Alle Zeichen zwischen „$“ und „*“ werden per XOR verknüpft, das Ergebnis steht als zweistellige Hexzahl am Ende. Der Empfänger rechnet genauso und verwirft das Paket, wenn es nicht passt. So vermeidest du heimtückische Fehler, etwa dass ein beschädigter Wert „812“ als „872“ verarbeitet wird.

Der Sender darf nicht schneller sein, als der Empfänger verarbeiten kann. Der Hardware-Empfangspuffer des Arduino Uno fasst nur 64 Byte; nutzt du in loop() lange delay()-Aufrufe, gehen ankommende Bytes verloren, sobald der Puffer voll ist. Verwende beim Empfänger millis() statt delay() und prüfe Serial.available() in jedem Schleifendurchlauf.

Projektideen mit UART

  • Steuerung per Handy: Das HC-05 ist eigentlich ein drahtloser UART; steuere mit dem HC-05 eine LED, ein Relais oder ein Roboterauto vom Smartphone.
  • GPS-Logger: Werte die NMEA-Sätze aus, die ein NEO-6M GPS per UART sendet, und schreib die Position auf eine SD-Karte.
  • System aus zwei Boards: Verbinde einen Uno, der die Sensoren liest, per UART mit einem ESP32, der die Daten über WLAN ins Internet schickt.
  • SMS-Alarm: Schick einem SIM800L per UART AT-Befehle und lass dir eine SMS senden, wenn eine Tür aufgeht.
  • Bedienfeld am Computer: Sende aus einer in Python geschriebenen Desktop-App Befehle an den Arduino und stell die Sensordaten als Diagramm dar.
  • MP3-Player: Wähle mit einem DFPlayer Mini über UART Titel aus, stell die Lautstärke ein und spiel Sprachansagen ab.

Häufige Fehler und Lösungen

SymptomMögliche UrsacheLösung
Wirre Zeichen im seriellen MonitorBaudraten stimmen nicht übereinIm Code und im seriellen Monitor dieselbe Baudrate wählen
Gar keine DatenTX an TX, RX an RX verdrahtetÜber Kreuz verbinden: TX → RX, RX → TX
Zufällig beschädigte ZeichenGND nicht verbundenMasse beider Boards verbinden
Hochladen scheitert (not in sync)Modul an D0/D1 angeschlossenBeim Hochladen abziehen oder SoftwareSerial nutzen
Befehle werden nicht erkanntZeilenende ist \r\n oder fehltSeriellen Monitor auf Neue Zeile stellen, Text mit trim() säubern
Das Ende langer Nachrichten fehlt64-Byte-Puffer übergelaufenKein delay(), Daten sofort lesen, Rate senken
RX-Pin des ESP32 geht nicht oder ist defekt5-V-TX direkt angeschlossenSpannungsteiler oder Pegelwandler einbauen
SoftwareSerial macht bei 115200 FehlerDas Software-Timing kommt nicht mit57600 oder weniger nutzen oder zum Hardware-UART wechseln
Antwortet ein UART-Modul nicht, schließ es zuerst mit einem USB-TTL-Wandler direkt an den Computer an und sende Befehle aus einem seriellen Terminal. Funktioniert es dort, liegt der Fehler im Arduino-Code oder in der Verdrahtung; funktioniert es auch dort nicht, prüfe Baudrate, Versorgung und das Modul selbst.

UART ist das erste Kommunikationsverfahren, das man in der Elektronik lernen sollte: Zwei Leitungen, eine gemeinsame Masse und dieselbe Baudrate genügen, und richtig aufgebaut läuft es jahrelang ohne Probleme. Wenn du gekreuzte Verdrahtung, Pegelanpassung und Pakete beherrschst, kannst du Dutzende Module vom GPS bis zum GSM bequem nutzen. In der BlueGrays-App findest du Projekte zur einseitigen und zweiseitigen Kommunikation zwischen zwei Arduinos, zum Einschalten einer LED per Bluetooth vom Handy und zu einem per Bluetooth gesteuerten Auto, jeweils Schritt für Schritt mit Schaltplan und Code.

Häufige Fragen

Wofür steht UART und wofür braucht man es?

UART steht für Universal Asynchronous Receiver-Transmitter. Damit tauschen zwei Geräte ohne Taktleitung, nur über TX und RX und mit einer vorher vereinbarten Baudrate, Byte für Byte Daten aus. Der serielle Monitor des Arduino, GPS-, Bluetooth- und GSM-Module nutzen UART.

Wie verbindet man TX und RX?

Der TX-Pin des einen Geräts kommt an den RX-Pin des anderen und umgekehrt, die Verbindung ist also gekreuzt. Zusätzlich müssen die GND-Pins beider Geräte verbunden sein. TX an TX verhindert jeden Datenfluss.

Was ist die Baudrate und welche soll ich wählen?

Die Baudrate ist die Zahl der pro Sekunde übertragenen Bits und muss auf beiden Seiten gleich sein. Am häufigsten sind bei Arduino-Modulen 9600 und 115200; 9600 ist Standard bei den meisten GPS- und Bluetooth-Modulen, 115200 wird beim ESP32 und für schnelle Ausgaben bevorzugt. Starte mit der im Datenblatt des Moduls angegebenen Standardrate.

Ist UART dasselbe wie eine serielle Schnittstelle?

Im Alltag werden die Begriffe oft gleich verwendet. UART ist die Hardwareeinheit, die Daten seriell macht; die serielle Schnittstelle ist der COM- oder /dev/tty-Anschluss am Computer. RS-232 und RS-485 sind Standards, die UART-Signale mit anderen Spannungspegeln über größere Entfernungen übertragen.

Wie nutze ich mehrere UARTs am Arduino?

Der Uno hat nur einen Hardware-UART, den er mit USB teilt; weitere Ports bekommst du mit SoftwareSerial, wobei immer nur einer empfangen kann. Der Arduino Mega hat drei zusätzliche Hardware-UARTs (Serial1, Serial2, Serial3), der ESP32 insgesamt drei und der Raspberry Pi Pico zwei.

Wie lang darf ein UART-Kabel sein?

UART mit TTL-Pegel (3,3 V oder 5 V) funktioniert bei niedrigen Baudraten zuverlässig bis zu einigen Metern; mit steigender Geschwindigkeit sinkt die Distanz. Für größere Entfernungen schaffen RS-485-Transceiver (z. B. MAX485) Hunderte Meter, RS-232 etwa 15 Meter.

Alle Projekte ansehen
Einweg-Kommunikation zwischen 2 Arduinos
#57Mittel
Premium

Einweg-Kommunikation zwischen 2 Arduinos

Du bringst zwei Arduinos über ein einziges Kabel zum Reden: Drückst du den Knopf am einen, geht die LED am anderen an, drückst du noch einmal, geht sie aus. Die sendende Platine meldet den Knopfdruck

4.4(37)
50
Bidirektionale Kommunikation zwischen 2 Arduinos
#58Mittel
Premium

Bidirektionale Kommunikation zwischen 2 Arduinos

Zwei Arduinos werden per Kabel verbunden und unterhalten sich: Drückst du den Knopf am einen, geht am anderen das Licht an, drückst du noch einmal, geht es aus. Auf beiden Platinen läuft dasselbe Prog

4.5(20)
26
LED per Bluetooth mit dem Handy steuern
#34Anfänger
Premium

LED per Bluetooth mit dem Handy steuern

Eine kleine Probe dafür, das Licht in deinem Zimmer vom Handy aus ein- und auszuschalten. Das Bluetooth-Modul leitet die Buchstaben, die du vom Handy schickst, an den Arduino weiter; ein Buchstabe sch

4.8(68)
89
Bluetooth-gesteuertes Auto mit L298N
#80Fortgeschritten
Premium

Bluetooth-gesteuertes Auto mit L298N

Mach dein Handy zur Fernbedienung und steuere dein eigenes Roboterauto. Der Arduino empfängt über ein Bluetooth-Modul die Befehle einer Fernsteuer-App auf dem Handy und treibt die Räder über einen Mot

5.0(38)
65
Python-Entwickler-Tastatur
#66Mittel
Premium

Python-Entwickler-Tastatur

Wenn du es leid bist, beim Programmieren immer wieder dieselben Muster zu tippen, ist diese kleine Tastatur genau das Richtige. Der Arduino Leonardo meldet sich am Computer wie eine ganz normale Tasta

4.6(35)
45
HC-SR04 Abstandsmessung (serielle Anzeige)
#27Anfänger

HC-SR04 Abstandsmessung (serielle Anzeige)

Der Sensor HC-SR04 funktioniert wie eine Fledermaus, die im Dunkeln ihren Weg findet: Er sendet einen Ton, den du nicht hörst, lauscht auf das Echo und misst, wie weit der Gegenstand vor ihm entfernt

4.6(46)
71
Temperatur und Luftfeuchtigkeit mit DHT11
#55Mittel

Temperatur und Luftfeuchtigkeit mit DHT11

Wie warm ist dein Zimmer, und ist die Luft feucht oder trocken? Der DHT11-Sensor misst Temperatur und Luftfeuchtigkeit, und der Arduino schreibt die Werte auf ein zweizeiliges LCD und aktualisiert sie

4.7(47)
73
Messung der Lichtintensität mit dem ESP32-LDR-Modul
#113Anfänger

Messung der Lichtintensität mit dem ESP32-LDR-Modul

Echtzeit-Anzeige des ADC-Rohwerts des LDR-Moduls und des anhand von Dunkel- und Hellreferenzwerten berechneten relativen Lichtwerts in Prozent im Serial Monitor. Dieser Prozentwert ist keine Lux-Messung. Vermittelt die Kalibrierungslogik des Moduls. Sollte idealerweise vor Projekt 10 durchgeführt werden, da es zur Festlegung des Schwellenwerts dient.

4.6(36)
55