¿Qué es SPI? Pines MOSI, MISO, SCK y CS en Arduino, paso a paso
Qué es SPI y cómo funciona: pines MOSI, MISO, SCK y CS, modos y velocidad, varios dispositivos, pines de Uno, Mega, ESP32 y Pico, y el choque entre SD y RFID.
SPI (Serial Peripheral Interface, interfaz periférica serie) es un método de comunicación que permite a un microcontrolador intercambiar datos muy rápido con dispositivos como tarjetas SD, lectores RFID, pantallas TFT a color o módulos inalámbricos a través de cuatro cables. Hay una línea de reloj (SCK), dos líneas separadas para los datos en cada sentido (MOSI y MISO) y una línea CS que elige con qué dispositivo se habla. Como puede ser decenas de veces más rápido que I2C, es el bus preferido por los módulos que mueven muchos datos.
En este artículo aprenderás cómo funciona SPI, los nombres de los pines y la nueva nomenclatura, los cuatro modos SPI, los límites de velocidad, los pines de Arduino Uno, Mega, ESP32 (VSPI y HSPI) y Raspberry Pi Pico, cómo conectar varios dispositivos al mismo bus y por qué una tarjeta SD y un lector RFID RC522 dan problemas juntos. En la última sección comparamos SPI con I2C y UART.
¿Qué es SPI y cómo funciona?
En SPI siempre hay un controlador (antes llamado maestro) y uno o más periféricos (antes llamados esclavos). Solo el controlador genera el reloj; es decir, el Arduino inicia la conversación, fija la velocidad y la termina. En cada pulso de reloj el controlador envía un bit por MOSI y, al mismo tiempo, el periférico devuelve un bit por MISO. Los registros de desplazamiento de los dos lados forman una especie de anillo: tras 8 pulsos, el byte del controlador ha pasado al periférico y el del periférico al controlador. Por eso SPI es full duplex: leer y escribir ocurre a la vez.
| Línea | Nombre antiguo | Nombre nuevo | Sentido | Función |
|---|---|---|---|---|
| SCK / SCLK | Serial Clock | SCK | Controlador → periférico | Señal de reloj; en cada pulso viaja un bit |
| MOSI | Master Out Slave In | COPI / SDO | Controlador → periférico | Datos del Arduino al módulo |
| MISO | Master In Slave Out | CIPO / SDI | Periférico → controlador | Datos del módulo de vuelta al Arduino |
| CS / SS | Slave Select | CS (Chip Select) | Controlador → periférico | Mientras está en LOW, ese módulo escucha; cada dispositivo tiene su propio CS |
Las serigrafías de los módulos no siempre coinciden y esa es la mayor fuente de confusión. En el módulo RFID RC522 la línea CS se llama SDA (no tiene nada que ver con el SDA de I2C), en el nRF24L01 CSN, en el MCP3008 CS/SHDN, y en algunas pantallas verás nombres como DIN (MOSI), CLK (SCK) y DOUT (MISO). La regla es sencilla: la entrada de datos (DIN, SDI, MOSI) va al MOSI del Arduino y la salida de datos (DOUT, SDO, MISO) va al MISO del Arduino.
- El controlador pone en LOW la línea CS del dispositivo con el que quiere hablar. Todos los demás dejan su CS en HIGH y liberan la línea MISO.
- El controlador empieza a generar pulsos de reloj en SCK.
- En cada pulso sale un bit por MOSI y entra un bit por MISO. El orden suele ser primero el bit más significativo (MSB first).
- Cuando se han transferido los bytes necesarios (comando, dirección, datos), el controlador vuelve a poner CS en HIGH y el dispositivo completa la operación.
Modos SPI: CPOL y CPHA
SPI no tiene un estándar único; los dispositivos se diferencian en el nivel en que reposa el reloj (CPOL, polaridad del reloj) y en el flanco del reloj en el que se leen los datos (CPHA, fase del reloj). Las cuatro combinaciones de estos dos ajustes forman los cuatro modos SPI. Si el controlador y el dispositivo no están en el mismo modo, los datos se desplazan un bit y lees valores sin sentido. Por suerte, la gran mayoría de los módulos usa el modo 0.
| Modo | CPOL | CPHA | Reloj en reposo | Flanco de lectura | Dispositivos de ejemplo |
|---|---|---|---|---|---|
| SPI_MODE0 | 0 | 0 | LOW | Subida | Tarjeta SD, RC522, nRF24L01, MAX7219, MCP3008, 74HC595 |
| SPI_MODE1 | 0 | 1 | LOW | Bajada | Algunos ADC e integrados de control |
| SPI_MODE2 | 1 | 0 | HIGH | Bajada | Poco habitual |
| SPI_MODE3 | 1 | 1 | HIGH | Subida | Acelerómetro ADXL345, algunas pantallas ST7789 sin pin CS |
Velocidad SPI y longitud de los cables
En SPI la velocidad la fija el controlador y el límite suele ponerlo el propio dispositivo. El Arduino Uno puede llegar a 8 MHz, la mitad de su reloj de 16 MHz; el valor por defecto de la librería SPI es 4 MHz. El ESP32 puede generar hasta 80 MHz en sus pines SPI propios (IO_MUX), y el límite baja si la señal se lleva a otros pines a través de la matriz GPIO. La Raspberry Pi Pico llega a unos 62,5 MHz con un reloj de sistema de 125 MHz. Las señales SPI rápidas necesitan cables cortos: con una protoboard y cables dupont de 10–20 cm, unos pocos MHz no dan problemas; a partir de 20–30 MHz mantén los cables cortos y, si puedes, usa conexiones soldadas. Varios metros de cable no son adecuados para SPI.
| Dispositivo | Función | Reloj SPI máximo (hoja de datos) | Modo SPI |
|---|---|---|---|
| Tarjeta microSD | Registro de datos | 400 kHz al iniciar, luego hasta 25 MHz | Modo 0 |
| RC522 (MFRC522) | Lector RFID | 10 MHz | Modo 0 |
| nRF24L01 | Radio de 2,4 GHz | 10 MHz | Modo 0 |
| MAX7219 | Matriz LED / 7 segmentos | 10 MHz | Modo 0 |
| MCP3008 | ADC de 8 canales y 10 bits | 3,6 MHz a 5 V, 1,35 MHz a 2,7 V | Modo 0 o 3 |
| ILI9341 | TFT a color de 2,4–3,2 pulgadas | 10 MHz en escritura (en la práctica se usa mucho más rápido) | Modo 0 |
Pines SPI: Arduino Uno, Mega, ESP32 y Raspberry Pi Pico
| Línea | Arduino Uno / Nano | Arduino Mega | ESP32 VSPI (por defecto) | 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 (por defecto) | D10 | D53 | GPIO 5 | GPIO 15 | GP17 |
| Nivel lógico | 5 V | 5 V | 3,3 V | 3,3 V | 3,3 V |
En el Uno las mismas líneas SPI también están en el conector ICSP de 6 pines del borde de la placa; en placas como Leonardo y Micro, SPI solo está en el ICSP. Para CS no es obligatorio usar D10: sirve cualquier pin digital. Pero en el Uno no dejes D10 como entrada: si el hardware SPI lee LOW en D10 mientras es entrada, sale del modo controlador. SPI.begin() configura este pin como salida automáticamente, y no deberías convertirlo en entrada para otra tarea. En el ESP32 el objeto SPI de Arduino usa VSPI por defecto; gracias a la matriz GPIO también puedes mover SPI a casi cualquier pin. En la Pico, SPI0 y SPI1 pueden asignarse a varios grupos de pines (p. ej. GP10, GP11, GP12 para SPI1); tienes los detalles en la herramienta Pinout.
La librería SPI de Arduino: funciones básicas
| Función | ¿Qué hace? |
|---|---|
| SPI.begin() | Inicia el hardware SPI; pone como salidas los pines SCK, MOSI y SS. |
| SPISettings(velocidad, MSBFIRST, SPI_MODE0) | Guarda en un objeto la velocidad, el orden de bits y el modo de un dispositivo. |
| SPI.beginTransaction(ajustes) | Aplica los ajustes y reserva el bus para ese dispositivo; hace seguro el paso entre dispositivos con ajustes distintos. |
| SPI.transfer(byte) | Envía un byte y devuelve el byte recibido al mismo tiempo. |
| SPI.transfer16(valor) | Envía y recibe un valor de 16 bits de una vez. |
| SPI.transfer(búfer, longitud) | Envía un array; los bytes recibidos sobrescriben el mismo array. |
| SPI.endTransaction() | Libera el bus; se llama después de poner CS en HIGH. |
Primer ejemplo: enviar datos a un 74HC595 por SPI
La forma más fácil de entender SPI es con un registro de desplazamiento 74HC595, porque el 595 es en realidad el periférico SPI más simple, uno sin MISO. El pin MOSI del Arduino va a la entrada DS del 595, SCK a SH_CP y D10 a ST_CP, que hace de latch. A diferencia de la función shiftOut(), el SPI por hardware envía el byte en pocos microsegundos:
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}Leer datos por SPI: el ADC MCP3008
Para ver la comunicación full duplex usaremos el MCP3008. Este integrado añade al Arduino 8 entradas analógicas más de 10 bits; es una buena alternativa al ADC poco lineal del ESP32 o a las solo 3 entradas analógicas de la Pico. Explicamos los fundamentos de la lectura analógica en el artículo ¿Qué es un ADC?. Conexión: CLK → D13, DOUT → D12, DIN → D11, CS → D10, VDD y VREF → 5V, AGND y 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}Aquí enviamos tres bytes y recibimos tres bytes a la vez. El primer byte (0x01) es solo el bit de inicio; en el segundo van el modo de entrada simple y el número de canal, mientras el MCP3008 devuelve los 2 bits altos del resultado. El tercer byte es 0x00; su contenido da igual, solo se envía para generar pulsos de reloj y recibir los 8 bits restantes del resultado. En SPI, "leer" siempre significa enviar algo. El resultado está entre 0 y 1023 y se convierte a voltios respecto a VREF (aquí 5 V).
Varios dispositivos SPI: líneas CS separadas
La mayor diferencia de SPI con I2C es que no usa direcciones. Los dispositivos comparten las líneas SCK, MOSI y MISO, y cada uno recibe su propio cable CS desde el Arduino. Solo escucha el dispositivo cuyo CS está en LOW, y solo ese escribe datos en MISO. Tres dispositivos necesitan 3 + 3 = 6 cables, cinco dispositivos 3 + 5 = 8; el número de pines crece con el de dispositivos. Algunos integrados como el 74HC595 y el MAX7219 pueden encadenarse (daisy chain): la salida de uno va a la entrada del siguiente y todos se controlan con un solo CS.
- Solo un CS en LOW a la vez. Si se seleccionan dos dispositivos juntos, chocan en la línea MISO y lees datos corruptos de los dos.
- En setup(), pon primero todos los pines CS como salida y en HIGH, y después inicia las librerías. Un pin CS al aire puede verse en LOW al azar y ocupar el bus.
- Usa beginTransaction para cada dispositivo. Una tarjeta SD puede querer 25 MHz y un MCP3008 1 MHz; las transacciones aplican la velocidad y el modo correctos en cada cambio.
- Si usas SPI dentro de interrupciones, avisa a la librería con SPI.usingInterrupt() o no hagas operaciones SPI dentro de la interrupción.
- Una pull-up de 10 kΩ en la línea CS de cada dispositivo evita que los dispositivos se seleccionen solos mientras el Arduino arranca o se reinicia.
Tarjeta SD y RFID en el mismo bus: ¿por qué no funciona?
Una pregunta clásica de los foros de Arduino: el RFID RC522 funciona solo, el módulo de tarjeta SD funciona solo, pero al conectarlos al mismo bus SPI uno de ellos o los dos se callan. Aunque los pines CS estén bien en el software, el problema suele estar en el hardware. Muchos módulos SD baratos llevan un búfer 74LVC125 que convierte las señales de 5 V a 3,3 V, y el canal de ese integrado que maneja la línea MISO está siempre activado. Así que, aunque el CS de la tarjeta SD esté en HIGH, el módulo no suelta MISO; cuando el RC522 intenta responder, dos salidas se pelean por la línea.
- Elige el módulo adecuado: los módulos que ponen MISO en alta impedancia cuando CS está en HIGH comparten el bus sin problemas. Puedes saber si un módulo libera la línea tirando de MISO con 10 kΩ primero a GND y luego a 5 V, con CS en HIGH, y midiendo con el multímetro.
- Conecta el pin de habilitación del búfer a CS: si sabes soldar, separar de GND el pin OE del canal MISO del 74LVC125 y llevarlo a la línea CS del módulo soluciona el problema de raíz.
- Pon una resistencia en serie en MISO: una resistencia de unos 1 kΩ en serie con la salida MISO del módulo SD permite que el RC522 imponga su señal. Es un apaño fácil, pero limita la velocidad.
- Usa un bus SPI separado: en el ESP32, si conectas la tarjeta SD a VSPI y el RC522 a HSPI, los dos dispositivos nunca coinciden. El Uno no tiene un segundo SPI por hardware, así que allí no existe esta opción.
- Cuida el orden de arranque: pon primero todos los CS en HIGH, luego llama a SPI.begin() y después a SD.begin() y PCD_Init(). El ejemplo de abajo sigue este orden.
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}En este código la librería SD y la librería MFRC522 ponen sus propios pines CS en LOW y HIGH; lo único que tienes que hacer es dejar los dos en HIGH al principio y asegurarte de que el hardware comparte MISO correctamente. El código escribe el UID de cada tarjeta leída, junto con una marca de tiempo, en el archivo kartlar.txt. En el Uno estas dos librerías usan juntas cerca de la mitad de la RAM; la macro F() libera espacio guardando los textos fijos en la flash.
VSPI y HSPI en el ESP32: dos buses SPI separados
El ESP32 tiene cuatro unidades SPI; SPI0 y SPI1 están reservadas para la flash interna, así que te quedan VSPI (SPI3) y HSPI (SPI2). Usar las dos es la forma más limpia de separar dispositivos con velocidades y modos muy distintos o de librarte del choque en MISO que hemos visto. En el núcleo de Arduino creas un objeto SPIClass para el segundo bus y le das sus pines con begin(). El código de abajo usa la tarjeta SD en el VSPI por defecto y el MCP3008 en HSPI, y añade cada segundo una medida a un archivo CSV:
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}SPI con la Raspberry Pi Pico (MicroPython)
La Pico tiene dos unidades SPI por hardware (SPI0 y SPI1), que en MicroPython se usan con la clase machine.SPI. Los parámetros polarity y phase corresponden a CPOL y CPHA; si los dos valen 0, es el modo 0. El CS lo manejas tú como un pin de salida normal. La función write_readinto() es la que mejor muestra el carácter full duplex de SPI: mientras envía un array, escribe los bytes que llegan en otro. Leamos el mismo MCP3008, esta vez alimentado a 3,3 V:
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 y UART: comparación
| Característica | SPI | I2C | UART |
|---|---|---|---|
| Número de cables | 4 (+1 CS por cada dispositivo extra) | 2 (SDA, SCL) | 2 (TX, RX) |
| Velocidad típica | 1–80 MHz | 100 kHz, 400 kHz, 1 MHz | 9600–115200 baudios (hasta unos pocos Mbit/s) |
| Reloj | Sí (lo genera el controlador) | Sí (lo genera el controlador) | No; los dos lados acuerdan la misma velocidad en baudios |
| Sentido | Full duplex | Half duplex | Full duplex |
| Selección de dispositivo | Cable CS propio | Dirección de 7 bits | Solo dos dispositivos (punto a punto) |
| Componentes extra | No hacen falta | Resistencias pull-up | No hacen falta |
| Distancia | Corta (en la placa, unas decenas de cm) | Corta (alrededor de 1 m) | Unos metros; mucho más con RS-485 |
| Módulos típicos | Tarjeta SD, RC522, TFT, nRF24L01, MAX7219 | OLED, adaptador I2C para LCD, RTC, BME280, MPU6050 | GPS, HC-05, SIM800L, ESP-01, ordenador |
Normalmente la elección la hace el módulo, pero en tus propios diseños esta regla ayuda: si importan la velocidad y la cantidad de datos (imágenes en pantalla, archivos, audio), usa SPI; si necesitas pocos cables y muchos sensores lentos, usa I2C; si quieres un enlace sencillo basado en texto entre dos dispositivos, usa UART. Tienes UART en detalle en el artículo Comunicación serie UART. También es muy habitual usar los tres en el mismo proyecto: por ejemplo, un registrador de datos que lee sensores por I2C, escribe en una tarjeta SD por SPI y recibe la posición de un GPS por UART.
Módulos que usan SPI e ideas de proyectos
- Cerradura con tarjeta y registro de accesos: lee la tarjeta con un RC522 y escribe la fecha y el UID en una tarjeta SD.
- Registrador de temperatura: guarda datos de sensores en una microSD en formato CSV y haz gráficas en Excel.
- Panel de texto deslizante: muestra la hora y mensajes en módulos de matriz LED MAX7219 encadenados.
- Interfaz a color: dibuja gráficos y menús en una pantalla TFT ILI9341; conecta también el panel táctil al mismo bus SPI.
- Mando inalámbrico: envía órdenes a tu coche robot con dos módulos nRF24L01.
- Medida multicanal: monta con un MCP3008 un controlador MIDI de 8 potenciómetros o un sistema de riego con 8 sensores de humedad del suelo.
Errores frecuentes y soluciones
| Síntoma | Causa probable | Solución |
|---|---|---|
| Siempre se lee 0xFF o 0x00 | MISO sin conectar, MOSI y MISO intercambiados o el dispositivo sin alimentación | Conecta DIN a MOSI y DOUT a MISO; mide el VCC del dispositivo |
| Valores sin sentido o desplazados un bit | Modo SPI incorrecto o reloj demasiado rápido para el dispositivo | Usa el modo de la hoja de datos, baja la velocidad a 1 MHz y vuelve a probar |
| Dos dispositivos que funcionan solos no funcionan juntos | Un módulo no libera MISO o los pines CS no están en HIGH al inicio | Pon todos los CS en HIGH primero; cambia el módulo que no libera MISO o usa un bus SPI separado |
| El SPI se detiene de repente en el Uno | D10 se ha usado como entrada y se ha puesto en LOW | Deja D10 como salida; puedes usarlo como CS |
| El ESP32 no arranca con HSPI conectado | GPIO 12 queda en HIGH al arrancar | Lleva el MISO con pull-up a VSPI o elige otro pin para MISO |
| Errores aleatorios con cables largos | Reflexiones y ruido en una señal rápida | Acorta los cables, baja la velocidad, lleva un cable de GND junto a las señales |
SPI es el idioma común de los módulos rápidos del mundo Arduino, desde tarjetas SD hasta pantallas a color: cuando conoces los cuatro cables, la lógica del CS y los cuatro modos, conectar un módulo SPI nuevo es cuestión de minutos. En la app BlueGrays encontrarás los proyectos de lectura de tarjetas RFID y cerradura, registrador de temperatura en microSD y reloj de matriz de puntos MAX7219, paso a paso con esquemas de circuito y código.
Preguntas frecuentes
¿Qué significa SPI?
SPI son las siglas de Serial Peripheral Interface (interfaz periférica serie). Permite que un controlador intercambie datos de forma rápida y síncrona con periféricos a través de cuatro líneas: SCK, MOSI, MISO y CS.
¿Qué son MOSI y MISO?
MOSI (Master Out Slave In) es la línea de datos del controlador al periférico; MISO (Master In Slave Out) es la línea de datos del periférico de vuelta al controlador. En la nomenclatura nueva también se llaman COPI y CIPO. En los módulos, DIN suele ir a MOSI y DOUT a MISO.
¿Cuáles son los pines SPI del Arduino Uno?
En el Arduino Uno y el Nano, SCK es D13, MISO es D12, MOSI es D11 y el CS por defecto es D10. Las mismas líneas están también en el conector ICSP de 6 pines de la placa. En el Arduino Mega son SCK D52, MISO D50, MOSI D51 y CS D53.
¿Qué diferencia hay entre SPI e I2C?
SPI usa cuatro cables, es full duplex y puede funcionar a decenas de MHz; cada dispositivo necesita su propio cable CS. I2C usa solo dos cables y selecciona los dispositivos por dirección, pero funciona a velocidades mucho menores, como 100–400 kHz, y necesita resistencias pull-up.
¿Cuántos dispositivos se pueden conectar a un bus SPI?
No hay un límite teórico; basta con tener un pin CS libre en el controlador por cada dispositivo. En la práctica aparecen problemas a altas velocidades cuando crecen la capacidad del bus y la longitud de los cables. Si te faltan pines, puedes multiplicar las líneas CS con un decodificador 74HC138 o usar dispositivos encadenables.
¿Por qué una tarjeta SD y un RFID no funcionan en el mismo bus SPI?
El conversor de nivel de muchos módulos SD baratos no suelta la línea MISO aunque CS esté en HIGH y estropea la respuesta del RC522. Se soluciona usando un módulo que libere bien MISO, conectando el pin de habilitación del búfer a CS o, en el ESP32, poniendo los dos dispositivos en buses SPI separados.
Proyectos para hacer después de leer esto
Ver todos los proyectos
Lectura de valores RFID
El llavero del portal o la tarjeta de acceso guardan un número de identificación secreto, y este proyecto lo lee. Acerca la tarjeta al lector RFID y el Arduino escribe su número en la pantalla del ord

