Basi · 12 min di lettura

Cos'è SPI? Pin MOSI, MISO, SCK e CS con Arduino spiegati bene

Cos'è SPI e come funziona: pin MOSI, MISO, SCK e CS, modalità e velocità, più dispositivi, pin di Uno, Mega, ESP32 e Pico, e il conflitto tra SD e RFID.

SPI (Serial Peripheral Interface, interfaccia seriale per periferiche) è un metodo di comunicazione che permette a un microcontrollore di scambiare dati molto velocemente con dispositivi come schede SD, lettori RFID, display TFT a colori o moduli wireless attraverso quattro fili. C'è una linea di clock (SCK), due linee separate per i dati nei due sensi (MOSI e MISO) e una linea CS che sceglie con quale dispositivo si sta parlando. Poiché può essere decine di volte più veloce dell'I2C, è il bus preferito dai moduli che trasferiscono molti dati.

In questo articolo imparerai come funziona SPI, i nomi dei pin e la nuova terminologia, le quattro modalità SPI, i limiti di velocità, i pin di Arduino Uno, Mega, ESP32 (VSPI e HSPI) e Raspberry Pi Pico, come collegare più dispositivi allo stesso bus e perché una scheda SD e un lettore RFID RC522 insieme danno problemi. Nell'ultima sezione confrontiamo SPI con I2C e UART.

Cos'è SPI e come funziona?

In SPI c'è sempre un controller (un tempo chiamato master) e una o più periferiche (un tempo chiamate slave). Solo il controller genera il clock; quindi è Arduino ad avviare la comunicazione, fissarne la velocità e chiuderla. A ogni impulso di clock il controller invia un bit su MOSI mentre, nello stesso momento, la periferica rimanda un bit su MISO. I registri a scorrimento dei due lati formano una specie di anello: dopo 8 impulsi il byte del controller è passato nella periferica e quello della periferica nel controller. Per questo SPI è full duplex: lettura e scrittura avvengono insieme.

LineaVecchio nomeNuovo nomeDirezioneFunzione
SCK / SCLKSerial ClockSCKController → perifericaSegnale di clock; a ogni impulso viaggia un bit
MOSIMaster Out Slave InCOPI / SDOController → perifericaDati da Arduino al modulo
MISOMaster In Slave OutCIPO / SDIPeriferica → controllerDati dal modulo di ritorno ad Arduino
CS / SSSlave SelectCS (Chip Select)Controller → perifericaFinché è LOW quel modulo ascolta; ogni dispositivo ha il suo CS

Le scritte sui moduli non sono sempre uguali, ed è la principale fonte di confusione. Sul modulo RFID RC522 la linea CS si chiama SDA (non ha niente a che vedere con l'SDA dell'I2C), sul nRF24L01 CSN, sul MCP3008 CS/SHDN, e su alcuni display troverai nomi come DIN (MOSI), CLK (SCK) e DOUT (MISO). La regola è semplice: l'ingresso dati (DIN, SDI, MOSI) va al MOSI di Arduino, l'uscita dati (DOUT, SDO, MISO) al MISO di Arduino.

  1. Il controller porta a LOW la linea CS del dispositivo con cui vuole parlare. Tutti gli altri tengono il CS a HIGH e lasciano libera la linea MISO.
  2. Il controller inizia a generare impulsi di clock su SCK.
  3. A ogni impulso esce un bit su MOSI ed entra un bit su MISO. Di solito si trasmette prima il bit più significativo (MSB first).
  4. Trasferiti i byte necessari (comando, indirizzo, dati), il controller riporta CS a HIGH e il dispositivo completa l'operazione.

Modalità SPI: CPOL e CPHA

SPI non ha uno standard unico; i dispositivi differiscono per il livello a cui resta il clock a riposo (CPOL, polarità del clock) e per il fronte del clock su cui vengono letti i dati (CPHA, fase del clock). Le quattro combinazioni di queste due impostazioni formano le quattro modalità SPI. Se controller e dispositivo non sono nella stessa modalità, i dati scivolano di un bit e leggi valori senza senso. Per fortuna la grande maggioranza dei moduli usa la modalità 0.

