Volver

Domina Serial, I2C y SPI en Arduino con Velxio

Introducción

Los protocolos de comunicación son la base de los sistemas embebidos. Ya sea que estés leyendo un sensor, comunicándote con una tarjeta SD o imprimiendo mensajes de depuración, estás utilizando uno de los tres protocolos principales: Serial (UART), I2C (TWI) o SPI. En este tutorial, ejecutaremos los tres simultáneamente en un Arduino Uno usando el simulador en navegador Velxio. Verás cómo escanear el bus I2C, leer/escribir una EEPROM, realizar transferencias SPI y registrar todo a través de Serial.

Diagrama del circuito de múltiples protocolos en el lienzo del simulador Velxio

Recorrido del Circuito

Este ejemplo utiliza solo la placa Arduino Uno en sí misma — no se requieren componentes externos. Los periféricos integrados del Arduino proporcionan todo lo necesario:

No es necesario cableado porque todas las conexiones son internas al Arduino. El lienzo de Velxio muestra el Uno con sus etiquetas de pines, y puedes inspeccionar los componentes virtuales abriendo el selector de componentes.

Modal del selector de componentes de Velxio navegando piezas por categoría

Explicación del Código

Analicemos el sketch paso a paso.

Librerías y Definiciones

#include <Wire.h>
#include <SPI.h>

#define DS1307_ADDR 0x68
#define EEPROM_ADDR 0x50
#define SS_PIN 10

Incluimos la librería Wire para I2C y la librería SPI para SPI. Se definen dos direcciones I2C: 0x68 para un RTC DS1307 (aunque no está físicamente presente, lo escanearemos) y 0x50 para una EEPROM 24Cxx. El pin de selección de esclavo SPI se establece en el pin digital 10.

Funciones Auxiliares

byte bcdToDec(byte val) {
  return ((val >> 4) * 10) + (val & 0x0F);
}

void readRTC(byte &hr, byte &min, byte &sec) {
  Wire.beginTransmission(DS1307_ADDR);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDR, 3);
  sec = bcdToDec(Wire.read() & 0x7F);
  min = bcdToDec(Wire.read());
  hr  = bcdToDec(Wire.read() & 0x3F);
}

La función bcdToDec convierte Decimal Codificado en Binario a decimal. readRTC lee los segundos, minutos y horas de un RTC DS1307. Las máscaras & 0x7F y & 0x3F limpian los bits no utilizados.

void writeEEPROM(byte reg, byte value) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write(reg);
  Wire.write(value);
  Wire.endTransmission();
  delay(5);
}

byte readEEPROM(byte reg) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(EEPROM_ADDR, 1);
  return Wire.available() ? Wire.read() : 0xFF;
}

Estas funciones escriben y leen un solo byte de una EEPROM I2C en la dirección 0x50. El delay(5) asegura que la EEPROM tenga tiempo para completar el ciclo de escritura.

byte spiTransfer(byte data) {
  digitalWrite(SS_PIN, LOW);
  byte result = SPI.transfer(data);
  digitalWrite(SS_PIN, HIGH);
  return result;
}

Esta función realiza una transferencia SPI full‑dúplex: pone SS en LOW, envía un byte, recibe la respuesta y pone SS en HIGH.

Setup