Autenticación RFID
Como el acceso con tarjeta del portal de un edificio: acercas tu tarjeta al lector RFID y el Arduino compara su número con el que tiene guardado. Con la tarjeta correcta se enciende el LED verde duran

Lector de tarjetas RFID RC522 para ESP32 (con LCD)
En este proyecto, conectaremos el módulo RFID RC522 basado en MFRC522 al ESP32 a través de SPI y leeremos el UID de la tarjeta o etiqueta. Esto constituye la base de aplicaciones como cerraduras, sistemas de afiliación y control de acceso. Mostraremos el UID leído en la pantalla LCD; esta versión no lo compara con una lista de tarjetas autorizadas. ATENCIÓN: El RC522 solo funciona a 3,3 V; si le aplicas 5 V, ¡el módulo se quemará!

Cerradura RFID ESP32 (RC522 + servo + OLED + zumbador + LED)
Vamos a construir una cerradura inteligente utilizando un ESP32, un módulo RFID RC522, un servomotor SG90, una pantalla OLED SSD1306, un zumbador activo y 2 LED. Cuando se lee una tarjeta, su código UID se compara con la lista de tarjetas autorizadas definida en el sistema; si es autorizada, el servomotor gira y se desbloquea la cerradura (LED verde + 2 pitidos cortos), y se vuelve a bloquear automáticamente tras 5 segundos. Si la tarjeta no está autorizada, se enciende el LED rojo, se emite una

