UART Nedir? TX/RX Bağlantısı, Baud ve İki Arduino Haberleşmesi
UART nedir, nasıl çalışır? TX/RX çapraz bağlantı, baud, start/stop bit, iki Arduino haberleşmesi, SoftwareSerial, 5V–3,3V uyumu, ESP32 Serial2 ve Pico UART.
UART nedir sorusunun kısa cevabı şudur: UART (Universal Asynchronous Receiver-Transmitter), iki cihazın yalnızca iki veri kablosu (TX ve RX) ve ortak bir GND ile bayt bayt veri alışverişi yapmasını sağlayan seri haberleşme donanımıdır. Arduino'yu bilgisayara bağladığında Seri Monitör'de gördüğün her yazı UART üzerinden gelir. GPS modülleri, HC-05 Bluetooth, ESP-01 Wi-Fi, SIM800L GSM, parmak izi okuyucular ve MP3 çalarlar gibi onlarca modül de Arduino ile UART üzerinden konuşur.
Bu yazıda UART'ın neden saat hattına ihtiyaç duymadığını, baud hızını, bir baytın start, veri ve stop bitleriyle nasıl çerçevelendiğini, TX ve RX'in neden çapraz bağlandığını, iki Arduino'yu önce tek yönlü, sonra çift yönlü haberleştirmeyi, SoftwareSerial'ın sınırlarını, 5 V ile 3,3 V kartları güvenle bağlamayı, ESP32'nin üç UART'ını ve Raspberry Pi Pico'nun UART pinlerini adım adım anlatıyoruz. Son bölümde verinin karışmaması için başlangıç ve bitiş karakterli paket yapmayı ve en sık karşılaşılan hataları göreceksin.