ModalitàCPOLCPHAClock a riposoFronte di letturaDispositivi di esempio
SPI_MODE000LOWSalitaScheda SD, RC522, nRF24L01, MAX7219, MCP3008, 74HC595
SPI_MODE101LOWDiscesaAlcuni ADC e integrati driver
SPI_MODE210HIGHDiscesaUsata raramente
SPI_MODE311HIGHSalitaAccelerometro ADXL345, alcuni display ST7789 senza pin CS
Se da un modulo leggi sempre 0xFF, 0x00 o valori assurdi diversi ogni volta, controlla prima nel datasheet la modalità SPI e la frequenza di clock massima. Abbassare la velocità a 1 MHz e riprovare mostra subito se il problema è nei collegamenti o nelle impostazioni.

Velocità SPI e lunghezza dei cavi

In SPI la velocità la decide il controller e il limite di solito lo pone il dispositivo stesso. Arduino Uno arriva fino a 8 MHz, metà del suo clock a 16 MHz; il valore predefinito della libreria SPI è 4 MHz. L'ESP32 può generare fino a 80 MHz sui suoi pin SPI dedicati (IO_MUX), e il limite si abbassa quando il segnale passa dalla matrice GPIO verso altri pin. Il Raspberry Pi Pico raggiunge circa 62,5 MHz con un clock di sistema di 125 MHz. I segnali SPI veloci vogliono fili corti: con breadboard e cavetti jumper da 10–20 cm qualche MHz non dà problemi; da 20–30 MHz in su tieni i fili corti e, se puoi, salda i collegamenti. Diversi metri di cavo non sono adatti a SPI.

DispositivoFunzioneClock SPI massimo (datasheet)Modalità SPI
Scheda microSDRegistrazione dati400 kHz all'avvio, poi fino a 25 MHzModalità 0
RC522 (MFRC522)Lettore RFID10 MHzModalità 0
nRF24L01Radio a 2,4 GHz10 MHzModalità 0
MAX7219Matrice LED / 7 segmenti10 MHzModalità 0
MCP3008ADC a 8 canali e 10 bit3,6 MHz a 5 V, 1,35 MHz a 2,7 VModalità 0 o 3
ILI9341TFT a colori da 2,4–3,2 pollici10 MHz in scrittura (in pratica pilotato molto più veloce)Modalità 0

Pin SPI: Arduino Uno, Mega, ESP32 e Raspberry Pi Pico

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

Sull'Uno le stesse linee SPI si trovano anche sul connettore ICSP a 6 pin sul bordo della scheda; su schede come Leonardo e Micro lo SPI è disponibile solo sull'ICSP. Per il CS non è obbligatorio usare D10: va bene qualsiasi pin digitale. Però sull'Uno non lasciare D10 come ingresso: se l'hardware SPI legge LOW su D10 mentre è un ingresso, esce dalla modalità controller. SPI.begin() imposta automaticamente questo pin come uscita, e non dovresti trasformarlo in ingresso per altri scopi. Sull'ESP32 l'oggetto SPI di Arduino usa VSPI per impostazione predefinita; grazie alla matrice GPIO puoi spostare SPI su quasi tutti i pin. Sul Pico, SPI0 e SPI1 si possono assegnare a diversi gruppi di pin (es. GP10, GP11, GP12 per SPI1); trovi i dettagli nello strumento Pinout.

RC522, nRF24L01 e le schede SD stesse sono dispositivi a 3,3 V. Collegarli direttamente ai segnali a 5 V dell'Uno può danneggiarli col tempo. La maggior parte dei moduli SD già pronti ha un traslatore di livello; alimenta RC522 e nRF24L01 dal pin 3V3 e valuta un convertitore di livello logico sulle linee di segnale. ESP32 e Pico lavorano già a 3,3 V, quindi sono direttamente compatibili con questi dispositivi.

La libreria SPI di Arduino: funzioni principali

FunzioneCosa fa?
SPI.begin()Avvia l'hardware SPI; imposta come uscite i pin SCK, MOSI e SS.
SPISettings(velocità, MSBFIRST, SPI_MODE0)Raccoglie in un oggetto velocità, ordine dei bit e modalità di un dispositivo.
SPI.beginTransaction(impostazioni)Applica le impostazioni e riserva il bus per quel dispositivo; rende sicuro il passaggio tra dispositivi con impostazioni diverse.
SPI.transfer(byte)Invia un byte e restituisce il byte ricevuto nello stesso momento.
SPI.transfer16(valore)Invia e riceve un valore a 16 bit in un colpo solo.
SPI.transfer(buffer, lunghezza)Invia un array; i byte ricevuti sovrascrivono lo stesso array.
SPI.endTransaction()Libera il bus; va chiamata dopo aver riportato CS a HIGH.