Registrador de Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
¡Construye un registrador de temperatura con marca de tiempo con ESP32! Lee temperatura/humedad del DHT22 cada minuto, obtén la hora real del DS1307 RTC y registra en tarjeta microSD como CSV. El OLED muestra en vivo la temperatura (fuente grande), porcentaje de humedad, marca de tiempo y contador de registros. El archivo /temp_log.csv en la tarjeta SD se abre en Excel, Google Sheets o Python pandas para análisis — perfecto para monitoreo de invernadero, seguimiento de temperatura del hog

Reloj y calendario de matriz de puntos (MAX7219, DS1307)
Un panel luminoso para tu mesa o tu pared que muestra la hora y la fecha con texto en movimiento. En la pantalla LED de 8x32 se ve un reloj de números grandes cuyos dos puntos parpadean cada segundo;

4x 32x8 Matriz LED Animación Y Texto
Si apilas cuatro módulos largos de matriz LED, obtienes una pantalla cuadrada con más de mil puntos de luz. Primero caen letras desde arriba como una lluvia de película, luego se abre un telón y en do

Serpiente de píxeles Matriz 8x8
Monta con tus propias manos el clásico juego de la serpiente y juega. En una matriz de luces de colores de 8x8 guías una serpiente verde con un joystick y te comes manzanas rojas; con cada manzana la
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 200 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

