Grundlagen · 11 Min. Lesezeit

Was ist SPI? MOSI, MISO, SCK und CS am Arduino einfach erklärt

Was ist SPI und wie funktioniert es? MOSI, MISO, SCK und CS, SPI-Modi und Takt, mehrere Geräte, Pins von Uno, Mega, ESP32 und Pico, SD-Karte mit RFID.

SPI (Serial Peripheral Interface) ist ein Übertragungsverfahren, mit dem ein Mikrocontroller über vier Leitungen sehr schnell Daten mit Geräten wie SD-Karten, RFID-Lesern, farbigen TFT-Displays oder Funkmodulen austauscht. Es gibt eine Taktleitung (SCK), zwei getrennte Datenleitungen für beide Richtungen (MOSI und MISO) und eine CS-Leitung, die auswählt, mit welchem Gerät gerade gesprochen wird. Weil SPI ein Vielfaches schneller sein kann als I2C, ist es die erste Wahl für Module, die große Datenmengen bewegen.

In diesem Beitrag lernst du, wie SPI funktioniert, die Pinnamen und die neue Bezeichnung, die vier SPI-Modi, die Geschwindigkeitsgrenzen, die Pins von Arduino Uno, Mega, ESP32 (VSPI und HSPI) und Raspberry Pi Pico, wie du mehrere Geräte an denselben Bus hängst und warum SD-Karte und RC522-RFID-Leser zusammen Probleme machen. Im letzten Abschnitt vergleichen wir SPI mit I2C und UART.

Was ist SPI und wie funktioniert es?

Bei SPI gibt es immer einen Controller (früher Master) und ein oder mehrere Peripheriegeräte (früher Slaves). Nur der Controller erzeugt den Takt; der Arduino beginnt also das Gespräch, bestimmt die Geschwindigkeit und beendet es. Bei jedem Taktimpuls sendet der Controller ein Bit über MOSI, und gleichzeitig schickt das Peripheriegerät ein Bit über MISO zurück. Die Schieberegister auf beiden Seiten bilden eine Art Ring: Nach 8 Taktimpulsen ist das Byte des Controllers beim Peripheriegerät und das Byte des Peripheriegeräts beim Controller angekommen. Deshalb ist SPI vollduplex: Lesen und Schreiben passieren gleichzeitig.

LeitungAlter NameNeuer NameRichtungAufgabe
SCK / SCLKSerial ClockSCKController → PeripherieTaktsignal; mit jedem Impuls wird ein Bit übertragen
MOSIMaster Out Slave InCOPI / SDOController → PeripherieDaten vom Arduino zum Modul
MISOMaster In Slave OutCIPO / SDIPeripherie → ControllerDaten vom Modul zurück zum Arduino
CS / SSSlave SelectCS (Chip Select)Controller → PeripherieSolange LOW, hört dieses Modul zu; jedes Gerät bekommt ein eigenes CS

Die Beschriftungen auf den Modulen sind nicht immer gleich, und das sorgt für die meiste Verwirrung. Beim RC522-RFID-Modul heißt die CS-Leitung SDA (das hat nichts mit SDA bei I2C zu tun), beim nRF24L01 CSN, beim MCP3008 CS/SHDN, und auf manchen Displays findest du Namen wie DIN (MOSI), CLK (SCK) und DOUT (MISO). Die Regel ist einfach: Der Dateneingang (DIN, SDI, MOSI) kommt an MOSI des Arduino, der Datenausgang (DOUT, SDO, MISO) an MISO des Arduino.

  1. Der Controller zieht die CS-Leitung des gewünschten Geräts auf LOW. Alle anderen Geräte behalten CS auf HIGH und geben die MISO-Leitung frei.
  2. Der Controller beginnt, Taktimpulse auf SCK zu erzeugen.
  3. Bei jedem Impuls geht ein Bit über MOSI hinaus und ein Bit kommt über MISO herein. Meist wird das höchstwertige Bit zuerst übertragen (MSB first).
  4. Sind alle nötigen Bytes (Befehl, Adresse, Daten) übertragen, setzt der Controller CS wieder auf HIGH und das Gerät schließt den Vorgang ab.

SPI-Modi: CPOL und CPHA