Primo esempio: inviare dati a un 74HC595 via SPI

Il modo più semplice per capire SPI è usare un registro a scorrimento 74HC595, perché il 595 è in pratica la periferica SPI più semplice, senza MISO. Il pin MOSI di Arduino va all'ingresso DS del 595, SCK a SH_CP e D10 a ST_CP, che fa da latch. A differenza della funzione shiftOut(), lo SPI hardware invia il byte in pochi microsecondi:

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}

Leggere dati via SPI: l'ADC MCP3008

Per vedere la comunicazione full duplex usiamo il MCP3008. Questo integrato aggiunge ad Arduino altri 8 ingressi analogici a 10 bit; è una buona alternativa all'ADC poco lineare dell'ESP32 o ai soli 3 ingressi analogici del Pico. Abbiamo spiegato le basi della lettura analogica nell'articolo Cos'è un ADC?. Collegamenti: CLK → D13, DOUT → D12, DIN → D11, CS → D10, VDD e VREF → 5V, AGND e 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}

Qui inviamo tre byte e ne riceviamo tre nello stesso momento. Il primo byte (0x01) è solo il bit di start; nel secondo viaggiano la modalità single-ended e il numero di canale, mentre il MCP3008 rimanda i 2 bit più alti del risultato. Il terzo byte è 0x00; il suo contenuto non conta, serve solo a generare impulsi di clock per ricevere gli 8 bit restanti. In SPI "leggere" significa sempre inviare qualcosa. Il risultato va da 0 a 1023 e si converte in volt rispetto a VREF (qui 5 V).

Più dispositivi SPI: linee CS separate

La differenza più grande tra SPI e I2C è che SPI non usa indirizzi. I dispositivi condividono le linee SCK, MOSI e MISO, e ognuno riceve da Arduino il proprio filo CS. Ascolta solo il dispositivo con il CS a LOW, e solo lui scrive dati su MISO. Tre dispositivi richiedono 3 + 3 = 6 fili, cinque dispositivi 3 + 5 = 8; il numero di pin cresce con quello dei dispositivi. Alcuni integrati come il 74HC595 e il MAX7219 si possono invece collegare in cascata (daisy chain): l'uscita di uno entra nel successivo e tutti si pilotano con un solo CS.

  • Un solo CS a LOW alla volta. Se due dispositivi vengono selezionati insieme si scontrano sulla linea MISO e leggi dati corrotti da entrambi.
  • In setup() imposta prima tutti i pin CS come uscita a HIGH, poi avvia le librerie. Un pin CS flottante può sembrare LOW a caso e occupare il bus.
  • Usa beginTransaction per ogni dispositivo. Una scheda SD può volere 25 MHz e un MCP3008 1 MHz; le transazioni applicano automaticamente velocità e modalità giuste a ogni cambio.
  • Se usi SPI dentro gli interrupt, comunicalo alla libreria con SPI.usingInterrupt(), oppure non fare operazioni SPI dentro l'interrupt.
  • Una pull-up da 10 kΩ sulla linea CS di ogni dispositivo evita che i dispositivi si selezionino da soli mentre Arduino si avvia o si resetta.

Scheda SD e RFID sullo stesso bus: perché non funziona?