UART nedir, nasıl çalışır?
UART'ın adındaki "asenkron" kelimesi işin özüdür: I2C ve SPI'de veriyle birlikte bir saat (clock) sinyali de gönderilir, UART'ta ise saat hattı yoktur. Bunun yerine iki taraf önceden bir hız üzerinde anlaşır; buna baud hızı denir. Hat boştayken HIGH (1) seviyesinde bekler. Gönderici bir bayt göndereceğinde hattı bir bit süresi boyunca LOW yapar; bu start bitidir ve alıcıya "şimdi saymaya başla" der. Ardından 8 veri biti en düşük anlamlı bitten (LSB) başlayarak sırayla gönderilir, isteğe bağlı bir parite biti gelebilir ve en sonda hat en az bir bit süresi HIGH yapılır; bu da stop bitidir. Arduino'nun varsayılan ayarı 8N1'dir: 8 veri biti, parite yok, 1 stop biti.
| Bit | Start | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | Stop |
|---|---|---|---|---|---|---|---|---|---|---|
| 'A' harfi (0x41 = 0100 0001) | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
| Hattın seviyesi | LOW | HIGH | LOW | LOW | LOW | LOW | LOW | HIGH | LOW | HIGH |
Her bitin süresi 1 / baud saniyedir. 9600 baud'da bir bit 104,2 mikrosaniye sürer; 8N1 çerçevesinde bir bayt 10 bit (start + 8 veri + stop) olduğu için saniyede en fazla 960 bayt gönderilebilir. Alıcı, start bitinin düşen kenarını yakaladıktan sonra her bitin tam ortasında hattı okur. İki tarafın saatleri birbirinden biraz farklı olsa bile 10 bit boyunca biriken hata bir bitin yarısını geçmediği sürece veri doğru okunur; bu yüzden toplam baud hatasının yaklaşık %2–3'ün altında kalması gerekir. Arduino Uno 16 MHz kristaliyle 115200 baud'u tam üretemez, gerçek hız yaklaşık %2,1 farklıdır; yine de sınırın içinde kaldığı için çalışır.
| Baud | Bit süresi | Saniyede en fazla bayt (8N1) | Nerede kullanılır? |
|---|---|---|---|
| 9600 | 104,2 µs | 960 | NEO-6M GPS, HC-05 veri modu, DFPlayer Mini, Seri Monitör'ün klasik ayarı |
| 19200 | 52,1 µs | 1920 | Bazı sensörler ve eski modemler |
| 38400 | 26,0 µs | 3840 | HC-05 AT komut modu |
| 57600 | 17,4 µs | 5760 | Eski Arduino bootloader'ları, SoftwareSerial için üst sınır |
| 115200 | 8,68 µs | 11520 | ESP32 ve ESP-01, hızlı hata ayıklama çıktısı |
| 1000000 ve üstü | 1 µs ve altı | 100.000+ | Kısa kablolu kart-kart bağlantılar, hızlı veri kaydı |
UART, I2C ve SPI farkı
Arduino'da en sık kullanılan üç seri haberleşme yöntemi UART, I2C ve SPI'dir. UART yalnızca iki cihaz arasında birebir çalışır ve iki tarafın da istediği an konuşabildiği (full duplex) bir bağlantıdır. I2C iki kabloyla onlarca cihazı adresleriyle aynı hatta toplar; SPI ise dört kabloyla çok daha hızlıdır ama her cihaz için ayrı bir seçim pini ister. Ayrıntılar için I2C nedir ve SPI nedir yazılarına bakabilirsin.
| Özellik | UART | I2C | SPI |
|---|---|---|---|
| Kablo sayısı | 2 (TX, RX) + GND | 2 (SDA, SCL) + GND | 4 (SCK, MOSI, MISO, CS) + GND |
| Saat hattı | Yok (asenkron) | Var | Var |
| Cihaz sayısı | 2 (noktadan noktaya) | 127'ye kadar, adresle | CS pini kadar |
| Tipik hız | 9600–115200 baud | 100–400 kHz | 1–80 MHz |
| Aynı anda iki yön | Evet (full duplex) | Hayır | Evet |
| Tipik modüller | GPS, Bluetooth, GSM, ESP-01, parmak izi | OLED, LCD, RTC, BME280 | SD kart, RFID, TFT, LoRa |
TX ve RX çapraz bağlantı, ortak GND
UART bağlantısının altın kuralı şudur: bir cihazın TX (gönderen) pini, diğerinin RX (alan) pinine bağlanır; yani kablolar çapraz gider. Ağzı kulağa bağlamak gibi düşünebilirsin: birinin konuştuğu yer, diğerinin dinlediği yer olmalı. TX'i TX'e bağlarsan iki çıkış birbirine bağlanmış olur ve hiçbir veri gitmez. Üçüncü kablo olan GND ise iki kartın gerilim referansını eşitler; GND bağlanmazsa "HIGH" ve "LOW" seviyeleri anlamsızlaşır ve gelen veri anlamsız karakterlere dönüşür. Kartlar ayrı kaynaklardan besleniyor olsa bile GND mutlaka birleştirilmelidir.
| Arduino A | Kablo | Arduino B | Not |
|---|---|---|---|
| TX (D11, SoftwareSerial) | → | RX (D10, SoftwareSerial) | A'nın gönderdiği B'ye gider |
| RX (D10, SoftwareSerial) | ← | TX (D11, SoftwareSerial) | B'nin cevabı A'ya gelir |
| GND | — | GND | Ortak toprak, zorunlu |
| 5V | isteğe bağlı | 5V | Yalnız biri USB'den besleniyorsa |
İki Arduino'yu haberleştirmek: tek yönlü

