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.

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.
| Bit | Start | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | Stopp |
|---|---|---|---|---|---|---|---|---|---|---|
| Buchstabe 'A' (0x41 = 0100 0001) | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
| Pegel der Leitung | LOW | HIGH | LOW | LOW | LOW | LOW | LOW | HIGH | LOW | HIGH |
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.
| Baud | Bitdauer | Max. Byte pro Sekunde (8N1) | Wo wird es genutzt? |
|---|---|---|---|
| 9600 | 104,2 µs | 960 | NEO-6M GPS, HC-05 Datenmodus, DFPlayer Mini, klassische Einstellung des seriellen Monitors |
| 19200 | 52,1 µs | 1920 | Einige Sensoren und ältere Modems |
| 38400 | 26,0 µs | 3840 | HC-05 im AT-Befehlsmodus |
| 57600 | 17,4 µs | 5760 | Ältere Arduino-Bootloader, Obergrenze für SoftwareSerial |
| 115200 | 8,68 µs | 11520 | ESP32 und ESP-01, schnelle Debug-Ausgabe |
| 1000000 und mehr | 1 µs und weniger | 100.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.
| Merkmal | UART | I2C | SPI |
|---|---|---|---|
| Leitungen | 2 (TX, RX) + GND | 2 (SDA, SCL) + GND | 4 (SCK, MOSI, MISO, CS) + GND |
| Taktleitung | Keine (asynchron) | Ja | Ja |
| Anzahl Geräte | 2 (Punkt-zu-Punkt) | Bis 127, per Adresse | So viele wie CS-Pins |
| Typische Geschwindigkeit | 9600–115200 Baud | 100–400 kHz | 1–80 MHz |
| Beide Richtungen gleichzeitig | Ja (Vollduplex) | Nein | Ja |
| Typische Module | GPS, Bluetooth, GSM, ESP-01, Fingerabdruck | OLED, LCD, RTC, BME280 | SD-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 A | Leitung | Arduino B | Hinweis |
|---|---|---|---|
| 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 | — | GND | Gemeinsame Masse, Pflicht |
| 5V | optional | 5V | Nur wenn nur ein Board über USB versorgt wird |
Zwei Arduinos verbinden: in eine Richtung

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.
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}
161#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}
29Zwei 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.
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}
151#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}
54Der 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.
| Merkmal | Hardware-UART (Serial) | SoftwareSerial | AltSoftSerial |
|---|---|---|---|
| Pins am Uno | D0 (RX), D1 (TX), mit USB geteilt | Fast jeder Pin (PCINT für RX) | Fest: D8 (RX), D9 (TX) |
| Höchste zuverlässige Rate | 1–2 MBaud | 57600 Baud (115200 grenzwertig) | Stabil bei mittleren Raten (9600–38400) |
| CPU-Last | Sehr gering (Hardwarepuffer) | Hoch, beim Senden Interrupts aus | Mittel, nutzt Timer1 |
| Gleichzeitig senden und empfangen | Ja | Nein | Ja |
| Mehrere Ports | 4 am Mega | Nur einer empfängt gleichzeitig | Ein Port |
| Konflikte | Hochladen und serieller Monitor | Timing-kritische Bibliotheken wie Servo, NeoPixel | PWM an D10 und Servo (Timer1) |
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.
| Verbindung | Was wird gebraucht? | Beispiel |
|---|---|---|
| Uno TX (5 V) → ESP32 / Pico RX (3,3 V) | Spannungsteiler oder Pegelwandler | 1 kΩ in Reihe + 2 kΩ nach GND: 5 × 2/3 ≈ 3,3 V |
| ESP32 / Pico TX (3,3 V) → Uno RX (5 V) | Meist direkt | Der Uno wertet über 3,0 V als HIGH |
| Uno TX → HC-05 RX | Spannungsteiler empfohlen | Der RX des HC-05 arbeitet mit 3,3-V-Pegel |
| Uno TX → SIM800L RX | Spannungsteiler | Der Signalpegel des SIM800L liegt bei etwa 2,8 V |
| Beide Boards 5 V oder beide 3,3 V | Direkt | Uno ↔ Nano, ESP32 ↔ Pico |
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.
| UART | Arduino-Name | Standard RX / TX | Hinweis |
|---|---|---|---|
| UART0 | Serial | GPIO 3 / GPIO 1 | Am USB-Seriell-Chip, Hochladen und serieller Monitor |
| UART1 | Serial1 | GPIO 9 / GPIO 10 (Flash, nicht nutzen) | In begin() andere Pins angeben, z. B. 25 / 26 |
| UART2 | Serial2 | GPIO 16 / GPIO 17 | Auf WROVER-Boards belegt PSRAM 16/17, andere Pins wählen |
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}
17Die 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.
| UART | TX-Pins | RX-Pins | MicroPython-Beispiel |
|---|---|---|---|
| uart0 | GP0, GP12, GP16 | GP1, GP13, GP17 | UART(0, 9600, tx=Pin(0), rx=Pin(1)) |
| uart1 | GP4, GP8 | GP5, GP9 | UART(1, 9600, tx=Pin(4), rx=Pin(5)) |
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)
28Datenpakete: 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.
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| Verfahren | Beispiel | Vorteil | Nachteil |
|---|---|---|---|
| Text mit Zeilenende | 512\n | Am einfachsten, im seriellen Monitor lesbar | Mitten 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,...*47 | Beschädigte Pakete werden erkannt | Etwas mehr Rechnung und Code |
| Binärpaket | 0xAA, Länge, Daten, CRC | Am kürzesten und schnellsten | Schwer 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.
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
| Symptom | Mögliche Ursache | Lösung |
|---|---|---|
| Wirre Zeichen im seriellen Monitor | Baudraten stimmen nicht überein | Im Code und im seriellen Monitor dieselbe Baudrate wählen |
| Gar keine Daten | TX an TX, RX an RX verdrahtet | Über Kreuz verbinden: TX → RX, RX → TX |
| Zufällig beschädigte Zeichen | GND nicht verbunden | Masse beider Boards verbinden |
| Hochladen scheitert (not in sync) | Modul an D0/D1 angeschlossen | Beim Hochladen abziehen oder SoftwareSerial nutzen |
| Befehle werden nicht erkannt | Zeilenende ist \r\n oder fehlt | Seriellen Monitor auf Neue Zeile stellen, Text mit trim() säubern |
| Das Ende langer Nachrichten fehlt | 64-Byte-Puffer übergelaufen | Kein delay(), Daten sofort lesen, Rate senken |
| RX-Pin des ESP32 geht nicht oder ist defekt | 5-V-TX direkt angeschlossen | Spannungsteiler oder Pegelwandler einbauen |
| SoftwareSerial macht bei 115200 Fehler | Das Software-Timing kommt nicht mit | 57600 oder weniger nutzen oder zum Hardware-UART wechseln |
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.
Projekte, die du danach bauen kannst
Alle Projekte ansehen
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

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

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

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

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

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

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

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.
Weitere Artikel
BlueGrays-App
Diese Schaltung Schritt für Schritt auf dem Handy nachbauen
Schaltplan, Code und Teileliste auf einem Bildschirm. Über 200 Arduino-, ESP32- und Pico-Projekte zum Nachbauen.
Mit dem Handy scannen
Richte die Kamera auf den Code, dann öffnet sich der App-Store deines Handys.
oder im Store öffnen

