Voltar

Domine Serial, I2C e SPI no Arduino com Velxio

Introdução

Protocolos de comunicação são a espinha dorsal dos sistemas embarcados. Seja lendo um sensor, comunicando-se com um cartão SD ou imprimindo mensagens de depuração, você está usando um dos três principais protocolos: Serial (UART), I2C (TWI) ou SPI. Neste tutorial, executaremos todos os três simultaneamente em um Arduino Uno usando o simulador online Velxio. Você verá como escanear o barramento I2C, ler/gravar uma EEPROM, realizar transferências SPI e registrar tudo via Serial.

Diagrama do circuito do multi-protocolo na tela do simulador Velxio

Explicação do Circuito

Este exemplo usa apenas a própria placa Arduino Uno — nenhum componente externo é necessário. Os periféricos integrados do Arduino fornecem tudo que precisamos:

Nenhuma conexão é necessária porque todas as conexões são internas ao Arduino. A tela do Velxio mostra o Uno com seus rótulos de pino, e você pode inspecionar os componentes virtuais abrindo o seletor de componentes.

Modal do seletor de componentes do Velxio navegando por categorias de peças

Explicação do Código

Vamos detalhar o sketch passo a passo.

Bibliotecas e Definições

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

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

Incluímos a biblioteca Wire para I2C e a biblioteca SPI para SPI. Dois endereços I2C são definidos: 0x68 para um RTC DS1307 (embora não esteja fisicamente presente, vamos escaneá-lo) e 0x50 para uma EEPROM 24Cxx. O pino de seleção de escravo SPI é configurado como pino digital 10.

Funções 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);
}

A função bcdToDec converte Decimal Codificado em Binário (BCD) para decimal. readRTC lê os segundos, minutos e horas de um RTC DS1307. As máscaras & 0x7F e & 0x3F limpam bits não 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;
}

Essas funções escrevem e leem um único byte de uma EEPROM I2C no endereço 0x50. O delay(5) garante que a EEPROM tenha tempo para completar o ciclo de gravação.

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

Esta função realiza uma transferência SPI full‑duplex: ela coloca SS em nível baixo, envia um byte, recebe a resposta e coloca SS em nível alto.

Setup

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

  Serial.println("===================================");
  Serial.println(" Demonstração Multi-Protocolo");
  Serial.println(" Serial (USART) + I2C (TWI) + SPI");
  Serial.println("===================================");
  Serial.println();

  // ── I2C: Escanear barramento ──
  Serial.println("[I2C] Escaneando barramento...");
  int found = 0;
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("  Dispositivo encontrado em 0x");
      if (addr < 16) Serial.print("0");
      Serial.println(addr, HEX);
      found++;
    }
  }
  Serial.print("  ");
  Serial.print(found);
  Serial.println(" dispositivo(s) no barramento I2C.");
  Serial.println();

  // ── I2C: Gravar/ler EEPROM ──
  Serial.println("[I2C] Teste de gravação/leitura de EEPROM:");
  writeEEPROM(0, 42);
  writeEEPROM(1, 99);
  byte v0 = readEEPROM(0);
  byte v1 = readEEPROM(1);
  Serial.print("  Gravou 42, leu ");
  Serial.print(v0);
  Serial.println(v0 == 42 ? " [OK]" : " [FALHA]");
  Serial.print("  Gravou 99, leu ");
  Serial.print(v1);
  Serial.println(v1 == 99 ? " [OK]" : " [FALHA]");
  Serial.println();

  // ── SPI: Teste de transferência ──
  Serial.println("[SPI] Teste de transferência:");
  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 concluído. Lendo RTC...");
  Serial.println();
}

No setup(), inicializamos todos os três protocolos. Em seguida, fazemos:

  1. Escanear o barramento I2C em busca de dispositivos do endereço 1 ao 126.
  2. Testar a EEPROM gravando os valores 42 e 99 nos endereços 0 e 1, depois lendo-os de volta e verificando.
  3. Testar SPI enviando três bytes (0xAA, 0x55, 0x42) e imprimindo os bytes recebidos.

Loop

void loop() {
  // ── Serial: Imprimir hora do RTC a cada 2 segundos ──
  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("  |  Tempo de atividade: ");
  Serial.print(millis() / 1000);
  Serial.println("s");

  delay(2000);
}

A cada dois segundos, o loop lê a hora do RTC e a imprime junto com o tempo de atividade do sistema. Isso demonstra a saída Serial contínua enquanto I2C e SPI estão ociosos.

Conceitos Principais

Armadilhas Comuns e Dicas de Depuração

Extensões Sugeridas

  1. Adicionar Sensores Reais: Conecte um RTC DS1307 e uma EEPROM 24Cxx ao barramento I2C, e um módulo de cartão SD via SPI.
  2. Registrar Dados na EEPROM: Armazene leituras de sensores e recupere-as após um reset.
  3. Usar Interrupções: Acione uma transferência SPI ao pressionar um botão.
  4. Implementar uma Interface de Comandos: Analise comandos Serial para controlar operações I2C e SPI.

Experimente Você Mesmo

Pronto para ver todos os três protocolos em ação? Abra o exemplo ao vivo no Velxio, compile e execute. Observe a saída do Monitor Serial enquanto o Arduino escaneia o barramento I2C, testa a EEPROM, realiza transferências SPI e, em seguida, imprime continuamente a hora do RTC.

Iniciar a Demonstração Multi-Protocolo no Velxio

Barra de ferramentas do editor Velxio com controles de compilar e executar Barra de ferramentas da tela do Velxio acima da janela de simulação

Feliz programação!


Compartilhar em:
David Montero

Escrito por

David Montero

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

GitHub velxio.dev

Artigos relacionados


Artigo anterior
Piscar um LED no Raspberry Pi Pico com o Simulador Velxio
Próximo artigo
Teste de Loopback SPI: Domine o Protocolo com a Velxio