Una domanda classica dei forum Arduino: l'RFID RC522 funziona da solo, il modulo scheda SD funziona da solo, ma collegati allo stesso bus SPI uno dei due, o entrambi, smettono di rispondere. Anche se i pin CS sono giusti nel software, il problema di solito è nell'hardware. Molti moduli SD economici hanno un buffer 74LVC125 che converte i segnali da 5 V a 3,3 V, e il canale di questo integrato che pilota la linea MISO è sempre abilitato. Quindi, anche con il CS della scheda SD a HIGH, il modulo non rilascia MISO; quando l'RC522 prova a rispondere, due uscite si contendono la linea.

  • Scegli il modulo giusto: i moduli che mettono MISO in alta impedenza quando CS è HIGH condividono il bus senza problemi. Per capire se un modulo rilascia la linea, con CS a HIGH tira MISO con 10 kΩ prima verso GND e poi verso 5 V e misura con il multimetro.
  • Collega il pin di abilitazione del buffer al CS: se sai saldare, staccare da GND il pin OE del canale MISO del 74LVC125 e collegarlo alla linea CS del modulo risolve il problema alla radice.
  • Aggiungi una resistenza in serie su MISO: una resistenza di circa 1 kΩ in serie all'uscita MISO del modulo SD permette all'RC522 di imporre il suo segnale. È un rimedio facile ma che limita la velocità.
  • Usa un bus SPI separato: sull'ESP32, se colleghi la scheda SD a VSPI e l'RC522 a HSPI, i due dispositivi non si incontrano mai. L'Uno non ha un secondo SPI hardware, quindi lì questa possibilità non esiste.
  • Rispetta l'ordine di avvio: porta prima tutti i CS a HIGH, poi chiama SPI.begin(), quindi SD.begin() e PCD_Init(). L'esempio qui sotto segue questo ordine.
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 questo codice la libreria SD e la libreria MFRC522 portano da sole a LOW e HIGH i propri pin CS; tu devi solo lasciarli entrambi a HIGH all'inizio e assicurarti che l'hardware condivida correttamente MISO. Il codice scrive l'UID di ogni tessera letta, insieme a un'indicazione di tempo, nel file kartlar.txt. Sull'Uno queste due librerie insieme usano circa metà della RAM; la macro F() libera spazio tenendo i testi costanti nella flash.

VSPI e HSPI sull'ESP32: due bus SPI separati

L'ESP32 contiene quattro unità SPI; SPI0 e SPI1 sono riservate alla flash interna, quindi a te restano VSPI (SPI3) e HSPI (SPI2). Usarle entrambe è il modo più pulito per separare dispositivi con velocità e modalità molto diverse o per evitare il conflitto su MISO visto sopra. Nel core Arduino crei un oggetto SPIClass per il secondo bus e gli assegni i pin con begin(). Il codice seguente usa la scheda SD sul VSPI predefinito e il MCP3008 su HSPI, e ogni secondo aggiunge una misura a un file CSV:

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, il pin MISO di HSPI, è uno dei pin di avvio (strapping) dell'ESP32: se è HIGH all'accensione, la scheda crede che la flash sia a 1,8 V e non parte. Non collegare a HSPI moduli con una pull-up su MISO (come la maggior parte dei moduli SD), oppure sposta MISO su un altro pin. Per questo in questo esempio la scheda SD sta su VSPI.

SPI con il Raspberry Pi Pico (MicroPython)

Il Pico ha due unità SPI hardware (SPI0 e SPI1), che in MicroPython si usano con la classe machine.SPI. I parametri polarity e phase corrispondono a CPOL e CPHA; se valgono entrambi 0 è la modalità 0. Il CS lo gestisci tu come un normale pin di uscita. La funzione write_readinto() mostra al meglio la natura full duplex di SPI: mentre invia un array, scrive i byte in arrivo in un altro. Leggiamo lo stesso MCP3008, questa volta alimentato a 3,3 V:

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 e UART a confronto

CaratteristicaSPII2CUART
Numero di fili4 (+1 CS per ogni dispositivo in più)2 (SDA, SCL)2 (TX, RX)
Velocità tipica1–80 MHz100 kHz, 400 kHz, 1 MHz9600–115200 baud (fino a qualche Mbit/s)
ClockSì (generato dal controller)Sì (generato dal controller)No; i due lati concordano la stessa velocità in baud
DirezioneFull duplexHalf duplexFull duplex
Selezione del dispositivoFilo CS dedicatoIndirizzo a 7 bitSolo due dispositivi (punto a punto)
Componenti aggiuntiviNon servonoResistenze di pull-upNon servono
DistanzaBreve (sulla scheda, qualche decina di cm)Breve (circa 1 m)Qualche metro; molto di più con RS-485
Moduli tipiciScheda SD, RC522, TFT, nRF24L01, MAX7219OLED, adattatore I2C per LCD, RTC, BME280, MPU6050GPS, HC-05, SIM800L, ESP-01, computer

Spesso la scelta la fa il modulo, ma nei tuoi progetti questa regola aiuta: se contano velocità e quantità di dati (immagini sul display, file, audio) usa SPI; se ti servono pochi fili e tanti sensori lenti usa I2C; se vuoi un collegamento semplice, a testo, tra due dispositivi usa UART. Trovi UART nel dettaglio nell'articolo Comunicazione seriale UART. È molto comune anche usarli tutti e tre nello stesso progetto: per esempio un data logger che legge i sensori via I2C, scrive su una scheda SD via SPI e riceve la posizione da un GPS via UART.