SPI hat keinen einheitlichen Standard; Geräte unterscheiden sich darin, auf welchem Pegel der Takt im Ruhezustand liegt (CPOL, Clock Polarity) und an welcher Taktflanke die Daten gelesen werden (CPHA, Clock Phase). Die vier Kombinationen dieser beiden Einstellungen ergeben die vier SPI-Modi. Sind Controller und Gerät nicht im selben Modus, verschieben sich die Daten um ein Bit und du liest sinnlose Werte. Zum Glück nutzt die große Mehrheit der Module Modus 0.

ModusCPOLCPHATakt in RuheFlanke zum LesenBeispielgeräte
SPI_MODE000LOWSteigendSD-Karte, RC522, nRF24L01, MAX7219, MCP3008, 74HC595
SPI_MODE101LOWFallendEinige ADC- und Treiber-ICs
SPI_MODE210HIGHFallendSelten verwendet
SPI_MODE311HIGHSteigendBeschleunigungssensor ADXL345, manche ST7789-Displays ohne CS-Pin
Liest du von einem Modul ständig 0xFF, 0x00 oder jedes Mal anderen Unsinn, prüfe zuerst im Datenblatt den SPI-Modus und den maximalen Takt. Den Takt auf 1 MHz zu senken und es erneut zu versuchen zeigt schnell, ob das Problem an der Verdrahtung oder an den Einstellungen liegt.

SPI-Geschwindigkeit und Kabellänge

Bei SPI bestimmt der Controller den Takt, und die Grenze setzt meist das Gerät selbst. Der Arduino Uno schafft bis zu 8 MHz, die Hälfte seines 16-MHz-Takts; der Standard der SPI-Bibliothek liegt bei 4 MHz. Der ESP32 kann an seinen eigenen SPI-Pins (IO_MUX) bis zu 80 MHz erzeugen; wird das Signal über die GPIO-Matrix auf andere Pins geleitet, sinkt diese Grenze. Der Raspberry Pi Pico erreicht bei 125 MHz Systemtakt etwa 62,5 MHz. Schnelle SPI-Signale brauchen kurze Leitungen: Mit Steckbrett und 10–20 cm langen Jumperkabeln sind einige MHz kein Problem; ab 20–30 MHz halte die Leitungen kurz und löte die Verbindungen, wenn möglich. Mehrere Meter Länge sind für SPI nicht geeignet.

GerätAufgabeMaximaler SPI-Takt (Datenblatt)SPI-Modus
MicroSD-KarteDatenloggingBeim Start 400 kHz, danach bis 25 MHzModus 0
RC522 (MFRC522)RFID-Leser10 MHzModus 0
nRF24L012,4-GHz-Funk10 MHzModus 0
MAX7219LED-Matrix / 7-Segment10 MHzModus 0
MCP30088-Kanal-ADC mit 10 Bit3,6 MHz bei 5 V, 1,35 MHz bei 2,7 VModus 0 oder 3
ILI9341Farb-TFT mit 2,4–3,2 Zoll10 MHz beim Schreiben (in der Praxis deutlich schneller betrieben)Modus 0

SPI-Pins: Arduino Uno, Mega, ESP32 und Raspberry Pi Pico

LeitungArduino Uno / NanoArduino MegaESP32 VSPI (Standard)ESP32 HSPIRaspberry Pi Pico SPI0
SCKD13D52GPIO 18GPIO 14GP18
MOSID11D51GPIO 23GPIO 13GP19 (TX)
MISOD12D50GPIO 19GPIO 12GP16 (RX)
CS (Standard)D10D53GPIO 5GPIO 15GP17
Logikpegel5 V5 V3,3 V3,3 V3,3 V

Beim Uno liegen dieselben SPI-Leitungen auch an der 6-poligen ICSP-Stiftleiste am Rand des Boards; bei Boards wie Leonardo und Micro gibt es SPI nur über ICSP. Für CS ist D10 nicht Pflicht, du kannst jeden digitalen Pin nehmen. Lass beim Uno aber D10 nicht als Eingang: Liest die SPI-Hardware an D10 als Eingang ein LOW, verlässt sie den Controller-Modus. SPI.begin() macht diesen Pin automatisch zum Ausgang, und du solltest ihn nicht für etwas anderes zum Eingang machen. Beim ESP32 nutzt das Arduino-Objekt SPI standardmäßig VSPI; dank der GPIO-Matrix kannst du SPI aber auf fast beliebige Pins legen. Beim Pico lassen sich SPI0 und SPI1 mehreren Pin-Gruppen zuordnen (z. B. GP10, GP11, GP12 für SPI1); Details zeigt dir das Werkzeug Pinout.

