Dispositivos I2C: Como descobrir o endereço

O que é I2C?

Logo utilizada para identificar o protocolo I2C

I2C significa: Inter-integrated Circuit Protocol. Este é nada mais que um protocolo de comunicação projetado para permitir uma interface entre múltiplos circuitos operando como “slave” se comunicar com um ou mais circuitos que operem em “master“.

Assim como o SPI (Serial Peripheral Interface) o I2C é focado na comunicação de curta distância e assim como os protocolos de comunicação Serial, como o RS-232 e UART, ele requer somente dois fios de dados para troca de informação.

Apesar de parecer mais simples, a comunicação via I2C é muito mais complexa que UART e até mesmo SPI, pois, os sinais devem aderir a um determinado padrão para os dispositivos no barramento I2C reconhecerem como comunicações I2C válidas. Felizmente, a maioria dos dispositivos cuidam de todos esses detalhes complicados para você, permitindo assim que você se concentre somente nos dados que deseja trocar.

Endereçamento

O protocolo I2C foi originalmente desenvolvido em 1982 pela Philips para vários circuitos integrados fabricados pela mesma. Devido a suas especificações ele originalmente garantia somente comunicações com um clock de até 100kHz e com um limite de endereços de 7-bit, ele foi evoluindo e posteriormente veio a ser adotado endereçamento de até 10-bit e hoje já é possível obter clocks de até 5MHz.

Diversos dispositivos I2C Slave conectados a um único I2C Master utilizando somente dois cabos para comunicação entre todos.
Imagem: www.esacademy.com

Utilizando apenas os 7-bit a rede acaba se limitando quanto ao número de dispositivos que normalmente pode ser no máximo 112, uma vez que existem alguns endereços reservados e que nunca serão utilizados. As atualizações mais recentes do I²C permitiram os dispositivos se comunicarem com ainda mais dispositivos e funcionarem em maior velocidade [400 kbit/s Versão 1(Fast mode), 1Mbit/s Versão 3(Fast mode plus), e 3.4Mbit/s Versão 2 (High Speed mode)].

Identificando o endereço de um dispositivo

Ao se desmembrar a biblioteca Wire.h que é a utilizada para a comunicação I2C verificamos que ela depende de uma outra biblioteca chamada twi.h, a qual se trata de uma biblioteca elementar para microcontroladores Atmel AVR. Agora desmembrando a twi.h achamos a função twi_writeTo(), essa é a função responsável por enviar dados no barramento e ela retorna valores de acordo com o resultado da transmissão, este foi o trecho encontrado:

if (twi_error == 0xFF)
    return 0;	// success
  else if (twi_error == TW_MT_SLA_NACK)
    return 2;	// error: address send, nack received
  else if (twi_error == TW_MT_DATA_NACK)
    return 3;	// error: data send, nack received
  else
    return 4;	// other twi error

[NACK siginifica negative-acknowledgement que é um sinal enviado de volta por um dispositivo ao rejeitar a mensagem ou os dados enviados ao mesmo.]

Ou seja, sempre ao final da transmissão teremos de volta um numero que irá indicar o resultado da mesma, o que quer dizer que se conectarmos a um dispositivo mesmo sem enviar nada ao mesmo e encerrar a transmissão teremos um número de “resultado” de volta, sabendo disso vamos ao código.

Código

Utilizando a biblioteca Wire.h temos a função Wire.endTransmission(), ou seja, a função que encerra a transmissão, logo, basta utilizar o retorno dela para determinar se no endereço testado há ou não um dispositivo. Quando houver um dispositivo o retorno será “0”, os erros 2 e 3 devem ser desconsiderados pois, não estão relacionados com a existência ou não de um dispositivo, no entanto, o erro “4” é uma incógnita pois, se trata de um erro não identificado, o que leva a pensar que há um dispositivo naquele endereço mas que a comunicação não foi bem sucedida.

#include <Wire.h>

void setup()
{
  Wire.begin();
  Serial.begin(115200);
  while (!Serial);             // Leonardo e Arduino's baseados no ATMega32u4
  Serial.println(F("\nI2C Basic Scanner v.7"));
}


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

  Serial.println(F("[I2CS] Escaneando..."));

  nDevices = 0;
  for (address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print(F("[I2CS] Dispositivo I2C encontrado no endereço 0x"));
      if (address < 16)Serial.print(F("0"));
      Serial.print(address, HEX);
      Serial.println(F("!"));

      nDevices++;
    }
    else if (error == 4)
    {
      Serial.print(F("[I2CS] Erro desconhecido encontrado no endereço 0x"));
      if (address < 16)Serial.print(F("0"));
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println(F("[I2CS] Nenhum dispositivo detectado\n"));
  else
    Serial.println(F("[I2CS] Escaneamento encerrado\n"));
  while (1);
}

Resultado

I2C Basic Scanner v.7
[I2CS] Escaneando...
[I2CS] Dispositivo I2C encontrado no endereço 0x27
[I2CS] Dispositivo I2C encontrado no endereço 0x3F
[I2CS] Dispositivo I2C encontrado no endereço 0x62
[I2CS] Dispositivo I2C encontrado no endereço 0x68
[I2CS] Escaneamento encerrado

I2C Advanced Scanner v.7

Uma versão ainda mais complexa e completa que estamos desenvolvendo pode ser encontrada em: https://github.com/ZonaMaker/Adv_I2CScanner
Caso queira contribuir, sinta-se a vontade, é Open-Source, basta clonar o repositório, fazer modificações e enviar o pull-request.

 

11

Graduando em Engenharia Elétrica pela Universidade Federal de São João del Rei (UFSJ) também é Técnico em Eletrotécnica pelo Centro Federal de Educação Tecnológica de Minas Gerais (CEFET-MG). Apaixonado por criação e desenvolvimento de projetos relacionados à software e hardware.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *