Temeller · 9 dk okuma

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.

CP2102 USB-TTL dönüştürücü
CP2102 USB-TTL dönüştürücü: bilgisayarın USB portunu TX, RX ve GND pinlerine sahip bir UART'a çevirir; Arduino Uno'daki USB yongası da aynı işi yapar.

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.

BitStartD0D1D2D3D4D5D6D7Stop
'A' harfi (0x41 = 0100 0001)0100000101
Hattın seviyesiLOWHIGHLOWLOWLOWLOWLOWHIGHLOWHIGH

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.

BaudBit süresiSaniyede en fazla bayt (8N1)Nerede kullanılır?
9600104,2 µs960NEO-6M GPS, HC-05 veri modu, DFPlayer Mini, Seri Monitör'ün klasik ayarı
1920052,1 µs1920Bazı sensörler ve eski modemler
3840026,0 µs3840HC-05 AT komut modu
5760017,4 µs5760Eski Arduino bootloader'ları, SoftwareSerial için üst sınır
1152008,68 µs11520ESP32 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.

ÖzellikUARTI2CSPI
Kablo sayısı2 (TX, RX) + GND2 (SDA, SCL) + GND4 (SCK, MOSI, MISO, CS) + GND
Saat hattıYok (asenkron)VarVar
Cihaz sayısı2 (noktadan noktaya)127'ye kadar, adresleCS pini kadar
Tipik hız9600–115200 baud100–400 kHz1–80 MHz
Aynı anda iki yönEvet (full duplex)HayırEvet
Tipik modüllerGPS, Bluetooth, GSM, ESP-01, parmak iziOLED, LCD, RTC, BME280SD 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 AKabloArduino BNot
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—GNDOrtak toprak, zorunlu
5Visteğe bağlı5VYalnız biri USB'den besleniyorsa
Arduino Uno ve Nano'da donanım UART'ı olan D0 (RX) ve D1 (TX) pinleri aynı zamanda USB yongasına bağlıdır. Bu pinlere bir modül bağlıyken kod yüklemeye çalışırsan yükleme "not in sync" hatasıyla başarısız olur ve Seri Monitör'de modülün verileri ile bilgisayarınkiler karışır. Ya yükleme sırasında D0/D1 kablolarını çıkar ya da bu yazıdaki örneklerde olduğu gibi SoftwareSerial ile başka pinler kullan.

İki Arduino'yu haberleştirmek: tek yönlü

Arduino Uno
Arduino Uno: tek donanım UART'ı (D0/D1) USB'ye ayrıldığı için iki Uno'yu SoftwareSerial ile D10/D11 üzerinden bağlamak en rahat yoldur.

İ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.

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

Alı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.

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

B 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.