RC522, nRF24L01 und die SD-Karten selbst sind 3,3-V-Bauteile. Direkt an den 5-V-Signalen des Uno können sie mit der Zeit Schaden nehmen. Die meisten fertigen SD-Kartenmodule haben einen Pegelwandler; RC522 und nRF24L01 versorgst du über den 3V3-Pin und solltest für die Signalleitungen einen Logikpegelwandler in Betracht ziehen. ESP32 und Pico arbeiten ohnehin mit 3,3 V und passen direkt zu diesen Bauteilen.

Die Arduino-SPI-Bibliothek: wichtige Funktionen

FunktionWas macht sie?
SPI.begin()Startet die SPI-Hardware; schaltet SCK, MOSI und SS auf Ausgang.
SPISettings(Takt, MSBFIRST, SPI_MODE0)Speichert Takt, Bitreihenfolge und Modus eines Geräts in einem Objekt.
SPI.beginTransaction(Einstellungen)Übernimmt die Einstellungen und reserviert den Bus für dieses Gerät; macht den Wechsel zwischen Geräten mit unterschiedlichen Einstellungen sicher.
SPI.transfer(Byte)Sendet ein Byte und gibt das gleichzeitig empfangene Byte zurück.
SPI.transfer16(Wert)Sendet und empfängt einen 16-Bit-Wert in einem Zug.
SPI.transfer(Puffer, Länge)Sendet ein Array; die empfangenen Bytes überschreiben dasselbe Array.
SPI.endTransaction()Gibt den Bus frei; wird nach dem Setzen von CS auf HIGH aufgerufen.

Erstes Beispiel: Daten per SPI an einen 74HC595 senden

Am einfachsten verstehst du SPI mit einem 74HC595-Schieberegister, denn der 595 ist im Grunde das einfachste SPI-Peripheriegerät, eines ohne MISO. Der MOSI-Pin des Arduino geht an den DS-Eingang des 595, SCK an SH_CP und D10 an ST_CP, das als Latch dient. Anders als die Funktion shiftOut() sendet Hardware-SPI das Byte in wenigen Mikrosekunden:

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}

Daten per SPI lesen: der ADC MCP3008

Um die Vollduplex-Übertragung zu sehen, nehmen wir den MCP3008. Dieser Baustein ergänzt den Arduino um 8 weitere analoge 10-Bit-Eingänge; er ist eine gute Alternative zum nichtlinearen ADC des ESP32 oder zu den nur 3 Analogeingängen des Pico. Die Grundlagen des analogen Lesens erklären wir im Beitrag Was ist ein ADC?. Verdrahtung: CLK → D13, DOUT → D12, DIN → D11, CS → D10, VDD und VREF → 5V, AGND und 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}

Hier senden wir drei Bytes und empfangen gleichzeitig drei Bytes. Das erste Byte (0x01) ist nur das Startbit; im zweiten Byte gehen Single-Ended-Modus und Kanalnummer hinaus, während der MCP3008 die obersten 2 Bits des Ergebnisses zurückschickt. Das dritte Byte ist 0x00; sein Inhalt ist egal, es wird nur gesendet, um Takte zu erzeugen und die restlichen 8 Bits des Ergebnisses zu empfangen. Bei SPI bedeutet "Lesen" immer, etwas zu senden. Das Ergebnis liegt zwischen 0 und 1023 und wird bezogen auf VREF (hier 5 V) in Volt umgerechnet.

Mehrere SPI-Geräte: getrennte CS-Leitungen