İlk örnekte A kartı A0'a bağlı bir potansiyometrenin değerini saniyede 10 kez B kartına gönderiyor, B kartı da bu değere göre D9'daki LED'in parlaklığını ayarlıyor. Her iki kartta da SoftwareSerial ile D10 (RX) ve D11 (TX) kullanıyoruz; böylece USB bağlantısı ve Seri Monitör serbest kalıyor. Değerler println() ile gönderildiği için her sayının sonunda "\r\n" (satır sonu) karakterleri vardır; alıcı bu karakteri görünce sayının bittiğini anlar. Bağlantı: A'nın D11'i B'nin D10'una, A'nın D10'u B'nin D11'ine, GND'ler birbirine.
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}
29Alıcı kodunda dikkat etmen gereken iki şey var. Birincisi, veri hiçbir zaman "tek parça" gelmez: "512" üç ayrı bayt olarak, aralarında yaklaşık 1 milisaniye ile ulaşır. Bu yüzden baytları bir tampona biriktirip satır sonu geldiğinde sayıya çeviriyoruz. İkincisi, kod hiçbir yerde beklemiyor: readString() ya da parseInt() gibi fonksiyonlar veri gelmediğinde varsayılan olarak 1 saniye bekler ve programını yavaşlatır. Baytları geldikçe okuyan bu yöntem en güvenilir ve en hızlı yoldur. Tampon boyutunu da sınırlıyoruz; bozuk bir veri gelirse dizinin dışına yazılmaz.
Çift yönlü haberleşme: komut ve cevap
Gerçek projelerde çoğu zaman iki yönlü bir konuşma gerekir: bir kart komut gönderir, diğeri uygular ve cevap verir. Aşağıdaki örnekte A kartı bir köprü gibi çalışır: Seri Monitör'e yazdığın her karakteri B'ye iletir, B'den gelen her karakteri de ekrana yazar. B kartı "LED ON", "LED OFF" ve "DURUM?" komutlarını anlar, her komuta cevap verir ve D2'deki butona basıldığında da kimse sormadan haber gönderir. Seri Monitör'de satır sonu ayarını Newline (Yeni Satır) yapmayı unutma; B komutun bittiğini bu karakterden anlar.
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}
54B kartındaki trim() çağrısı, Seri Monitör "Both NL & CR" ayarındayken gelen \r karakterini ve fazladan boşlukları temizler; bu sayede iki ayarda da komutlar tanınır. String nesnesi için reserve(32) kullanmak, her karakter eklendiğinde belleğin yeniden düzenlenmesini önler ve Uno'nun 2 KB'lık RAM'inin parçalanmasını azaltır. Bu yapı, bilgisayardaki bir Python programıyla Arduino'yu konuşturmanın da temelidir; ayrıntılar Arduino Python seri haberleşme yazısında.
SoftwareSerial'ın sınırları
SoftwareSerial, UART'ı donanım yerine yazılımla taklit eder: her bitin zamanlamasını işlemci kendisi ölçer. Bu çok kullanışlıdır ama bedeli vardır. Gönderim sırasında her bayt boyunca kesmeler kapatılır; 9600 baud'da bu bayt başına yaklaşık 1 milisaniye demektir ve bu sırada millis() kayabilir, servo darbeleri titreyebilir, başka seri porttan gelen veri kaçabilir. Aynı anda yalnızca bir SoftwareSerial portu dinleyebilir; ikinci bir port açarsan hangisini dinleyeceğini listen() ile seçmen gerekir. Mega ve Leonardo gibi kartlarda RX olarak yalnızca kesme destekli belirli pinler kullanılabilir.
| Özellik | Donanım UART (Serial) | SoftwareSerial | AltSoftSerial |
|---|---|---|---|
| Uno'da pinler | D0 (RX), D1 (TX), USB ile ortak | Neredeyse her pin (RX için PCINT) | Sabit: D8 (RX), D9 (TX) |
| Güvenilir en yüksek hız | 1–2 Mbaud | 57600 baud (115200 sınırda) | Orta hızlarda (9600–38400) kararlı |
| İşlemci yükü | Çok az (donanım tamponu) | Yüksek, gönderirken kesmeler kapalı | Orta, Timer1 kullanır |
| Aynı anda gönderme ve alma | Evet | Hayır | Evet |
| Birden fazla port | Mega'da 4 adet | Aynı anda yalnız biri dinler | Tek port |
| Çakışmalar | Kod yükleme ve Seri Monitör | Servo, NeoPixel gibi zamanlamaya duyarlı kütüphaneler | D10 PWM ve Servo (Timer1) |
5V–3,3V seviye uyumu
UART'ta "HIGH" seviyesi kartın çalışma gerilimidir: Arduino Uno'da 5 V, ESP32, Raspberry Pi Pico, ESP-01 ve çoğu yeni modülde 3,3 V. 5 V'luk bir TX çıkışını 3,3 V'luk bir RX girişine doğrudan bağlamak, girişi aşırı gerilime maruz bırakır ve zamanla ya da anında pine zarar verir; ESP32 ve RP2040 tabanlı Pico'nun pinleri 5 V'a dayanıklı değildir. Ters yön genellikle sorun değildir: Uno, 3,0 V ve üstünü HIGH kabul ettiği için 3,3 V'luk bir TX'i okuyabilir, ama bu sınıra yakın olduğundan uzun kablolarda bir seviye dönüştürücü daha sağlamdır.
| Bağlantı | Ne gerekir? | Örnek |
|---|---|---|
| Uno TX (5 V) → ESP32 / Pico RX (3,3 V) | Gerilim bölücü ya da seviye dönüştürücü | 1 kΩ seri + 2 kΩ GND'ye: 5 × 2/3 ≈ 3,3 V |
| ESP32 / Pico TX (3,3 V) → Uno RX (5 V) | Genellikle doğrudan | Uno 3,0 V üstünü HIGH sayar |
| Uno TX → HC-05 RX | Gerilim bölücü önerilir | HC-05 RX'i 3,3 V seviyesindedir |
| Uno TX → SIM800L RX | Gerilim bölücü | SIM800L sinyal seviyesi 2,8 V civarıdır |
| İki kartın her ikisi de 5 V ya da 3,3 V | Doğrudan | Uno ↔ Nano, ESP32 ↔ Pico |
ESP32 UART: Serial, Serial1 ve Serial2
ESP32'de üç donanım UART'ı vardır ve en güzel tarafı, GPIO matrisi sayesinde UART pinlerinin neredeyse istediğin herhangi bir pine taşınabilmesidir. UART0 (Serial) USB-seri yongaya bağlıdır ve Seri Monitör için kullanılır. UART2 (Serial2) varsayılan olarak GPIO 16 (RX) ve 17 (TX) pinlerindedir. UART1'in eski varsayılan pinleri (GPIO 9 ve 10) ise kartın flaş belleğine bağlı olduğu için doğrudan kullanılamaz; Serial1'i her zaman begin(baud, SERIAL_8N1, RX, TX) şeklinde pin vererek başlatmalısın. Aşağıdaki kod, Seri Monitör ile UART2'ye bağlı bir cihaz (GPS, başka bir Arduino, bir sensör) arasında iki yönlü köprü kurar; GPS'in NMEA cümlelerini görmek için idealdir.
| UART | Arduino adı | Varsayılan RX / TX | Not |
|---|---|---|---|
| UART0 | Serial | GPIO 3 / GPIO 1 | USB-seri yongaya bağlı, kod yükleme ve Seri Monitör |
| UART1 | Serial1 | GPIO 9 / GPIO 10 (flaş, kullanma) | begin() içinde başka pin ver, ör. 25 / 26 |
| UART2 | Serial2 | GPIO 16 / GPIO 17 | WROVER kartlarında 16/17 PSRAM'e ayrılmıştır, başka pin seç |
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}
17ESP32'nin UART'ları 5 Mbaud'a kadar çıkabilir ve her birinin donanım tamponu vardır; varsayılan alım tamponu 256 bayttır ve Serial2.setRxBufferSize(1024) gibi bir çağrıyla begin()'den önce büyütülebilir. Bu, saniyede onlarca cümle gönderen GPS modülleri ya da uzun cevaplar veren GSM modülleri için önemlidir. ESP32'nin pinleri 3,3 V olduğu için 5 V'luk bir Arduino ile bağlarken bir önceki bölümdeki bölücüyü unutma. ESP32'nin pin dizilimini Pinout aracında görebilirsin.
Raspberry Pi Pico UART pinleri ve MicroPython
Raspberry Pi Pico'da iki donanım UART'ı (uart0 ve uart1) vardır ve her biri birkaç farklı pin çiftine yönlendirilebilir. MicroPython'da REPL ve print() çıktıları USB üzerinden ayrı bir sanal seri porttan geldiği için UART0 tamamen serbesttir; Arduino'daki gibi kod yüklerken kablo çıkarmak gerekmez. Pico'nun pinleri 3,3 V'tur ve RP2040'lı Pico'da 5 V'a dayanıklı değildir. Aşağıdaki kod, Arduino'daki B kartının yaptığı işi Pico'da yapar: UART0'dan gelen satırları okur, "LED ON" ve "LED OFF" komutlarına göre dahili LED'i yakar ve cevap verir. Uno'daki köprü koduyla konuşturmak istersen Uno'nun TX hattına gerilim bölücü koymayı unutma.
| UART | TX pinleri | RX pinleri | MicroPython örneği |
|---|---|---|---|
| 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)
28Veri paketleme: başlangıç ve bitiş karakteri
UART bir bayt akışıdır; nerede başlayıp nerede bittiğini bilmez. Gönderici "23.5,48,812" yazdığında alıcı bunun ortasından dinlemeye başlamış olabilir, bir bayt gürültü yüzünden kaybolmuş olabilir ya da iki ölçüm arka arkaya birleşebilir. Çözüm, veriyi bir paket hâline getirmektir: her paketi "<" ile başlatıp ">" ile bitirirsen alıcı ilk "<" karakterine kadar her şeyi yok sayar, ">" gelince paketi işler, araya giren yarım paketleri de atar. Göndericide yapman gereken tek şey değerleri Serial.print('<'), virgüller ve Serial.print('>') arasında yazmaktır. Aşağıdaki alıcı kodunu Seri Monitör'e <23.5,48,812> yazarak hemen deneyebilirsin.
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| Yöntem | Örnek | Artısı | Eksisi |
|---|---|---|---|
| Satır sonu ile metin | 512\n | En basit, Seri Monitör'de okunur | Yarım satırda başı bilinmez |
| Başlangıç-bitiş karakteri | <23.5,48,812> | Senkron kaybından kendini toparlar | Veri içinde < ve > kullanılamaz |
| Sağlama toplamlı metin (NMEA gibi) | $GPGGA,...*47 | Bozulan paket fark edilir | Hesaplama ve kod biraz uzar |
| İkili (binary) paket | 0xAA, uzunluk, veri, CRC | En kısa ve hızlı | Okuması ve hata ayıklaması zor |
Parazitli ortamlarda ya da uzun kablolarda bir adım daha ileri gidip pakete bir sağlama toplamı (checksum) ekleyebilirsin. GPS modüllerinin kullandığı NMEA biçimi buna güzel bir örnektir: "$" ile "*" arasındaki tüm karakterlerin XOR'u alınır ve iki haneli onaltılık sayı olarak sona yazılır. Alıcı aynı hesabı yapar, sonuç tutmazsa paketi atar. Böylece bozulmuş bir "812" değerinin "872" olarak işlenmesi gibi sinsi hataların önüne geçersin.
UART ile proje fikirleri
- Telefonla kontrol: HC-05 Bluetooth modülü aslında kablosuz bir UART'tır; HC-05 ile telefondan LED, röle ya da robot araba kontrol et.
- GPS konum kaydı: NEO-6M GPS modülünün UART'tan gönderdiği NMEA cümlelerini çözümleyip konumu SD karta yaz.
- İki kartlı sistem: Sensörleri okuyan bir Uno'yu, Wi-Fi ile veriyi internete gönderen bir ESP32'ye UART ile bağla.
- SMS alarmı: SIM800L modülüne AT komutlarını UART ile gönderip kapı açıldığında SMS at.
- Bilgisayardan kontrol paneli: Python ile yazılmış bir masaüstü uygulamasından Arduino'ya komut gönder ve sensör verilerini grafikle.
- MP3 çalar: DFPlayer Mini ile UART üzerinden şarkı seç, ses ayarla ve sesli uyarılar çal.
Sık yapılan hatalar ve çözümleri
| Belirti | Olası neden | Çözüm |
|---|---|---|
| Seri Monitör'de anlamsız karakterler | Baud hızları farklı | Kodda ve Seri Monitör'de aynı baud'u seç |
| Hiç veri gelmiyor | TX-TX, RX-RX bağlanmış | Kabloları çapraz bağla: TX → RX, RX → TX |
| Rastgele bozuk karakterler | GND bağlı değil | İki kartın GND'sini birleştir |
| Kod yüklenmiyor (not in sync) | D0/D1'de modül takılı | Yüklerken kabloları çıkar ya da SoftwareSerial kullan |
| Komutlar tanınmıyor | Satır sonu \r\n ya da hiç yok | Seri Monitör'ü Newline yap, gelen metni trim() ile temizle |
| Uzun mesajların sonu kayboluyor | 64 baytlık tampon taştı | delay() kullanma, veriyi geldikçe oku, hızı düşür |
| ESP32 RX pini çalışmıyor ya da bozuldu | 5 V TX doğrudan bağlandı | Gerilim bölücü ya da seviye dönüştürücü ekle |
| SoftwareSerial 115200'de hatalı | Yazılım zamanlaması yetişmiyor | 57600 ya da altını kullan veya donanım UART'ına geç |
UART, elektronikte öğrenmen gereken ilk haberleşme yöntemidir: iki kablo, ortak bir GND ve aynı baud hızı yeterlidir; doğru kurulduğunda yıllarca sorunsuz çalışır. Çapraz bağlantıyı, seviye uyumunu ve paket yapmayı öğrendiğinde GPS'ten GSM'e kadar onlarca modülü rahatça kullanabilirsin. BlueGrays uygulamasında iki Arduino arasında tek ve çift yönlü haberleşme, Bluetooth ile telefondan LED yakma ve Bluetooth kontrollü araba projelerini adım adım devre şemaları ve kodlarıyla bulabilirsin.
Sıkça sorulan sorular
UART ne demek, ne işe yarar?
UART, Universal Asynchronous Receiver-Transmitter yani evrensel asenkron alıcı-verici demektir. İki cihazın saat hattı olmadan, yalnızca TX ve RX kablolarıyla ve önceden anlaştıkları bir baud hızıyla bayt bayt veri alışverişi yapmasını sağlar. Arduino'nun Seri Monitör'ü, GPS, Bluetooth ve GSM modülleri UART kullanır.
TX ve RX nasıl bağlanır?
Bir cihazın TX pini diğerinin RX pinine, RX pini de diğerinin TX pinine bağlanır; yani bağlantı çaprazdır. Ayrıca iki cihazın GND pinleri mutlaka birleştirilmelidir. TX'i TX'e bağlamak veri akışını tamamen engeller.
Baud rate nedir, hangisini seçmeliyim?
Baud hızı saniyede gönderilen bit sayısıdır ve iki tarafta aynı olmalıdır. Arduino ile modüllerde en yaygın değerler 9600 ve 115200'dür; 9600 çoğu GPS ve Bluetooth modülünün varsayılanıdır, 115200 ise ESP32 ve hızlı çıktılar için tercih edilir. Modülün belgesinde yazan varsayılan hızla başla.
UART ile seri port aynı şey mi?
Günlük kullanımda çoğu zaman aynı anlamda kullanılır. UART, veriyi seri hâle getiren donanım birimidir; seri port ise bilgisayardaki COM ya da /dev/tty bağlantısıdır. RS-232 ve RS-485 ise UART sinyallerini daha uzak mesafelere taşımak için farklı gerilim seviyeleri kullanan standartlardır.
Arduino'da birden fazla UART nasıl kullanılır?
Uno'da tek donanım UART'ı vardır ve USB ile paylaşılır; ek portlar için SoftwareSerial kullanılır, ancak aynı anda yalnızca biri dinleyebilir. Arduino Mega'da Serial1, Serial2 ve Serial3 olmak üzere üç ek donanım UART'ı, ESP32'de toplam üç, Raspberry Pi Pico'da iki donanım UART'ı vardır.
UART kablosu en fazla kaç metre olabilir?
3,3 V ve 5 V TTL seviyeli UART, düşük baud hızlarında birkaç metreye kadar güvenilir çalışır; hız arttıkça mesafe kısalır. Daha uzun mesafeler için RS-485 dönüştürücüleriyle (ör. MAX485) yüzlerce metreye, RS-232 ile de yaklaşık 15 metreye kadar çıkılabilir.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
2 Arduino Tek Yönlü Haberleşme
İki Arduino'yu tek bir kabloyla konuşturursun: birindeki butona basınca öbüründeki LED yanar, bir daha basınca söner. Gönderen kart butona basıldığını kısa bir mesajla bildirir, alan kart bu mesajı du