Moduli che usano SPI e idee di progetto

  • Serratura a tessera con registro degli accessi: leggi la tessera con un RC522 e scrivi data e UID su una scheda SD.
  • Registratore di temperatura: salva i dati dei sensori su una microSD in formato CSV e fai un grafico in Excel.
  • Pannello a scritte scorrevoli: mostra ora e messaggi su moduli a matrice LED MAX7219 in cascata.
  • Interfaccia a colori: disegna grafici e menu su un display TFT ILI9341; collega anche il pannello touch allo stesso bus SPI.
  • Radiocomando: invia comandi alla tua auto robot con due moduli nRF24L01.
  • Misura multicanale: costruisci con un MCP3008 un controller MIDI con 8 potenziometri o un impianto di irrigazione con 8 sensori di umidità del terreno.

Errori comuni e soluzioni

SintomoCausa probabileSoluzione
Si legge sempre 0xFF o 0x00MISO non collegato, MOSI e MISO invertiti o dispositivo non alimentatoCollega DIN a MOSI e DOUT a MISO; misura il VCC del dispositivo
Valori senza senso o spostati di un bitModalità SPI sbagliata o clock troppo alto per il dispositivoUsa la modalità del datasheet, abbassa la velocità a 1 MHz e riprova
Due dispositivi che funzionano da soli non funzionano insiemeUn modulo non rilascia MISO o i pin CS non sono HIGH all'avvioPorta prima tutti i CS a HIGH; sostituisci il modulo che non rilascia MISO o usa un bus SPI separato
Lo SPI si blocca all'improvviso sull'UnoD10 è stato usato come ingresso e portato a LOWLascia D10 come uscita; puoi usarlo come CS
L'ESP32 non si avvia con HSPI collegatoGPIO 12 resta HIGH all'avvioSposta il MISO con pull-up su VSPI o scegli un altro pin per MISO
Errori casuali con cavi lunghiRiflessioni e disturbi su un segnale veloceAccorcia i cavi, abbassa la velocità, fai correre un filo GND accanto ai segnali
Un analizzatore logico economico a 8 canali è utilissimo per vedere cosa succede sul bus SPI: registra insieme SCK, MOSI, MISO e CS e decodifica quale byte è uscito e quale è tornato. Nel momento in cui dici "il codice è giusto ma non funziona", ti mostra in pochi secondi se il problema è nei collegamenti o nelle impostazioni.

SPI è la lingua comune dei moduli veloci del mondo Arduino, dalle schede SD ai display a colori: una volta imparati i quattro fili, la logica del CS e le quattro modalità, collegare un nuovo modulo SPI è questione di minuti. Nell'app BlueGrays trovi i progetti di lettura di tessere RFID e serratura, registratore di temperatura su microSD e orologio a matrice di punti MAX7219, passo dopo passo con schemi del circuito e codice.

Domande frequenti

Cosa significa SPI?

SPI è la sigla di Serial Peripheral Interface (interfaccia seriale per periferiche). Permette a un controller di scambiare dati in modo veloce e sincrono con le periferiche su quattro linee: SCK, MOSI, MISO e CS.

Cosa sono MOSI e MISO?

MOSI (Master Out Slave In) è la linea dati dal controller alla periferica; MISO (Master In Slave Out) è la linea dati dalla periferica di ritorno al controller. Nella nuova terminologia si chiamano anche COPI e CIPO. Sui moduli, DIN di solito va a MOSI e DOUT a MISO.

Quali sono i pin SPI di Arduino Uno?

Su Arduino Uno e Nano, SCK è D13, MISO è D12, MOSI è D11 e il CS predefinito è D10. Le stesse linee si trovano anche sul connettore ICSP a 6 pin della scheda. Su Arduino Mega sono SCK D52, MISO D50, MOSI D51 e CS D53.

Che differenza c'è tra SPI e I2C?

SPI usa quattro fili, è full duplex e può funzionare a decine di MHz; ogni dispositivo ha bisogno del suo filo CS. I2C usa solo due fili e seleziona i dispositivi tramite indirizzo, ma lavora a velocità molto più basse, come 100–400 kHz, e richiede resistenze di pull-up.

Quanti dispositivi si possono collegare a un bus SPI?