Der größte Unterschied zwischen SPI und I2C ist, dass SPI keine Adressen nutzt. Die Geräte teilen sich SCK, MOSI und MISO, und jedes bekommt vom Arduino eine eigene CS-Leitung. Nur das Gerät, dessen CS auf LOW liegt, hört zu, und nur dieses schreibt Daten auf MISO. Drei Geräte brauchen 3 + 3 = 6 Leitungen, fünf Geräte 3 + 5 = 8; die Pinzahl wächst mit der Zahl der Geräte. Manche Bausteine wie 74HC595 und MAX7219 lassen sich stattdessen in Reihe schalten (Daisy Chain): Der Ausgang des einen geht in den Eingang des nächsten, und alle werden mit einem einzigen CS angesteuert.

  • Immer nur ein CS darf LOW sein. Werden zwei Geräte gleichzeitig ausgewählt, kollidieren sie auf der MISO-Leitung und du liest von beiden falsche Daten.
  • Schalte in setup() zuerst alle CS-Pins auf Ausgang und HIGH und starte erst dann die Bibliotheken. Ein offener CS-Pin kann zufällig LOW erscheinen und den Bus belegen.
  • Nutze beginTransaction für jedes Gerät. Eine SD-Karte will vielleicht 25 MHz, ein MCP3008 1 MHz; Transaktionen setzen bei jedem Wechsel automatisch den richtigen Takt und Modus.
  • Wenn du SPI in Interrupts nutzt, teile es der Bibliothek mit SPI.usingInterrupt() mit oder arbeite im Interrupt gar nicht mit SPI.
  • Ein 10-kΩ-Pull-up an der CS-Leitung jedes Geräts verhindert, dass sich Geräte beim Start oder Reset des Arduino selbst auswählen.

SD-Karte und RFID am selben Bus: warum klappt das nicht?

Ein Klassiker in Arduino-Foren: Der RC522-RFID-Leser funktioniert allein, das SD-Kartenmodul funktioniert allein, aber am selben SPI-Bus verstummt eines oder beide. Selbst wenn die CS-Pins in der Software stimmen, liegt das Problem meist in der Hardware. Viele günstige SD-Kartenmodule haben einen 74LVC125-Puffer, der 5-V-Signale auf 3,3 V umsetzt, und der Kanal dieses Bausteins, der die MISO-Leitung treibt, ist immer aktiv. Selbst wenn CS der SD-Karte auf HIGH liegt, gibt das Modul MISO also nicht frei; will der RC522 antworten, kämpfen zwei Ausgänge um die Leitung.

  • Wähle das richtige Modul: Module, die MISO bei CS = HIGH hochohmig schalten, teilen sich den Bus problemlos. Ob ein Modul die Leitung freigibt, findest du heraus, indem du MISO bei CS = HIGH über 10 kΩ erst gegen GND, dann gegen 5 V ziehst und mit dem Multimeter misst.
  • Verbinde den Enable-Pin des Puffers mit CS: Wenn du sicher löten kannst, trennst du den OE-Pin des MISO-Kanals am 74LVC125 von GND und verbindest ihn mit der CS-Leitung des Moduls; das löst das Problem dauerhaft.
  • Setze einen Serienwiderstand in MISO: Ein Serienwiderstand von etwa 1 kΩ am MISO-Ausgang des SD-Moduls lässt den RC522 die Leitung überstimmen. Eine einfache, aber den Takt begrenzende Notlösung.
  • Nutze einen getrennten SPI-Bus: Hängst du beim ESP32 die SD-Karte an VSPI und den RC522 an HSPI, begegnen sich die beiden Geräte nie. Der Uno hat keinen zweiten Hardware-SPI, dort gibt es diese Möglichkeit nicht.
  • Achte auf die Startreihenfolge: Setze zuerst alle CS-Pins auf HIGH, rufe dann SPI.begin() auf, danach SD.begin() und PCD_Init(). Das Beispiel unten hält diese Reihenfolge ein.
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}

In diesem Code schalten die SD-Bibliothek und die MFRC522-Bibliothek ihre CS-Pins selbst auf LOW und HIGH; du musst nur zu Beginn beide auf HIGH lassen und sicherstellen, dass die Hardware MISO richtig teilt. Der Code schreibt die UID jeder gelesenen Karte zusammen mit einem Zeitstempel in die Datei kartlar.txt. Auf dem Uno belegen beide Bibliotheken zusammen etwa die Hälfte des RAM; das Makro F() schafft Platz, indem es konstante Texte im Flash hält.

VSPI und HSPI beim ESP32: zwei getrennte SPI-Busse

Der ESP32 enthält vier SPI-Einheiten; SPI0 und SPI1 sind für den internen Flash reserviert, für dich bleiben VSPI (SPI3) und HSPI (SPI2). Beide zu nutzen ist der sauberste Weg, Geräte mit sehr unterschiedlichem Takt und Modus zu trennen oder dem oben beschriebenen MISO-Konflikt zu entgehen. Im Arduino-Core legst du für den zweiten Bus ein SPIClass-Objekt an und übergibst mit begin() seine Pins. Der folgende Code betreibt die SD-Karte am Standard-VSPI und den MCP3008 an HSPI und hängt jede Sekunde einen Messwert an eine CSV-Datei an:

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}
GPIO 12, der MISO-Pin von HSPI, ist einer der Boot-Pins (Strapping-Pins) des ESP32: Liegt er beim Start auf HIGH, hält das Board den Flash für einen 1,8-V-Typ und startet nicht. Schließe Module mit Pull-up an MISO (wie die meisten SD-Kartenmodule) nicht an HSPI an, oder lege MISO auf einen anderen Pin. Deshalb sitzt die SD-Karte in diesem Beispiel an VSPI.