2 Arduino Çift Yönlü Haberleşme
İki Arduino kabloyla birbirine bağlanıp konuşur: birinin butonuna basınca öbürünün ışığı yanar, yeniden basınca söner. İki kartta da aynı program çalışır, yani ikisi de hem haber gönderir hem haber al

Bluetooth İle Telefondan Led Yakma
Telefonundan odadaki ışıkları açıp kapatmanın küçük bir provası. Bluetooth modülü telefondan gelen harfleri Arduino'ya iletir; bir harf kırmızı LED'i, başka bir harf yeşil LED'i yakar, aynı harflerin

L298N ile Bluetooth Kontrollü Araba
Telefonunu kumandaya çevirip kendi robot arabanı sür. Arduino, Bluetooth modülü üzerinden telefondaki bir kumanda uygulamasından gelen komutları alır ve motor sürücüyle tekerlekleri döndürür; araba il

Python Yazılımcı Klavyesi
Kod yazarken aynı kalıpları tekrar tekrar yazmaktan sıkıldıysan bu küçük klavye tam sana göre. Arduino Leonardo bilgisayara klavye gibi bağlanır; 4x4 tuş takımındaki her tuş koşul, döngü, ekrana yazdı

HC-SR04 Mesafe Ölçme (Serial Ekran)
Yarasalar karanlıkta yollarını nasıl buluyorsa HC-SR04 sensörü de öyle çalışır: duyamadığın bir ses gönderir, yankısını dinler ve önündeki cismin ne kadar uzakta olduğunu ölçer. Arduino bu mesafeyi sa

DHT11 İle Sıcaklık Ve Nem
Odan kaç derece, hava nemli mi, kuru mu? DHT11 sensörü sıcaklığı ve nemi ölçer, Arduino da bu değerleri iki satırlık LCD ekrana yazar ve birkaç saniyede bir yeniler. Sensöre bir şey olursa ekranda hat

ESP32 LDR Modülü ile Işık Şiddeti Okuma
LDR modülünün ham ADC değerini ve karanlık/aydınlık referanslarına göre hesaplanan göreli ışık yüzdesini Serial Monitor'da gerçek zamanlı izleme. Bu yüzde lux ölçümü değildir. Modülün kalibrasyon mantığını öğretir. Proje 10'un öncesinde yapılması ideal; çünkü eşik değerini belirlemek için kullanılır.
Diğer yazılar
BlueGrays uygulaması
Bu devreyi telefonunda adım adım kur
Devre şeması, kod ve parça listesi tek ekranda. 200'den fazla Arduino, ESP32 ve Pico projesi seni bekliyor.
Telefonunla tara
Kamerayı koda tut; telefonunun uygulama mağazası açılır.
ya da mağazada aç