ÖzellikDonanım UART (Serial)SoftwareSerialAltSoftSerial
Uno'da pinlerD0 (RX), D1 (TX), USB ile ortakNeredeyse her pin (RX için PCINT)Sabit: D8 (RX), D9 (TX)
Güvenilir en yüksek hız1–2 Mbaud57600 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 almaEvetHayırEvet
Birden fazla portMega'da 4 adetAynı anda yalnız biri dinlerTek port
ÇakışmalarKod yükleme ve Seri MonitörServo, NeoPixel gibi zamanlamaya duyarlı kütüphanelerD10 PWM ve Servo (Timer1)
Birden fazla UART modülü (ör. GPS + Bluetooth) kullanacaksan Uno yerine dört donanım UART'ı olan Arduino Mega'yı (Serial'a ek olarak Serial1–Serial3) ya da üç UART'lı ESP32'yi tercih et. Leonardo ve Pro Micro'da USB ayrı olduğu için D0/D1'deki Serial1 tamamen serbesttir.

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ğrudanUno 3,0 V üstünü HIGH sayar
Uno TX → HC-05 RXGerilim bölücü önerilirHC-05 RX'i 3,3 V seviyesindedir
Uno TX → SIM800L RXGerilim bölücüSIM800L sinyal seviyesi 2,8 V civarıdır
İki kartın her ikisi de 5 V ya da 3,3 VDoğrudanUno ↔ Nano, ESP32 ↔ Pico
Gerilim bölücü yalnızca tek yönlü ve düşük-orta hızlı sinyaller için uygundur (ör. 115200 baud'a kadar). İki yönlü ya da çok hızlı hatlarda BSS138 tabanlı çift yönlü bir lojik seviye dönüştürücü kullan. Bölücü dirençlerini gerilim bölücü hesaplayıcısıyla kendi değerlerine göre hesaplayabilirsin; seviye dönüştürücülerin ayrıntıları lojik seviye dönüştürücü yazısında.

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.

UARTArduino adıVarsayılan RX / TXNot
UART0SerialGPIO 3 / GPIO 1USB-seri yongaya bağlı, kod yükleme ve Seri Monitör
UART1Serial1GPIO 9 / GPIO 10 (flaş, kullanma)begin() içinde başka pin ver, ör. 25 / 26
UART2Serial2GPIO 16 / GPIO 17WROVER kartlarında 16/17 PSRAM'e ayrılmıştır, başka pin seç
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

ESP32'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.

UARTTX pinleriRX pinleriMicroPython örneği
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

Veri 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.

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
YöntemÖrnekArtısıEksisi
Satır sonu ile metin512\nEn basit, Seri Monitör'de okunurYarım satırda başı bilinmez
Başlangıç-bitiş karakteri<23.5,48,812>Senkron kaybından kendini toparlarVeri içinde < ve > kullanılamaz
Sağlama toplamlı metin (NMEA gibi)$GPGGA,...*47Bozulan paket fark edilirHesaplama ve kod biraz uzar
İkili (binary) paket0xAA, uzunluk, veri, CRCEn 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.

Göndericinin hızı alıcının işleme hızından fazla olmamalı. Arduino Uno'nun donanım alım tamponu yalnızca 64 bayttır; loop() içinde uzun delay() kullanırken gelen baytlar tampon dolunca kaybolur. Alıcıda delay() yerine millis() kullan ve Serial.available() kontrolünü döngünün her turunda yap.

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

BelirtiOlası nedenÇözüm
Seri Monitör'de anlamsız karakterlerBaud hızları farklıKodda ve Seri Monitör'de aynı baud'u seç
Hiç veri gelmiyorTX-TX, RX-RX bağlanmışKabloları çapraz bağla: TX → RX, RX → TX
Rastgele bozuk karakterlerGND 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ıyorSatır sonu \r\n ya da hiç yokSeri Monitör'ü Newline yap, gelen metni trim() ile temizle
Uzun mesajların sonu kayboluyor64 baytlık tampon taştıdelay() kullanma, veriyi geldikçe oku, hızı düşür
ESP32 RX pini çalışmıyor ya da bozuldu5 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şmiyor57600 ya da altını kullan veya donanım UART'ına geç
Bir UART modülü cevap vermiyorsa önce onu bir USB-TTL dönüştürücüyle doğrudan bilgisayara bağla ve bir seri terminalden komut gönder. Modül orada çalışıyorsa sorun Arduino kodunda ya da kablolamadadır; orada da çalışmıyorsa baud hızını, beslemeyi ve modülün kendisini kontrol et.

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.

Tüm projeleri gör
2 Arduino Tek Yönlü Haberleşme
#57Orta
Premium

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

4.4(37)
50
2 Arduino Çift Yönlü Haberleşme
#58Orta
Premium

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

4.5(20)
26
Bluetooth İle Telefondan Led Yakma
#34Başlangıç
Premium

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

4.8(68)
89
L298N ile Bluetooth Kontrollü Araba
#80İleri
Premium

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

5.0(38)
65
Python Yazılımcı Klavyesi
#66Orta
Premium

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ı

4.6(35)
45
HC-SR04 Mesafe Ölçme (Serial Ekran)
#27Başlangıç

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

4.6(46)
71
DHT11 İle Sıcaklık Ve Nem
#55Orta

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

4.7(47)
73
ESP32 LDR Modülü ile Işık Şiddeti Okuma
#113Başlangıç

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.

4.6(36)
55