SPI mit dem Raspberry Pi Pico (MicroPython)

Der Pico hat zwei Hardware-SPI-Einheiten (SPI0 und SPI1), die du in MicroPython über die Klasse machine.SPI nutzt. Die Parameter polarity und phase entsprechen CPOL und CPHA; sind beide 0, ist es Modus 0. CS steuerst du selbst als normalen Ausgangspin. Die Funktion write_readinto() zeigt die Vollduplex-Natur von SPI am besten: Während sie ein Array sendet, schreibt sie die ankommenden Bytes in ein anderes. Lesen wir denselben MCP3008, diesmal mit 3,3 V versorgt:

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 und UART im Vergleich

MerkmalSPII2CUART
Anzahl der Leitungen4 (+1 CS je weiteres Gerät)2 (SDA, SCL)2 (TX, RX)
Typische Geschwindigkeit1–80 MHz100 kHz, 400 kHz, 1 MHz9600–115200 Baud (bis zu einigen Mbit/s)
TaktJa (vom Controller erzeugt)Ja (vom Controller erzeugt)Keiner; beide Seiten vereinbaren dieselbe Baudrate
RichtungVollduplexHalbduplexVollduplex
GeräteauswahlEigene CS-Leitung7-Bit-AdresseNur zwei Geräte (Punkt zu Punkt)
Zusätzliche BauteileKeine nötigPull-up-WiderständeKeine nötig
ReichweiteKurz (auf der Platine, einige zehn cm)Kurz (etwa 1 m)Einige Meter; mit RS-485 viel weiter
Typische ModuleSD-Karte, RC522, TFT, nRF24L01, MAX7219OLED, I2C-LCD-Adapter, RTC, BME280, MPU6050GPS, HC-05, SIM800L, ESP-01, Computer

Meist trifft das Modul die Wahl, aber für eigene Entwürfe hilft diese Regel: Zählen Geschwindigkeit und Datenmenge (Displaybilder, Dateien, Audio), nimm SPI; brauchst du wenige Leitungen und viele langsame Sensoren, nimm I2C; willst du eine einfache, textbasierte Verbindung zwischen zwei Geräten, nimm UART. UART im Detail findest du im Beitrag UART serielle Kommunikation. Alle drei im selben Projekt zu nutzen ist ebenfalls sehr verbreitet: etwa ein Datenlogger, der Sensoren per I2C liest, per SPI auf eine SD-Karte schreibt und per UART die Position von einem GPS bekommt.

Module mit SPI und Projektideen

  • Kartenschloss mit Zutrittsprotokoll: Lies die Karte mit einem RC522 und schreibe Datum und UID auf eine SD-Karte.
  • Temperaturlogger: Speichere Sensordaten als CSV auf einer microSD-Karte und zeichne in Excel ein Diagramm.
  • Laufschrift-Anzeige: Zeige Uhrzeit und Nachrichten auf in Reihe geschalteten MAX7219-LED-Matrix-Modulen.
  • Farbige Oberfläche: Zeichne Grafiken und Menüs auf einem ILI9341-TFT-Display; hänge das Touchpanel an denselben SPI-Bus.
  • Funkfernbedienung: Schicke deinem Roboterauto mit zwei nRF24L01-Modulen Befehle.
  • Mehrkanalmessung: Baue mit einem MCP3008 einen MIDI-Controller mit 8 Potis oder eine Bewässerung mit 8 Bodenfeuchtesensoren.

Häufige Fehler und Lösungen