void setup() {
  Serial.begin(9600);
  Wire.begin();
  pinMode(SS_PIN, OUTPUT);
  digitalWrite(SS_PIN, HIGH);
  SPI.begin();

  Serial.println("===================================");
  Serial.println(" Multi-Protocol Demo");
  Serial.println(" Serial (USART) + I2C (TWI) + SPI");
  Serial.println("===================================");
  Serial.println();

  // ── I2C: Scan bus ──
  Serial.println("[I2C] Scanning bus...");
  int found = 0;
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("  Found device at 0x");
      if (addr < 16) Serial.print("0");
      Serial.println(addr, HEX);
      found++;
    }
  }
  Serial.print("  ");
  Serial.print(found);
  Serial.println(" device(s) on I2C bus.");
  Serial.println();

  // ── I2C: Write/read EEPROM ──
  Serial.println("[I2C] EEPROM write/read test:");
  writeEEPROM(0, 42);
  writeEEPROM(1, 99);
  byte v0 = readEEPROM(0);
  byte v1 = readEEPROM(1);
  Serial.print("  Wrote 42, read ");
  Serial.print(v0);
  Serial.println(v0 == 42 ? " [OK]" : " [FAIL]");
  Serial.print("  Wrote 99, read ");
  Serial.print(v1);
  Serial.println(v1 == 99 ? " [OK]" : " [FAIL]");
  Serial.println();

  // ── SPI: Transfer test ──
  Serial.println("[SPI] Transfer test:");
  byte spiData[] = {0xAA, 0x55, 0x42};
  for (int i = 0; i < 3; i++) {
    byte rx = spiTransfer(spiData[i]);
    Serial.print("  TX=0x");
    if (spiData[i] < 16) Serial.print("0");
    Serial.print(spiData[i], HEX);
    Serial.print(" RX=0x");
    if (rx < 16) Serial.print("0");
    Serial.println(rx, HEX);
  }
  Serial.println();

  Serial.println("Setup complete. Reading RTC...");
  Serial.println();
}

En setup(), inicializamos los tres protocolos. Luego:

  1. Escaneamos el bus I2C en busca de dispositivos desde la dirección 1 hasta 126.
  2. Probamos la EEPROM escribiendo los valores 42 y 99 en las direcciones 0 y 1, luego los leemos y verificamos.
  3. Probamos SPI enviando tres bytes (0xAA, 0x55, 0x42) e imprimiendo los bytes recibidos.

Loop

void loop() {
  // ── Serial: Print RTC time every 2 seconds ──
  byte hr, min, sec;
  readRTC(hr, min, sec);

  Serial.print("[RTC] ");
  if (hr < 10) Serial.print("0");
  Serial.print(hr);
  Serial.print(":");
  if (min < 10) Serial.print("0");
  Serial.print(min);
  Serial.print(":");
  if (sec < 10) Serial.print("0");
  Serial.print(sec);

  Serial.print("  |  Uptime: ");
  Serial.print(millis() / 1000);
  Serial.println("s");

  delay(2000);
}

Cada dos segundos, el bucle lee la hora del RTC y la imprime junto con el tiempo de actividad del sistema. Esto demuestra la salida Serial continua mientras I2C y SPI están inactivos.

Conceptos Clave

Errores Comunes y Consejos de Depuración

Extensiones Sugeridas

  1. Añadir Sensores Reales: Conecta un RTC DS1307 y una EEPROM 24Cxx al bus I2C, y un módulo de tarjeta SD vía SPI.
  2. Registrar Datos en la EEPROM: Almacena lecturas de sensores y recupéralas después de un reinicio.
  3. Usar Interrupciones: Activa una transferencia SPI con la pulsación de un botón.
  4. Implementar una Interfaz de Comandos: Analiza comandos Serial para controlar operaciones I2C y SPI.

Pruébalo Tú Mismo

¿Listo para ver los tres protocolos en acción? Abre el ejemplo en vivo en Velxio, compila y ejecuta. Observa la salida del Monitor Serial mientras el Arduino escanea el bus I2C, prueba la EEPROM, realiza transferencias SPI y luego imprime continuamente la hora del RTC.

Iniciar la Demo Multi-Protocolo en Velxio

Barra de herramientas del editor de Velxio con controles de compilación y ejecución Barra de herramientas del lienzo de Velxio sobre la ventana de simulación

¡Feliz hacking!


Compartir en:
David Montero

Escrito por

David Montero

Creator of Velxio, the open-source circuit and Arduino simulator.

GitHub velxio.dev

Artículos relacionados


Artículo anterior
Parpadeo de un LED en Raspberry Pi Pico con el Simulador Velxio
Artículo siguiente
Prueba de bucle SPI: Domina el protocolo con Velxio