Temeller · 9 dk okuma

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.

HatEski adıYeni adıYönGörevi
SCK / SCLKSerial ClockSCKKontrolcü → çevre birimiSaat sinyali; her darbede bir bit taşınır
MOSIMaster Out Slave InCOPI / SDOKontrolcü → çevre birimiArduino'dan modüle giden veri
MISOMaster In Slave OutCIPO / SDIÇevre birimi → kontrolcüModülden Arduino'ya dönen veri
CS / SSSlave SelectCS (Chip Select)Kontrolcü → çevre birimiLOW 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.

  1. 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.
  2. Kontrolcü SCK hattında saat darbeleri üretmeye başlar.
  3. Her darbede MOSI'den bir bit çıkar, MISO'dan bir bit girer. Bit sırası genelde en anlamlı bit önce (MSB first) şeklindedir.
  4. 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.

ModCPOLCPHASaat boştaykenVerinin okunduğu kenarÖrnek cihazlar
SPI_MODE000LOWYükselenSD kart, RC522, nRF24L01, MAX7219, MCP3008, 74HC595
SPI_MODE101LOWDüşenBazı ADC ve sürücü entegreleri
SPI_MODE210HIGHDüşenNadiren kullanılır
SPI_MODE311HIGHYükselenADXL345 ivmeölçer, CS pini olmayan bazı ST7789 ekranlar
Bir modülden sürekli 0xFF, 0x00 ya da her seferinde farklı saçma değerler okuyorsan önce veri sayfasında SPI modunu ve en yüksek saat hızını kontrol et. Hızı 1 MHz'e düşürüp denemek, sorunun kablo mu yoksa ayar mı olduğunu çabucak gösterir.

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.

CihazGöreviEn yüksek SPI saati (veri sayfası)SPI modu
MicroSD kartVeri kaydıBaşlangıçta 400 kHz, sonra 25 MHz'e kadarMod 0
RC522 (MFRC522)RFID okuyucu10 MHzMod 0
nRF24L012,4 GHz kablosuz10 MHzMod 0
MAX7219LED matris / 7 segment10 MHzMod 0
MCP30088 kanal 10 bit ADC5 V'ta 3,6 MHz, 2,7 V'ta 1,35 MHzMod 0 ya da 3
ILI93412,4–3,2 inç renkli TFTYazmada 10 MHz (pratikte çok daha hızlı sürülür)Mod 0

SPI pinleri: Arduino Uno, Mega, ESP32 ve Raspberry Pi Pico

HatArduino Uno / NanoArduino MegaESP32 VSPI (varsayılan)ESP32 HSPIRaspberry Pi Pico SPI0
SCKD13D52GPIO 18GPIO 14GP18
MOSID11D51GPIO 23GPIO 13GP19 (TX)
MISOD12D50GPIO 19GPIO 12GP16 (RX)
CS (varsayılan)D10D53GPIO 5GPIO 15GP17
Mantık seviyesi5 V5 V3,3 V3,3 V3,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.

RC522, nRF24L01 ve SD kartların kendisi 3,3 V cihazlardır. Uno'nun 5 V'luk sinyallerine doğrudan bağlanmaları cihazı zamanla bozabilir. Hazır SD kart modüllerinin çoğunda seviye dönüştürücü vardır; RC522 ve nRF24L01'i ise 3V3 pininden besle ve sinyal hatlarında lojik seviye dönüştürücü kullanmayı düşün. ESP32 ve Pico zaten 3,3 V olduğu için bu cihazlarla doğrudan uyumludur.

Arduino SPI kütüphanesi: temel fonksiyonlar

FonksiyonNe 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:

C++ (Arduino IDE)
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.

C++ (Arduino IDE)
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.
C++ (Arduino IDE)
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:

C++ (Arduino IDE)
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}
HSPI'nin MISO pini olan GPIO 12, ESP32'nin açılış (strapping) pinlerinden biridir: açılış anında HIGH ise kart flash belleği 1,8 V sanır ve açılmaz. MISO hattında pull-up direnci olan modülleri (çoğu SD kart modülü gibi) HSPI'ye bağlama ya da MISO'yu başka bir pine taşı. Bu örnekte SD kart bu yüzden VSPI'de duruyor.

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:

MicroPython
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ı

ÖzellikSPII2CUART
Kablo sayısı4 (+ her ek cihaz için 1 CS)2 (SDA, SCL)2 (TX, RX)
Tipik hız1–80 MHz100 kHz, 400 kHz, 1 MHz9600–115200 baud (birkaç Mbit/s'e kadar)
SaatVar (kontrolcü üretir)Var (kontrolcü üretir)Yok; iki taraf aynı baud hızında anlaşır
YönTam çift yönlüYarım çift yönlüTam çift yönlü
Cihaz seçimiAyrı CS kablosu7 bitlik adresYalnızca iki cihaz (noktadan noktaya)
Ek parçaGerekmezPull-up dirençleriGerekmez
MesafeKısa (kart üzeri, birkaç on cm)Kısa (1 m civarı)Birkaç metre; RS-485 ile çok daha uzun
Tipik modüllerSD kart, RC522, TFT, nRF24L01, MAX7219OLED, LCD I2C modülü, RTC, BME280, MPU6050GPS, 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

BelirtiOlası sebepÇözüm
Hep 0xFF ya da 0x00 okunuyorMISO bağlı değil, MOSI ile MISO yer değiştirmiş ya da cihazın beslemesi yokDIN'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ıyorBir modül MISO'yu bırakmıyor ya da CS pinleri başta HIGH değilTü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 duruyorD10 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ıyorGPIO 12 açılışta HIGH kalıyorPull-up'lı MISO'yu VSPI'ye taşı ya da MISO için başka bir pin seç
Uzun kabloda rastgele hatalarHızlı sinyalde yansıma ve parazitKabloları kısalt, hızı düşür, GND kablosunu sinyallerin yanından götür
SPI'da neler olup bittiğini görmek için birkaç dolarlık 8 kanallı bir lojik analizör çok işe yarar: SCK, MOSI, MISO ve CS'yi aynı anda kaydeder, hangi baytın gidip hangisinin geldiğini çözümler. "Kod doğru ama çalışmıyor" dediğin anda sorunun kabloda mı yoksa ayarda mı olduğunu birkaç saniyede gösterir.

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.

Tüm projeleri gör
RFID Değer Okuma
#53Başlangıç
Premium

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ı

4.7(47)
61
RFID Kimlik Doğrulama
#54Orta
Premium

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

4.8(64)
83
ESP32 RFID RC522 Kart Okuyucu (LCD Ekranlı)
#123Orta

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!

4.8(21)
39
ESP32 RFID Kapı Kilidi (RC522 + Servo + OLED + Buzzer + LED)
#137İleri
Premium

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ü

4.8(9)
15
ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)
#144İleri
Premium

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,

4.7(7)
12
Dot Matrix Saat ve Takvim (MAX7219, DS1307)
#84Orta
Premium

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

5.0(37)
59
4x 32x8 Matrix LED Animasyon Ve Yazı
#90Orta
Premium

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

4.6(40)
66
Piksel Yılan: 8x8 Matris
#88İleri
Premium

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

4.7(39)
57