SymptomWahrscheinliche UrsacheLösung
Es wird immer 0xFF oder 0x00 gelesenMISO nicht verbunden, MOSI und MISO vertauscht oder Gerät ohne VersorgungDIN an MOSI und DOUT an MISO anschließen; VCC des Geräts messen
Werte sind unsinnig oder um ein Bit verschobenFalscher SPI-Modus oder zu hoher Takt für das GerätModus aus dem Datenblatt nutzen, Takt auf 1 MHz senken und erneut testen
Zwei einzeln funktionierende Geräte laufen nicht zusammenEin Modul gibt MISO nicht frei oder die CS-Pins sind beim Start nicht HIGHAlle CS zuerst auf HIGH setzen; das Modul tauschen, das MISO nicht freigibt, oder getrennten SPI-Bus nutzen
SPI bleibt am Uno plötzlich stehenD10 wurde als Eingang genutzt und auf LOW gezogenD10 als Ausgang lassen; du kannst ihn als CS verwenden
ESP32 startet mit angeschlossenem HSPI nichtGPIO 12 liegt beim Start auf HIGHMISO mit Pull-up an VSPI verlegen oder für MISO einen anderen Pin wählen
Zufällige Fehler bei langen KabelnReflexionen und Störungen bei schnellem SignalKabel kürzen, Takt senken, eine GND-Leitung neben den Signalen führen
Ein günstiger 8-Kanal-Logikanalysator ist sehr nützlich, um zu sehen, was auf dem SPI-Bus passiert: Er zeichnet SCK, MOSI, MISO und CS gleichzeitig auf und dekodiert, welches Byte hinausging und welches zurückkam. Sobald du sagst "der Code stimmt, aber es geht nicht", zeigt er dir in Sekunden, ob das Problem an der Verdrahtung oder an den Einstellungen liegt.

SPI ist die gemeinsame Sprache der schnellen Module in der Arduino-Welt, von SD-Karten bis zu Farbdisplays: Kennst du die vier Leitungen, die CS-Logik und die vier Modi, ist ein neues SPI-Modul in wenigen Minuten angeschlossen. In der BlueGrays-App findest du die Projekte RFID-Karten lesen und Türschloss, microSD-Temperaturlogger und MAX7219-Punktmatrix-Uhr, Schritt für Schritt mit Schaltplan und Code.

Häufige Fragen

Wofür steht SPI?

SPI steht für Serial Peripheral Interface. Damit tauscht ein Controller über vier Leitungen, SCK, MOSI, MISO und CS, schnell und synchron Daten mit Peripheriegeräten aus.

Was sind MOSI und MISO?

MOSI (Master Out Slave In) ist die Datenleitung vom Controller zum Peripheriegerät, MISO (Master In Slave Out) die Datenleitung vom Peripheriegerät zurück zum Controller. In der neueren Bezeichnung heißen sie auch COPI und CIPO. Bei Modulen kommt DIN meist an MOSI und DOUT an MISO.

Welche Pins sind beim Arduino Uno für SPI?

Beim Arduino Uno und Nano ist SCK D13, MISO D12, MOSI D11 und das Standard-CS D10. Dieselben Leitungen liegen auch an der 6-poligen ICSP-Stiftleiste. Beim Arduino Mega sind es SCK D52, MISO D50, MOSI D51 und CS D53.

Was ist der Unterschied zwischen SPI und I2C?

SPI nutzt vier Leitungen, ist vollduplex und kann mit mehreren zehn MHz laufen; jedes Gerät braucht eine eigene CS-Leitung. I2C kommt mit zwei Leitungen aus und wählt Geräte per Adresse, läuft aber mit viel kleineren Takten wie 100–400 kHz und braucht Pull-up-Widerstände.

Wie viele Geräte kann man an einen SPI-Bus hängen?

Eine theoretische Grenze gibt es nicht; du brauchst nur für jedes Gerät einen freien CS-Pin am Controller. In der Praxis treten bei hohem Takt Probleme auf, wenn Buskapazität und Kabellänge wachsen. Reichen die Pins nicht, kannst du die CS-Leitungen mit einem 74HC138-Decoder vervielfachen oder kaskadierbare Geräte verwenden.

Warum laufen SD-Karte und RFID nicht am selben SPI-Bus?

Der Pegelwandler vieler günstiger SD-Kartenmodule gibt die MISO-Leitung auch bei CS = HIGH nicht frei und verfälscht so die Antwort des RC522. Ein Modul, das MISO richtig freigibt, den Enable-Pin des Puffers an CS zu legen oder beim ESP32 beide Geräte auf getrennte SPI-Busse zu verteilen, löst das Problem.

Alle Projekte ansehen
RFID-Werte lesen
#53Anfänger
Premium

