Etiquetas:, , , ,
0
(0)

Estabelecer uma comunicação entre diversos dispositivos pode ser prático, sobretudo em projectos de domótica. Uma técnica empregada com frequência é o protocolo I2C (ou TWI). O protocolo I2C é um método que permite conectar diversas placas mestres e diversas placas escravas, de modo a comunicar até 128 dispositivos. Ele possibilita conexões assíncronas entre diversos componentes, para compartilhar informações por meio de um “barramento comum”.  Já falamos anteriormente sobre a comunicação pela porta serial (dita UART), utilizada para enviar o código ao Arduino através de um computador ou para conectar dois dispositivos em particular via Bluetooth.

Obs.: Vale observar que a comunicação I2C é originalmente concebida para a comunicação entre placas. Assim, ela não é adaptada à comunicação à distância (>1m).

Equipamento

  • Computador
  • Arduino UNO (2 ou mais)
  • Cabos jumper M/M (3 vezes a quantidade de placas)

Esquema de ligação do barramento I2C entre placas Arduino

O protocolo I2C também possibilita estabelecer comunicação entre diferentes sistemas (sensores, ecrã LCD, Raspberry Pi, etc.). Um exemplo interessante é a comunicação entre diversas placas Arduino. Para isso, é preciso escrever ao menos dois programas, um para a placa mestre e outro para as placas escravas.

A comunicação I2C é definida por um barramento de dois fios (também chamado de TWI, Two Wire Interface) e um endereço. Os pinos utilizados pela comunicação I2C normalmente são fixos para cada dispositivo. Há um pino para o envio dos dados (SDA Serial Data Line) e outro para o relógio de sincronização (SLC Serial Clock Line).

Pinos I2C/TWI:

  • Uno, Ethernet A4 (SDA), A5 (SCL)
  • Mega2560 20 (SDA), 21 (SCL)
  • Leonardo 2 (SDA), 3 (SCL)
  • Due 20 (SDA), 21 (SCL), SDA1, SCL1

No exemplo abaixo, utilizamos uma placa Arduino Uno, e portanto os pinos A4 e A5.

Para que as duas placas comuniquem-se entre si, é preciso ligá-las corretamente (A4 com A4 e A5 com A5) e não esquecer de conectar as terras (GND) conforme indicado no esquema a seguir.

Atenção: Se os pinos A4 e A5 forem conectados aos pinos de uma placa não alimentada, o código irá travar no momento da transmissão.

Em geral, uma das placas envia as informações (Writer) e uma outra as recebe (Reader).

Código para configuração do barramento I2C

A biblioteca Wire.h permite definir a comunicação serial no barramento I2C com facilidade. As funções são similares às da biblioteca Serial.

  • Wire.begin() permite configurar o endereço do dispositivo. O argumento da função pode ser vazio para os dispositivos mestres.
  • Wire.write() permite o envio de bytes.
  • Wire.requestFrom() gerencia a função de recepção de solicitações
  • Wire.beginTransmission() inicia a transmissão de dados e define o receptor.
  • Wire.endTransmission termina a transmissão de dados
  • Wire.onRequest() gerencia a função de recepção de solicitações
  • Wire.onRecieve() gerencia a função de recepção de dados

Código da placa Mestre

#include <Wire.h>

# define I2C_SLAVE1_ADDRESS 11
# define I2C_SLAVE2_ADDRESS 12

#define PAYLOAD_SIZE 2

int n = 0;

void setup()
{
  Wire.begin();
  Serial.begin(9600);

  Serial.println(F("-------------------------------------I am the Master"));
  delay(1000);

  //Request value of n to slave
  Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1);
  n = Wire.read();
  Serial.print(F("recieved value : "));
  Serial.println(n);

  //Send value 12 to slave
  Wire.beginTransmission(I2C_SLAVE1_ADDRESS);
  Wire.write(12);
  Serial.print(F("sending value : "));
  Serial.println(12);
  Wire.endTransmission();

  Serial.print(" ");

  //Request value of n to slave after change
  Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1);
  n = Wire.read();
  Serial.print(F(" new recieved value : "));
  Serial.println(n);
}


void loop()
{
  delay(100);
}

Código da placa Escrava

#include <Wire.h>

# define I2C_SLAVE_ADDRESS 11 // 12 pour l'esclave 2 et ainsi de suite

#define PAYLOAD_SIZE 2

void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS);
  Serial.begin(9600);
  Serial.println("-------------------------------------I am Slave1");
  delay(1000);
  Wire.onRequest(requestEvents);
  Wire.onReceive(receiveEvents);
}

void loop() {}

int n = 0;

void requestEvents()
{
  Serial.println(F("---> recieved request"));
  Serial.print(F("sending value : "));
  Serial.println(n);
  Wire.write(n);
}

void receiveEvents(int numBytes)
{
  Serial.println(F("---> recieved events"));
  n = Wire.read();
  Serial.print(numBytes);
  Serial.println(F("bytes recieved"));
  Serial.print(F("recieved value : "));
  Serial.println(n);
}



Abra o monitor serial das placas escravas antes do monitor da placa mestre.

No monitor serial da placa mestre:

No monitor serial da placa Escrava 1:

Podemos observar que as duas placas trocam informações. É muito simples estender este exemplo para diversas placas Arduino (Leonardo, Mini, etc.), adaptando-se as ligações e o endereço do componente no código escravo.

.

Código para identificar os periféricos conectados ao barramento I2C

Um bom teste para saber se os seus dispositivos comunicam-se bem entre si é utilizar o código abaixo (I2CScanner), que retorna os endereços de todos os dispositivos conectados à placa mestre.

#include <Wire.h>


void setup()
{
  Wire.begin();
  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println(F("\nI2C Scanner"));
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println(F("Scanning..."));

  nDevices = 0;
  for (address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();


    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error == 4)
    {
      Serial.print("Unknown error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println(F("No I2C devices found\n"));
  else
    Serial.println(F("done\n"));

  delay(5000);           // wait 5 seconds for next scan
}

Se tiver qualquer dificuldade para estabelecer uma comunicação I2C entre diferentes dispositivos, deixe um comentário abaixo ou contacte-nos.

Fontes

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?