SPI Nedir? MOSI, MISO, SCK, CS Pinleri ve Arduino SPI Rehberi
SPI nedir, nasıl çalışır? MOSI, MISO, SCK ve CS pinleri, SPI modları ve hızı, birden fazla cihaz, Uno, Mega, ESP32 ve Pico pinleri, SD kart ile RFID çakışması.
SPI (Serial Peripheral Interface, seri çevre birimi arayüzü), bir mikrodenetleyicinin SD kart, RFID okuyucu, renkli TFT ekran ya da kablosuz modül gibi cihazlarla dört kablo üzerinden çok hızlı veri alışverişi yapmasını sağlayan bir haberleşme yöntemidir. Bir saat (SCK) hattı, iki yönlü veri için iki ayrı hat (MOSI ve MISO) ve hangi cihazla konuşulduğunu seçen bir CS hattı vardır. I2C'den onlarca kat hızlı olabilmesi, onu büyük miktarda veri taşıyan modüllerin tercihi yapar.
Bu yazıda SPI'ın nasıl çalıştığını, pin adlarını ve yeni adlandırmayı, dört SPI modunu, hız sınırlarını, Arduino Uno, Mega, ESP32 (VSPI ve HSPI) ve Raspberry Pi Pico pinlerini, birden fazla cihazı aynı hatta bağlamayı ve SD kart ile RC522 RFID'nin birlikte neden sorun çıkardığını öğreneceksin. Son bölümde SPI'ı I2C ve UART ile karşılaştırıyoruz.
SPI nedir, nasıl çalışır?
SPI'da her zaman bir kontrolcü (controller, eski adıyla master) ve bir ya da daha fazla çevre birimi (peripheral, eski adıyla slave) bulunur. Saati yalnızca kontrolcü üretir; yani Arduino konuşmayı başlatır, hızını belirler ve bitirir. Her saat darbesinde kontrolcü MOSI hattından bir bit gönderirken, aynı anda çevre birimi de MISO hattından bir bit geri yollar. İki taraftaki kaydırmalı yazmaçlar sanki bir halka oluşturur: 8 saat darbesinden sonra kontrolcünün baytı çevre birimine, çevre biriminin baytı da kontrolcüye geçmiş olur. Bu yüzden SPI tam çift yönlüdür (full duplex): okuma ve yazma aynı anda yapılır.
| Hat | Eski adı | Yeni adı | Yön | Görevi |
|---|---|---|---|---|
| SCK / SCLK | Serial Clock | SCK | Kontrolcü → çevre birimi | Saat sinyali; her darbede bir bit taşınır |
| MOSI | Master Out Slave In | COPI / SDO | Kontrolcü → çevre birimi | Arduino'dan modüle giden veri |
| MISO | Master In Slave Out | CIPO / SDI | Çevre birimi → kontrolcü | Modülden Arduino'ya dönen veri |
| CS / SS | Slave Select | CS (Chip Select) | Kontrolcü → çevre birimi | LOW olduğunda o modül dinler; her cihaza ayrı bir CS |
Modüllerin üzerindeki yazılar her zaman aynı değildir ve bu, kafa karışıklığının en büyük kaynağıdır. RC522 RFID modülünde CS hattı SDA diye yazılır (I2C'deki SDA ile ilgisi yoktur), nRF24L01'de CSN, MCP3008'de CS/SHDN, bazı ekranlarda DIN (MOSI), CLK (SCK) ve DOUT (MISO) gibi adlar görürsün. Kural basittir: veri girişi (DIN, SDI, MOSI) Arduino'nun MOSI'sine, veri çıkışı (DOUT, SDO, MISO) Arduino'nun MISO'suna gider.
- Kontrolcü, konuşmak istediği cihazın CS hattını LOW yapar. Diğer tüm cihazların CS'si HIGH kalır ve MISO hattını serbest bırakırlar.
- Kontrolcü SCK hattında saat darbeleri üretmeye başlar.
- Her darbede MOSI'den bir bit çıkar, MISO'dan bir bit girer. Bit sırası genelde en anlamlı bit önce (MSB first) şeklindedir.
- Gereken bayt sayısı (komut, adres, veri) aktarıldıktan sonra kontrolcü CS'yi tekrar HIGH yapar ve cihaz işlemi tamamlar.
SPI modları: CPOL ve CPHA
SPI'ın tek bir standardı yoktur; cihazlar saatin boşta hangi seviyede durduğu (CPOL, clock polarity) ve verinin saatin hangi kenarında okunduğu (CPHA, clock phase) konusunda farklılık gösterir. Bu iki ayarın dört kombinasyonu dört SPI modunu oluşturur. Kontrolcü ile cihaz aynı modda değilse veri bir bit kayar ve anlamsız değerler okursun. Neyse ki modüllerin büyük çoğunluğu Mod 0 kullanır.
| Mod | CPOL | CPHA | Saat boştayken | Verinin okunduğu kenar | Örnek cihazlar |
|---|---|---|---|---|---|
| SPI_MODE0 | 0 | 0 | LOW | Yükselen | SD kart, RC522, nRF24L01, MAX7219, MCP3008, 74HC595 |
| SPI_MODE1 | 0 | 1 | LOW | Düşen | Bazı ADC ve sürücü entegreleri |
| SPI_MODE2 | 1 | 0 | HIGH | Düşen | Nadiren kullanılır |
| SPI_MODE3 | 1 | 1 | HIGH | Yükselen | ADXL345 ivmeölçer, CS pini olmayan bazı ST7789 ekranlar |
SPI hızı ve kablo uzunluğu
SPI'da hızı kontrolcü belirler ve sınır genelde cihazın kendisidir. Arduino Uno 16 MHz'lik saatinin yarısı olan 8 MHz'e kadar çıkabilir; SPI kütüphanesinin varsayılanı 4 MHz'tir. ESP32 kendi SPI pinlerinde (IO_MUX) 80 MHz'e kadar saat üretebilir, sinyal GPIO matrisi üzerinden başka pinlere yönlendirildiğinde bu sınır düşer. Raspberry Pi Pico ise 125 MHz sistem saatinde yaklaşık 62,5 MHz'e kadar çıkabilir. Hızlı SPI sinyalleri kısa kablolar ister: breadboard ve 10–20 cm'lik jumper kablolarla birkaç MHz sorunsuzdur; 20–30 MHz ve üzerinde kabloları kısa tut, mümkünse lehimli bağlantı kullan. Metrelerce uzunluk SPI'a uygun değildir.
| Cihaz | Görevi | En yüksek SPI saati (veri sayfası) | SPI modu |
|---|---|---|---|
| MicroSD kart | Veri kaydı | Başlangıçta 400 kHz, sonra 25 MHz'e kadar | Mod 0 |
| RC522 (MFRC522) | RFID okuyucu | 10 MHz | Mod 0 |
| nRF24L01 | 2,4 GHz kablosuz | 10 MHz | Mod 0 |
| MAX7219 | LED matris / 7 segment | 10 MHz | Mod 0 |
| MCP3008 | 8 kanal 10 bit ADC | 5 V'ta 3,6 MHz, 2,7 V'ta 1,35 MHz | Mod 0 ya da 3 |
| ILI9341 | 2,4–3,2 inç renkli TFT | Yazmada 10 MHz (pratikte çok daha hızlı sürülür) | Mod 0 |
SPI pinleri: Arduino Uno, Mega, ESP32 ve Raspberry Pi Pico
| Hat | Arduino Uno / Nano | Arduino Mega | ESP32 VSPI (varsayılan) | ESP32 HSPI | Raspberry Pi Pico SPI0 |
|---|---|---|---|---|---|
| SCK | D13 | D52 | GPIO 18 | GPIO 14 | GP18 |
| MOSI | D11 | D51 | GPIO 23 | GPIO 13 | GP19 (TX) |
| MISO | D12 | D50 | GPIO 19 | GPIO 12 | GP16 (RX) |
| CS (varsayılan) | D10 | D53 | GPIO 5 | GPIO 15 | GP17 |
| Mantık seviyesi | 5 V | 5 V | 3,3 V | 3,3 V | 3,3 V |
Uno'da aynı SPI hatları kartın ucundaki 6 pinli ICSP başlığında da bulunur; Leonardo ve Micro gibi kartlarda SPI yalnızca ICSP'den alınır. CS için D10 zorunlu değildir, istediğin dijital pini kullanabilirsin. Ancak Uno'da D10'u giriş olarak bırakma: SPI donanımı, D10 giriş durumundayken LOW okursa kendini kontrolcü modundan çıkarır. SPI.begin() bu pini otomatik olarak çıkış yapar; sen de onu başka bir iş için giriş yapmamalısın. ESP32'de Arduino'nun SPI nesnesi varsayılan olarak VSPI'yi kullanır; GPIO matrisi sayesinde SPI'ı neredeyse istediğin pinlere de taşıyabilirsin. Pico'da SPI0 ve SPI1 birkaç farklı pin grubuna atanabilir (ör. SPI1 için GP10, GP11, GP12); ayrıntılar için Pinout aracına bakabilirsin.
Arduino SPI kütüphanesi: temel fonksiyonlar
| Fonksiyon | Ne yapar? |
|---|---|
| SPI.begin() | SPI donanımını başlatır; SCK, MOSI ve SS pinlerini çıkış yapar. |
| SPISettings(hız, MSBFIRST, SPI_MODE0) | Bir cihazın hızını, bit sırasını ve modunu tek nesnede tutar. |
| SPI.beginTransaction(ayarlar) | Ayarları uygular ve hattı bu cihaz için ayırır; farklı ayarlı cihazlar arasında geçişi güvenli yapar. |
| SPI.transfer(bayt) | Bir bayt gönderir ve aynı anda gelen baytı döndürür. |
| SPI.transfer16(değer) | 16 bitlik bir değeri tek seferde gönderip alır. |
| SPI.transfer(tampon, uzunluk) | Bir diziyi gönderir; gelen baytlar aynı dizinin üzerine yazılır. |
| SPI.endTransaction() | Hattı serbest bırakır; CS'yi HIGH yaptıktan sonra çağrılır. |
İlk örnek: SPI ile 74HC595'e veri göndermek
SPI'ı anlamanın en kolay yolu bir 74HC595 kaydırmalı yazmaç kullanmaktır; çünkü 595 aslında MISO'su olmayan, en basit SPI çevre birimidir. Arduino'nun MOSI pini 595'in DS girişine, SCK pini SH_CP'ye, D10 ise mandal (latch) görevi gören ST_CP'ye bağlanır. shiftOut() fonksiyonundan farklı olarak donanım SPI'ı baytı birkaç mikrosaniyede gönderir:
1// Donanım SPI ile 74HC595: 8 LED'i iki kabloyla sürmek / 74HC595 over hardware SPI: 8 LEDs from two data wires
2// D11 (MOSI) -> DS (14), D13 (SCK) -> SH_CP (11), D10 -> ST_CP / latch (12)
3#include <SPI.h>
4
5const int LATCH_PIN = 10; // 595'te CS gibi davranır / acts like CS on the 595
6
7void write595(byte value) {
8 SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); // 4 MHz, mod 0 / 4 MHz, mode 0
9 digitalWrite(LATCH_PIN, LOW);
10 SPI.transfer(value); // 8 biti gönder / shift out 8 bits
11 digitalWrite(LATCH_PIN, HIGH); // yükselen kenarda çıkışlara aktar / latch on the rising edge
12 SPI.endTransaction();
13}
14
15void setup() {
16 pinMode(LATCH_PIN, OUTPUT);
17 digitalWrite(LATCH_PIN, HIGH);
18 SPI.begin();
19}
20
21void loop() {
22 for (int i = 0; i < 8; i++) { // yürüyen ışık / running light
23 write595(1 << i);
24 delay(100);
25 }
26}SPI ile veri okumak: MCP3008 ADC
Tam çift yönlü haberleşmeyi görmek için MCP3008'i kullanalım. Bu entegre Arduino'ya 8 tane 10 bitlik analog giriş daha ekler; ESP32'nin doğrusal olmayan ADC'sine ya da Pico'nun yalnızca 3 analog girişine iyi bir alternatiftir. Analog okuma temellerini ADC nedir? yazısında anlattık. Bağlantı: CLK → D13, DOUT → D12, DIN → D11, CS → D10, VDD ve VREF → 5V, AGND ve DGND → GND.
1// MCP3008 (8 kanal, 10 bit ADC) okuma / Reading an MCP3008 (8-channel 10-bit ADC)
2// D13 -> CLK, D12 <- DOUT, D11 -> DIN, D10 -> CS/SHDN
3#include <SPI.h>
4
5const int CS_PIN = 10;
6SPISettings mcpSettings(1000000, MSBFIRST, SPI_MODE0); // 1 MHz, mod 0 / 1 MHz, mode 0
7
8int readMCP3008(byte channel) {
9 SPI.beginTransaction(mcpSettings);
10 digitalWrite(CS_PIN, LOW); // cihazı seç / select the chip
11 SPI.transfer(0x01); // başlangıç biti / start bit
12 byte high = SPI.transfer(0x80 | (channel << 4)); // tek uçlu + kanal / single-ended + channel
13 byte low = SPI.transfer(0x00); // kalan 8 bit / remaining 8 bits
14 digitalWrite(CS_PIN, HIGH); // seçimi bırak / release the chip
15 SPI.endTransaction();
16 return ((high & 0x03) << 8) | low; // 10 bitlik sonuç / 10-bit result
17}
18
19void setup() {
20 Serial.begin(9600);
21 pinMode(CS_PIN, OUTPUT);
22 digitalWrite(CS_PIN, HIGH); // başta seçili değil / not selected at start
23 SPI.begin();
24}
25
26void loop() {
27 int raw = readMCP3008(0);
28 float volts = raw * 5.0 / 1023.0;
29 Serial.print("CH0: ");
30 Serial.print(raw);
31 Serial.print(" ");
32 Serial.print(volts, 2);
33 Serial.println(" V");
34 delay(500);
35}Burada üç bayt gönderiyoruz ve aynı anda üç bayt alıyoruz. İlk bayt (0x01) yalnızca başlangıç bitidir; ikinci baytta tek uçlu ölçüm ve kanal numarası gider, bu sırada MCP3008 sonucun en üst 2 bitini geri yollar. Üçüncü bayt 0x00'dır; içeriği önemsizdir, yalnızca saat üretip sonucun kalan 8 bitini almak için gönderilir. SPI'da "okumak" her zaman bir şey göndermek demektir. Sonuç 0–1023 arasındadır ve VREF'e (burada 5 V) göre volta çevrilir.
Birden fazla SPI cihazı: ayrı CS hatları
SPI'ın I2C'den en büyük farkı adres kullanmamasıdır. Cihazlar SCK, MOSI ve MISO hatlarını ortak kullanır; her birine Arduino'dan ayrı bir CS kablosu çekilir. Hangi cihazın CS'si LOW ise yalnızca o dinler ve yalnızca o MISO'ya veri yazar. Üç cihaz için 3 + 3 = 6 kablo, beş cihaz için 3 + 5 = 8 kablo gerekir; pin sayısı cihaz sayısıyla artar. 74HC595 ve MAX7219 gibi bazı entegreler ise zincirleme (daisy chain) bağlanabilir: birinin çıkışı diğerinin girişine gider ve hepsi tek CS ile sürülür.
- Aynı anda yalnızca bir CS LOW olsun. İki cihaz birlikte seçilirse MISO hattında çakışırlar ve ikisinden de bozuk veri okursun.
- setup()'ta önce tüm CS pinlerini çıkış yapıp HIGH'a çek, sonra kütüphaneleri başlat. Boşta kalan bir CS pini rastgele LOW görünüp hattı meşgul edebilir.
- Her cihaz için beginTransaction kullan. SD kart 25 MHz, MCP3008 1 MHz isteyebilir; transaction'lar her geçişte doğru hızı ve modu otomatik uygular.
- Kesmelerde SPI kullanıyorsan SPI.usingInterrupt() ile kütüphaneye bildir ya da kesme içinde SPI işlemi yapma.
- Her cihazın CS hattına 10 kΩ pull-up eklemek, Arduino açılırken ya da yeniden başlarken cihazların kendiliğinden seçilmesini engeller.
SD kart ve RFID aynı hatta: neden çalışmıyor?
Arduino forumlarının klasik sorusu: RC522 RFID tek başına çalışıyor, SD kart modülü tek başına çalışıyor, ikisi aynı SPI hattına bağlanınca biri ya da ikisi birden susuyor. Yazılımda CS pinleri doğru olsa bile sorun çoğu zaman donanımdadır. Ucuz SD kart modüllerinin birçoğunda 5 V sinyalleri 3,3 V'a çeviren bir 74LVC125 tampon entegresi bulunur ve bu entegrenin MISO hattını süren kanalı her zaman etkindir. Yani SD kartın CS'si HIGH olsa bile modül MISO hattını bırakmaz; RC522 cevap vermeye çalıştığında hat iki çıkış arasında çekişir.
- Doğru modülü seç: MISO'yu CS HIGH olduğunda yüksek empedansa alan modüller sorunsuz paylaşılır. Bir modülün hattı bırakıp bırakmadığını, CS HIGH iken MISO'yu 10 kΩ ile önce GND'ye sonra 5 V'a çekip multimetreyle ölçerek anlayabilirsin.
- Tamponun etkinleştirme ucunu CS'ye bağla: Lehim deneyimin varsa 74LVC125'in MISO kanalının OE ucunu GND'den ayırıp modülün CS hattına bağlamak sorunu kökten çözer.
- MISO'ya seri direnç ekle: SD modülünün MISO çıkışına 1 kΩ civarında seri direnç koymak, RC522'nin hattı yenmesini sağlar. Kolay ama hız sınırlayan geçici bir çözümdür.
- Ayrı SPI hattı kullan: ESP32'de SD kartı VSPI'ye, RC522'yi HSPI'ye bağlarsan iki cihaz hiç karşılaşmaz. Uno'da ikinci donanım SPI'ı olmadığı için bu seçenek yoktur.
- Başlatma sırasına dikkat et: Önce tüm CS'leri HIGH yap, sonra SPI.begin(), ardından SD.begin() ve PCD_Init() çağır. Aşağıdaki örnek bu sırayı izler.
1// Aynı SPI hattında SD kart ve RC522 RFID / SD card and RC522 RFID on the same SPI bus
2// Ortak / shared: D11 MOSI, D12 MISO, D13 SCK. CS: SD -> D4, RC522 SDA(SS) -> D10, RC522 RST -> D9
3#include <SPI.h>
4#include <SD.h>
5#include <MFRC522.h>
6
7const int SD_CS = 4;
8const int RFID_CS = 10;
9const int RFID_RST = 9;
10
11MFRC522 rfid(RFID_CS, RFID_RST);
12
13void setup() {
14 Serial.begin(9600);
15 // Önce TÜM CS pinlerini HIGH yap: hiçbir cihaz hattı meşgul etmesin
16 // First drive ALL CS pins HIGH so no device grabs the bus
17 pinMode(SD_CS, OUTPUT);
18 digitalWrite(SD_CS, HIGH);
19 pinMode(RFID_CS, OUTPUT);
20 digitalWrite(RFID_CS, HIGH);
21
22 SPI.begin();
23 if (!SD.begin(SD_CS)) {
24 Serial.println(F("SD bulunamadi / SD not found"));
25 }
26 rfid.PCD_Init();
27 Serial.println(F("Karti okut / Scan a card"));
28}
29
30void loop() {
31 if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;
32
33 String uid = "";
34 for (byte i = 0; i < rfid.uid.size; i++) {
35 if (rfid.uid.uidByte[i] < 0x10) uid += "0";
36 uid += String(rfid.uid.uidByte[i], HEX);
37 }
38 rfid.PICC_HaltA();
39
40 File f = SD.open("kartlar.txt", FILE_WRITE); // kütüphane CS'yi kendisi yönetir / the library handles CS itself
41 if (f) {
42 f.print(millis());
43 f.print(";");
44 f.println(uid);
45 f.close();
46 Serial.println("Kaydedildi / Saved: " + uid);
47 } else {
48 Serial.println(F("Dosya acilamadi / File open failed"));
49 }
50}Bu kodda SD kütüphanesi ve MFRC522 kütüphanesi kendi CS pinlerini kendileri LOW ve HIGH yapar; senin yapman gereken yalnızca başlangıçta ikisini de HIGH bırakmak ve donanımın MISO'yu doğru paylaştığından emin olmaktır. Kod, okutulan her kartın UID'sini zaman bilgisiyle birlikte kartlar.txt dosyasına yazar. Uno'da bu iki kütüphane birlikte RAM'in yaklaşık yarısını kullanır; F() makrosu sabit metinleri flash'ta tutarak yer açar.
ESP32'de VSPI ve HSPI: iki ayrı SPI hattı
ESP32'nin içinde dört SPI birimi vardır; SPI0 ve SPI1 dahili flash belleğe ayrılmıştır, kullanıcıya VSPI (SPI3) ve HSPI (SPI2) kalır. İkisini birden kullanmak, hızları ve modları çok farklı cihazları ayırmanın ya da yukarıdaki MISO çakışmasından kurtulmanın en temiz yoludur. Arduino çekirdeğinde ikinci hat için bir SPIClass nesnesi oluşturur ve begin() ile pinlerini verirsin. Aşağıdaki kod SD kartı varsayılan VSPI'de, MCP3008'i HSPI'de çalıştırır ve her saniye ölçümü bir CSV dosyasına ekler:
1// ESP32: iki ayrı SPI hattı / two separate SPI buses
2// VSPI (varsayılan SPI / default SPI): SD kart / SD card -> SCK 18, MISO 19, MOSI 23, CS 5
3// HSPI: MCP3008 -> SCK 14, MISO 12, MOSI 13, CS 15
4#include <SPI.h>
5#include <SD.h>
6
7const int SD_CS = 5;
8const int ADC_CS = 15;
9
10SPIClass hspi(HSPI); // ikinci donanım SPI / second hardware SPI
11SPISettings mcpSettings(1000000, MSBFIRST, SPI_MODE0);
12
13int readMCP3008(byte channel) {
14 hspi.beginTransaction(mcpSettings);
15 digitalWrite(ADC_CS, LOW);
16 hspi.transfer(0x01);
17 byte high = hspi.transfer(0x80 | (channel << 4));
18 byte low = hspi.transfer(0x00);
19 digitalWrite(ADC_CS, HIGH);
20 hspi.endTransaction();
21 return ((high & 0x03) << 8) | low;
22}
23
24void setup() {
25 Serial.begin(115200);
26 pinMode(ADC_CS, OUTPUT);
27 digitalWrite(ADC_CS, HIGH);
28 hspi.begin(14, 12, 13, ADC_CS); // SCK, MISO, MOSI, SS
29
30 if (!SD.begin(SD_CS)) { // SD varsayılan VSPI'yi kullanır / SD uses the default VSPI
31 Serial.println("SD bulunamadi / SD not found");
32 }
33}
34
35void loop() {
36 int raw = readMCP3008(0);
37 File f = SD.open("/olcum.csv", FILE_APPEND); // ekle kipinde aç / open in append mode
38 if (f) {
39 f.printf("%lu,%d\n", millis(), raw);
40 f.close();
41 }
42 Serial.printf("CH0: %d\n", raw);
43 delay(1000);
44}Raspberry Pi Pico ile SPI (MicroPython)
Pico'da iki donanım SPI birimi (SPI0 ve SPI1) vardır ve MicroPython'da machine.SPI sınıfıyla kullanılır. polarity ve phase parametreleri CPOL ve CPHA'ya karşılık gelir; ikisi de 0 ise Mod 0'dır. CS'yi sıradan bir çıkış pini olarak kendin yönetirsin. write_readinto() fonksiyonu SPI'ın tam çift yönlü yapısını en iyi gösteren fonksiyondur: bir diziyi gönderirken gelen baytları başka bir diziye yazar. Aynı MCP3008'i bu kez 3,3 V ile besleyip okuyalım:
1# Raspberry Pi Pico: SPI0 ile MCP3008 okuma / reading an MCP3008 on SPI0
2# GP18 -> CLK, GP19 -> DIN (MOSI), GP16 <- DOUT (MISO), GP17 -> CS. MCP3008 VDD ve VREF 3V3 / VDD and VREF on 3V3
3from machine import Pin, SPI
4import time
5
6spi = SPI(0, baudrate=1_000_000, polarity=0, phase=0, # mod 0 / mode 0
7 sck=Pin(18), mosi=Pin(19), miso=Pin(16))
8cs = Pin(17, Pin.OUT, value=1) # başta seçili değil / not selected at start
9
10def read_mcp3008(channel):
11 tx = bytearray([0x01, 0x80 | (channel << 4), 0x00])
12 rx = bytearray(3)
13 cs.value(0) # cihazı seç / select the chip
14 spi.write_readinto(tx, rx) # aynı anda gönder ve al / send and receive at once
15 cs.value(1)
16 return ((rx[1] & 0x03) << 8) | rx[2]
17
18while True:
19 raw = read_mcp3008(0)
20 print("CH0:", raw, "{:.2f} V".format(raw * 3.3 / 1023))
21 time.sleep(0.5)SPI, I2C ve UART karşılaştırması
| Özellik | SPI | I2C | UART |
|---|---|---|---|
| Kablo sayısı | 4 (+ her ek cihaz için 1 CS) | 2 (SDA, SCL) | 2 (TX, RX) |
| Tipik hız | 1–80 MHz | 100 kHz, 400 kHz, 1 MHz | 9600–115200 baud (birkaç Mbit/s'e kadar) |
| Saat | Var (kontrolcü üretir) | Var (kontrolcü üretir) | Yok; iki taraf aynı baud hızında anlaşır |
| Yön | Tam çift yönlü | Yarım çift yönlü | Tam çift yönlü |
| Cihaz seçimi | Ayrı CS kablosu | 7 bitlik adres | Yalnızca iki cihaz (noktadan noktaya) |
| Ek parça | Gerekmez | Pull-up dirençleri | Gerekmez |
| Mesafe | Kısa (kart üzeri, birkaç on cm) | Kısa (1 m civarı) | Birkaç metre; RS-485 ile çok daha uzun |
| Tipik modüller | SD kart, RC522, TFT, nRF24L01, MAX7219 | OLED, LCD I2C modülü, RTC, BME280, MPU6050 | GPS, HC-05, SIM800L, ESP-01, bilgisayar |
Seçim çoğu zaman modül tarafından yapılır ama kendi tasarımında şu kural işe yarar: hız ve veri miktarı önemliyse (ekran görüntüsü, dosya, ses) SPI; az kablo ve çok sayıda yavaş sensör gerekiyorsa I2C; iki cihaz arasında metin tabanlı, basit bir bağlantı istiyorsan UART kullan. UART'ın ayrıntılarını UART seri haberleşme yazısında bulabilirsin. Aynı projede üçünün birden kullanılması da çok yaygındır: örneğin I2C ile sensör okuyup SPI ile SD karta yazan ve UART ile GPS'ten konum alan bir veri kaydedici.
SPI kullanan modüller ve proje fikirleri
- Kartlı kapı kilidi ve giriş kaydı: RC522 ile kartı oku, SD karta tarih ve UID yaz.
- Sıcaklık kaydedici: Sensör verilerini microSD karta CSV olarak kaydet ve Excel'de grafik çiz.
- Kayan yazı panosu: Zincirlenmiş MAX7219 LED matris modülleriyle saat ve mesaj göster.
- Renkli arayüz: ILI9341 TFT ekranda grafik ve menü çiz; dokunmatik paneli de aynı SPI hattına bağla.
- Kablosuz kumanda: İki nRF24L01 modülüyle robot arabana uzaktan komut gönder.
- Çok kanallı ölçüm: MCP3008 ile 8 potansiyometreli bir MIDI kontrolcü ya da 8 toprak nem sensörlü bir sulama sistemi kur.
Sık yapılan hatalar ve çözümleri
| Belirti | Olası sebep | Çözüm |
|---|---|---|
| Hep 0xFF ya da 0x00 okunuyor | MISO bağlı değil, MOSI ile MISO yer değiştirmiş ya da cihazın beslemesi yok | DIN'i MOSI'ye, DOUT'u MISO'ya bağla; cihazın VCC'sini ölç |
| Değerler anlamsız ya da bir bit kaymış | Yanlış SPI modu ya da cihaz için fazla yüksek saat hızı | Veri sayfasındaki modu kullan, hızı 1 MHz'e düşürüp tekrar dene |
| Tek başına çalışan iki cihaz birlikte çalışmıyor | Bir modül MISO'yu bırakmıyor ya da CS pinleri başta HIGH değil | Tüm CS'leri önce HIGH yap; MISO'yu bırakmayan modülü değiştir ya da ayrı SPI hattı kullan |
| Uno'da SPI bir anda duruyor | D10 giriş olarak kullanılmış ve LOW'a çekilmiş | D10'u çıkış olarak bırak; CS için de kullanabilirsin |
| ESP32 HSPI bağlıyken açılmıyor | GPIO 12 açılışta HIGH kalıyor | Pull-up'lı MISO'yu VSPI'ye taşı ya da MISO için başka bir pin seç |
| Uzun kabloda rastgele hatalar | Hızlı sinyalde yansıma ve parazit | Kabloları kısalt, hızı düşür, GND kablosunu sinyallerin yanından götür |
SPI, SD kartlardan renkli ekranlara kadar Arduino dünyasının hızlı modüllerinin ortak dilidir: dört kabloyu, CS mantığını ve dört modu öğrendiğinde yeni bir SPI modülünü bağlamak birkaç dakikalık iş olur. BlueGrays uygulamasında RFID kart okuma ve kapı kilidi, microSD sıcaklık kaydedici ve MAX7219 dot matris saat projelerini devre şemaları ve kodlarıyla adım adım bulabilirsin.
Sıkça sorulan sorular
SPI ne demek?
SPI, Serial Peripheral Interface (seri çevre birimi arayüzü) kelimelerinin kısaltmasıdır. Bir kontrolcünün SCK, MOSI, MISO ve CS olmak üzere dört hat üzerinden çevre birimleriyle hızlı ve senkron veri alışverişi yapmasını sağlar.
MOSI ve MISO nedir?
MOSI (Master Out Slave In), kontrolcüden çevre birimine giden veri hattıdır; MISO (Master In Slave Out) ise çevre biriminden kontrolcüye dönen veri hattıdır. Yeni adlandırmada bunlar COPI ve CIPO olarak da geçer. Modüllerde DIN genelde MOSI'ye, DOUT ise MISO'ya bağlanır.
Arduino Uno'da SPI pinleri hangileri?
Arduino Uno ve Nano'da SCK D13, MISO D12, MOSI D11 ve varsayılan CS D10'dur. Aynı hatlar kartın üzerindeki 6 pinli ICSP başlığında da bulunur. Arduino Mega'da ise SCK D52, MISO D50, MOSI D51 ve CS D53'tür.
SPI ile I2C arasındaki fark nedir?
SPI dört kablo kullanır, tam çift yönlüdür ve onlarca MHz hıza çıkabilir; her cihaz için ayrı bir CS kablosu gerekir. I2C yalnızca iki kablo kullanır ve cihazları adresle seçer, ama 100–400 kHz gibi çok daha düşük hızlarda çalışır ve pull-up direnci ister.
Bir SPI hattına kaç cihaz bağlanabilir?
Teorik bir sınır yoktur; her cihaz için kontrolcüde boş bir CS pini olması yeterlidir. Pratikte hat kapasitesi ve kablo uzunluğu arttıkça yüksek hızlarda sorun çıkar. Pin yetmezse CS hatlarını bir 74HC138 kod çözücüyle çoğaltabilir ya da zincirlenebilen cihazlar kullanabilirsin.
SD kart ve RFID neden aynı SPI hattında çalışmıyor?
Birçok ucuz SD kart modülündeki seviye dönüştürücü, CS HIGH olsa bile MISO hattını bırakmaz ve RC522'nin cevabını bozar. MISO'yu doğru bırakan bir modül kullanmak, tampon entegrenin etkinleştirme ucunu CS'ye bağlamak ya da ESP32'de iki cihazı ayrı SPI hatlarına almak sorunu çözer.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
RFID Değer Okuma
Apartman anahtarlığında ya da giriş kartında gizli bir kimlik numarası saklıdır; bu proje onu okur. Kartı RFID okuyucuya yaklaştırınca Arduino kartın numarasını bilgisayar ekranına yazar. Kartlı kapı

RFID Kimlik Doğrulama
Apartman kapısındaki kartlı giriş gibi: RFID okuyucuya kartını yaklaştırırsın, Arduino kartın numarasını kayıtlı olanla karşılaştırır. Doğru kartta yeşil, yabancı kartta kırmızı LED üç saniye yanar ve

ESP32 RFID RC522 Kart Okuyucu (LCD Ekranlı)
Bu projede MFRC522 tabanlı RC522 RFID modülünü ESP32'ye SPI üzerinden bağlayıp kart/etiket UID'sini okuyacağız. Kapı kilidi, üyelik sistemi ve giriş kontrolü gibi uygulamaların temelini oluşturur. Okunan UID'yi LCD ekranda göstereceğiz; bu sürümde yetkili kart listesiyle karşılaştırma yapılmaz. DİKKAT: RC522 sadece 3.3V ile çalışır, 5V verirseniz modül yanar!

ESP32 RFID Kapı Kilidi (RC522 + Servo + OLED + Buzzer + LED)
ESP32 ile RC522 RFID modülü, SG90 servo motoru, SSD1306 OLED ekran, aktif buzzer ve 2 LED kullanarak akıllı bir kapı kilidi yapıyoruz. Kart okutulduğunda, UID kod içinde tanımlı yetkili kartlar listesiyle karşılaştırılır — yetkiliyse servo motoru döndürerek kilit açılır (yeşil LED + 2 kısa bip), 5 saniye sonra otomatik kilitler. Yetkisiz kartta kırmızı LED yanar, 3 hızlı bip ile uyarı verir ve OLED'de yakalanan UID gösterilir. Gerçek IoT güvenlik senaryosu için pratik ve öğretici — SPI protokolü

ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)
ESP32 ile zamanlı sıcaklık ve nem kayıt sistemi kur! Bu projede DHT22 sensörü ile dakikada bir sıcaklık/nem okuyup DS1307 RTC modülünden aldığın gerçek zaman etiketiyle microSD karta CSV formatında kaydediyoruz. OLED ekranda büyük font ile son sıcaklık değeri, nem yüzdesi, timestamp ve toplam kayıt sayısı canlı gösterilir. SD kart üzerindeki /temp_log.csv dosyası Excel/Google Sheets/Python pandas ile açılıp analiz edilebilir — sera monitörü, ev/oda sıcaklık takibi, laboratuvar veri toplama,

Dot Matrix Saat ve Takvim (MAX7219, DS1307)
Masada ya da duvarda duran, saati ve tarihi kayan yazıyla gösteren ışıklı bir pano. 8x32 LED ekranda iki noktası her saniye yanıp sönen büyük rakamlı saat durur; her dakika başında günün adı ve tarih

4x 32x8 Matrix LED Animasyon Ve Yazı
Dört uzun LED matris modülü üst üste dizilince binden fazla ışık noktası olan kare bir ekran çıkar. Önce filmlerdeki gibi yukarıdan harfler yağmur gibi düşer, ardından bir perde açılır ve iki satırda

Piksel Yılan: 8x8 Matris
Klasik yılan oyununu kendi ellerinle kur ve oyna. Renkli 8x8 ışık matrisinde yeşil yılanı oyun çubuğuyla yönlendirip kırmızı elmaları yersin; her elmada yılan uzar, biraz daha hızlanır ve puanın küçük
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ç