RFID-Werte lesen

In deinem Schlüsselanhänger für die Haustür oder deiner Zugangskarte steckt eine geheime Kennnummer, und dieses Projekt liest sie aus. Halte die Karte an den RFID-Leser, und der Arduino schreibt ihre

4.7(47)
61
RFID-Authentifizierung
#54Mittel
Premium

RFID-Authentifizierung

Wie der Kartenzugang an der Haustür: Du hältst deine Karte an den RFID-Leser, und der Arduino vergleicht ihre Nummer mit der gespeicherten. Bei der richtigen Karte leuchtet drei Sekunden lang die grün

4.8(64)
83
ESP32 RFID-Kartenleser RC522 (mit LCD)
#123Mittel

ESP32 RFID-Kartenleser RC522 (mit LCD)

In diesem Projekt schließen wir das MFRC522-basierte RC522-RFID-Modul über SPI an den ESP32 an und lesen die UID der Karte bzw. des Tags aus. Dies bildet die Grundlage für Anwendungen wie Türschlösser, Mitgliedersysteme und Zugangskontrollen. Wir zeigen die gelesene UID auf einem LCD-Display an; diese Version gleicht sie nicht mit einer Liste autorisierter Karten ab. ACHTUNG: Das RC522 arbeitet nur mit 3,3 V; bei 5 V brennt das Modul durch!

4.8(21)
39
ESP32-RFID-Türschloss (RC522 + Servo + OLED + Summer + LED)
#137Fortgeschritten
Premium

ESP32-RFID-Türschloss (RC522 + Servo + OLED + Summer + LED)

Mit dem ESP32, einem RC522-RFID-Modul, einem SG90-Servomotor, einem SSD1306-OLED-Display, einem aktiven Summer und zwei LEDs bauen wir ein intelligentes Türschloss. Wenn eine Karte eingelesen wird, wird die UID mit der Liste der autorisierten Karten verglichen, die im Code definiert ist – ist die Karte autorisiert, wird das Schloss durch Drehen des Servomotors entriegelt (grüne LED + 2 kurze Pieptöne) und nach 5 Sekunden automatisch wieder verriegelt. Bei einer nicht autorisierten Karte leuchtet

4.8(9)
15
ESP32 Temperatur-Datenlogger (DHT22 + DS1307 RTC + microSD + OLED)
#144Fortgeschritten
Premium

ESP32 Temperatur-Datenlogger (DHT22 + DS1307 RTC + microSD + OLED)

Baue einen zeitgestempelten Temperaturlogger mit ESP32! Lese Temperatur/Feuchtigkeit vom DHT22 jede Minute, hole die aktuelle Zeit vom DS1307 RTC und protokolliere auf microSD-Karte als CSV. Das OLED zeigt live Temperatur (große Schrift), Luftfeuchtigkeit, Zeitstempel und Logzähler. Die /temp_log.csv-Datei auf der SD-Karte öffnet sich in Excel, Google Sheets oder Python pandas zur Analyse — perfekt für Gewächshausüberwachung, Raumtemperaturverfolgung, Laboraufzeichnung, Lebensmittellageru

4.7(7)
12
Punktmatrixuhr und Kalender (MAX7219, DS1307)
#84Mittel
Premium

Punktmatrixuhr und Kalender (MAX7219, DS1307)

Eine leuchtende Tafel für Tisch oder Wand, die Uhrzeit und Datum als Laufschrift zeigt. Auf dem 8x32-LED-Display steht eine Uhr mit großen Ziffern, deren zwei Punkte jede Sekunde blinken; zu Beginn je

5.0(37)
59
4x 32x8 Matrix LED Animation und Text
#90Mittel
Premium

4x 32x8 Matrix LED Animation und Text

Stapelst du vier lange LED-Matrixmodule übereinander, entsteht ein quadratischer Bildschirm mit über tausend Lichtpunkten. Zuerst rieseln Buchstaben wie Regen von oben herab, wie im Film, dann öffnet

4.6(40)
66
Pixel-Schlange 8x8 Matrix
#88Fortgeschritten
Premium

Pixel-Schlange 8x8 Matrix

Bau das klassische Schlangenspiel selbst und spiel es. Auf einer bunten 8x8-Lichtmatrix steuerst du eine grüne Schlange mit dem Joystick und frisst rote Äpfel; mit jedem Apfel wird die Schlange länger

4.7(39)
57