Indietro

Padroneggia Serial, I2C e SPI su Arduino con Velxio

Introduzione

I protocolli di comunicazione sono il fondamento dei sistemi embedded. Che tu stia leggendo un sensore, comunicando con una scheda SD o stampando messaggi di debug, stai utilizzando uno dei tre principali protocolli: Serial (UART), I2C (TWI) o SPI. In questo tutorial, eseguiremo tutti e tre simultaneamente su un Arduino Uno utilizzando il simulatore in-browser Velxio. Vedrai come scansionare il bus I2C, leggere/scrivere una EEPROM, eseguire trasferimenti SPI e registrare tutto tramite Serial.

Schema elettrico del multi-protocollo sul canvas del simulatore Velxio

Analisi del Circuito

Questo esempio utilizza solo la scheda Arduino Uno stessa — non sono necessari componenti esterni. Le periferiche integrate di Arduino forniscono tutto ciò di cui abbiamo bisogno:

Non è necessario alcun cablaggio perché tutte le connessioni sono interne ad Arduino. Il canvas di Velxio mostra l’Uno con le etichette dei pin e puoi ispezionare i componenti virtuali aprendo il selettore dei componenti.

Finestra modale del selettore componenti di Velxio che sfoglia le parti per categoria

Analisi del Codice

Analizziamo lo sketch passo dopo passo.

Librerie e Definizioni

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

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

Includiamo la libreria Wire per I2C e la libreria SPI per SPI. Sono definiti due indirizzi I2C: 0x68 per un RTC DS1307 (anche se non fisicamente presente, lo scanneremo) e 0x50 per una EEPROM 24Cxx. Il pin slave select SPI è impostato sul pin digitale 10.

Funzioni di Supporto

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 funzione bcdToDec converte il codice binario decimale (BCD) in decimale. readRTC legge secondi, minuti e ore da un RTC DS1307. I mascheramenti & 0x7F e & 0x3F cancellano i bit inutilizzati.

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;
}

Queste funzioni scrivono e leggono un singolo byte da una EEPROM I2C all’indirizzo 0x50. Il delay(5) garantisce che la EEPROM abbia il tempo di completare il ciclo di scrittura.

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

Questa funzione esegue un trasferimento SPI full‑duplex: porta SS a LOW, invia un byte, riceve la risposta e riporta SS a 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();
}

In setup(), inizializziamo tutti e tre i protocolli. Poi:

  1. Scansioniamo il bus I2C per dispositivi dagli indirizzi 1 a 126.
  2. Testiamo la EEPROM scrivendo i valori 42 e 99 agli indirizzi 0 e 1, poi leggendoli e verificandoli.
  3. Testiamo SPI inviando tre byte (0xAA, 0x55, 0x42) e stampando i byte ricevuti.

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);
}

Ogni due secondi, il loop legge l’ora dall’RTC e la stampa insieme al tempo di attività del sistema. Questo dimostra l’output Serial continuo mentre I2C e SPI sono inattivi.

Concetti Chiave

Insidie Comuni e Suggerimenti per il Debug

Estensioni Suggerite

  1. Aggiungi Sensori Reali: Collega un RTC DS1307 e una EEPROM 24Cxx al bus I2C, e un modulo scheda SD tramite SPI.
  2. Registra Dati sulla EEPROM: Memorizza letture dei sensori e recuperale dopo un reset.
  3. Usa Interrupt: Attiva un trasferimento SPI alla pressione di un pulsante.
  4. Implementa un Interfaccia a Comandi: Analizza comandi Serial per controllare le operazioni I2C e SPI.

Provalo Tu Stesso

Pronto a vedere tutti e tre i protocolli in azione? Apri l’esempio live in Velxio, compila ed esegui. Osserva l’output del Monitor Seriale mentre Arduino scansiona il bus I2C, testa la EEPROM, esegue trasferimenti SPI e poi stampa continuamente l’ora dell’RTC.

Avvia la Demo Multi-Protocollo su Velxio

Barra degli strumenti dell'editor Velxio con controlli di compilazione ed esecuzione Barra degli strumenti del canvas Velxio sopra il viewport di simulazione

Buon hacking!


Condividi su:
David Montero

Scritto da

David Montero

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

GitHub velxio.dev

Articoli correlati


Articolo precedente
Lampeggiare un LED su Raspberry Pi Pico con il Simulatore Velxio
Articolo successivo
Test di Loopback SPI: Padroneggia il Protocollo con Velxio