Non c'è un limite teorico; basta avere un pin CS libero sul controller per ogni dispositivo. In pratica a velocità elevate nascono problemi quando crescono la capacità del bus e la lunghezza dei cavi. Se i pin non bastano, puoi moltiplicare le linee CS con un decoder 74HC138 o usare dispositivi collegabili in cascata.

Perché scheda SD e RFID non funzionano sullo stesso bus SPI?

Il traslatore di livello di molti moduli SD economici non rilascia la linea MISO nemmeno con CS a HIGH e rovina la risposta dell'RC522. Si risolve usando un modulo che rilascia correttamente MISO, collegando il pin di abilitazione del buffer al CS oppure, sull'ESP32, mettendo i due dispositivi su bus SPI separati.

Vedi tutti i progetti
Lettura del valore RFID
#53Principiante
Premium

Lettura del valore RFID

Il portachiavi del condominio o la tessera d'ingresso nascondono un numero di identificazione segreto, e questo progetto lo legge. Avvicina la tessera al lettore RFID e l'Arduino scrive il suo numero

4.7(47)
61
Autenticazione RFID
#54Intermedio
Premium

Autenticazione RFID

Come l'ingresso con tessera di un condominio: avvicini la tua tessera al lettore RFID e l'Arduino confronta il suo numero con quello salvato. Con la tessera giusta il LED verde resta acceso tre second

4.8(64)
83
Lettore di schede RFID RC522 per ESP32 (con LCD)
#123Intermedio

Lettore di schede RFID RC522 per ESP32 (con LCD)

In questo progetto collegheremo il modulo RFID RC522 basato su MFRC522 all'ESP32 tramite SPI per leggere l'UID della tessera o dell'etichetta. Costituisce la base per applicazioni quali serrature, sistemi di abbonamento e controllo degli accessi. Visualizzeremo l'UID letto su un display LCD; questa versione non lo confronta con un elenco di tessere autorizzate. ATTENZIONE: l'RC522 funziona solo a 3,3 V; a 5 V il modulo si brucerà!

4.8(21)
39
Serratura RFID ESP32 (RC522 + servomotore + OLED + cicalino + LED)
#137Avanzato
Premium

Serratura RFID ESP32 (RC522 + servomotore + OLED + cicalino + LED)

Realizziamo una serratura intelligente utilizzando un modulo RFID RC522 con ESP32, un servomotore SG90, un display OLED SSD1306, un cicalino attivo e 2 LED. Quando viene letta una tessera, il codice UID viene confrontato con l’elenco delle tessere autorizzate definito nel sistema: se autorizzata, il servomotore ruota sbloccando la serratura (LED verde + 2 brevi bip); dopo 5 secondi, la serratura si blocca automaticamente. In caso di tessera non autorizzata, si accende il LED rosso, viene emesso

4.8(9)
15
Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avanzato
Premium

Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)

Costruisci un data logger di temperatura con timestamp usando ESP32! Leggi temperatura/umidità dal DHT22 ogni minuto, ottieni l'ora reale dal DS1307 RTC e registra su scheda microSD in formato CSV. L'OLED mostra dal vivo temperatura (font grande), percentuale di umidità, timestamp e contatore di log. Il file /temp_log.csv sulla scheda SD si apre in Excel, Google Sheets o Python pandas per l'analisi — perfetto per il monitoraggio di serre, tracciamento della temperatura domestica, raccolta

4.7(7)
12
Orologio e calendario a matrice di punti (MAX7219, DS1307)
#84Intermedio
Premium

Orologio e calendario a matrice di punti (MAX7219, DS1307)

Un pannello luminoso per la scrivania o la parete che mostra ora e data con scritte scorrevoli. Sul display LED 8x32 c'è un orologio a cifre grandi con i due punti che lampeggiano ogni secondo; all'in

5.0(37)
59
Animazione e testo LED a matrice 4x 32x8
#90Intermedio
Premium

Animazione e testo LED a matrice 4x 32x8

Impilando quattro lunghi moduli a matrice di LED ottieni uno schermo quadrato con più di mille punti luminosi. Prima le lettere cadono dall'alto come una pioggia da film, poi si apre un sipario e due

4.6(40)
66
Serpente di pixel Matrice 8x8
#88Avanzato
Premium

Serpente di pixel Matrice 8x8

Costruisci con le tue mani il classico gioco del serpente e giocaci. Su una matrice di luci colorate 8x8 guidi un serpente verde con un joystick e mangi mele rosse; a ogni mela il serpente si allunga,

4.7(39)
57