Dispositivi I2C commerciali, come identificare l’indirizzo

Il protocollo I2C è un’ottima opzione per implementare comunicazioni via cavo tra prototipi realizzati con Arduino e con ciò che hai imparato nel precedente tutorial sei in grado di sviluppare un sistema interconnesso basandoti sullo schema software generale che hai sperimentato.

Molti dispositivi commerciali, come ad esempio sensori di precisione e display LCD, utilizzano il protocollo I2C per comunicare con un microcontrollore.

In questi casi, non è solitamente necessario scrivere uno sketch per gestire la trasmissione e la ricezione dei comandi, che comunque dipenderebbero dai meccanismi definiti dai produttori dei dispositivi, poiché i produttori forniscono librerie in C/C++ di più alto livello, che permettono di gestire la comunicazione con il dispositivo secondo una logica vicina all’ambito applicativo.

Ad esempio, il produttore di un sensore di temperatura digitale con interfaccia I2C potrebbe fornire librerie compatibili con Arduino che permettono di comunicare con il dispositivo con istruzioni del tipo: readTemperature() senza doversi preoccupare di quali messaggi inviare sulla linea I2C per richiedere la temperatura o di come configurare uno slave per ricevere messaggi di notifica sulla temperatura.

La libreria incorporerebbe tutto il codice necessario a gestire lo scambio di messaggi sul bus I2C, semplificando il lavoro di chi deve scrivere il firmware del microcontrollore.

Attualmente, esistono moltissimi dispositivi che possono essere collegati ad Arduino mediante I2C e che sono corredati da librerie di alto livello.

Poiché ogni dispositivo collegato ad un bus I2C deve avere un indirizzo unico, i produttori dei dispositivi non preassegnano un unico indirizzo ai loro prodotti ma forniscono sempre qualche meccanismo per selezionare l’indirizzo tra un pool di indirizzi possibili.

Potrebbero esserci dei micro interruttori oppure potrebbero esserci dei ponticelli o connettori da togliere o inserire sulla scheda elettronica del dispositivo.

Collegando il dispositivo ad Arduino potrebbe essere necessario reimpostare gli indirizzi di default assegnati dai produttori dei dispositivi per evitare conflitti con altri dispositivi eventualmente connessi sullo stesso bus.

Se disponi del manuale del prodotto, normalmente l’indirizzo di default e la procedura per modificarlo è documentata.

Se il dispositivo è stato acquistato su Internet, specie se di produzione asiatica, è probabile che non arrivi corredato di manuale, oppure che sia un clone di un dispositivo di altra marca.

In questo tutorial ti mostriamo l’uso di un programmino facilmente reperibile su Internet che ti tornerà molto utile per scoprire qual’è l’indirizzo a cui risponde un dispositivo collegato al bus I2C di cui non hai la documentazione.



// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
// 
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>


void setup()
{
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("nI2C Scanner");
}


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

  Serial.println("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("No I2C devices foundn");
  else
    Serial.println("donen");

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

Il programma è di pubblico dominio, non è stato sviluppato dalla nostra scuola e il suo funzionamento è relativamente semplice.

In pratica viene creato un master I2C che prova a contattare ciclicamente tutti i possibili indirizzi sul bus I2C. Se qualcuno risponde, il relativo indirizzo viene visualizzato sul terminale seriale.

Approfittiamo di questo tutorial per citare il sistema di numerazione esadecimale, molto usato in informatica.

Abbiamo già visto che oltre a contare e generare numerali con le dieci cifre arabe (0,1,2,3,4,5,6,7,8,9) è possibile contare e generare numerali (sequenze di caratteri che rappresentano valori interi) con meno cifre, come nel sistema binario.

Ovviamente è possibile farlo anche con più cifre. Il sistema esadecimale ne utilizza sei che sono 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

Ad esempio il numero “duecentocinquantaquattro” viene scritto in esadecimale come FE, il numero “centoquarantotto” come 94.

I sistemi di numerazione usati in informatica sono: il sistema binario, il sistema ottale e il sistema esadecimale.

Il linguaggio C/C++, e quindi il linguaggio Arduino, permettono di indicare i numeri in uno qualunque di questi sistemi.

Poiché le cifre arabe compaiono in tutti e tre i sistemi, quando si legge un numero come 101, potrebbe non essere chiaro se questo sia da interpretare in binario e quindi di valore pari a “cinque“, in ottale e quindi di valore pari a “sessantacinque“, in decimale e quindi pari a “centouno” oppure in esadecimale e quindi pari a “duecentocinquantasette“.

Per questo in C/C++ si utilizza una apposita convenzione.

I numeri binari si scrivono premettendo la lettera B. Ad esempio B101001.

I numeri ottali si scrivono premettendo sempre la cifra zero. Ad esempio 0234712.

I numeri decimali si scrivono senza alcun prefisso. Ad esempio 2358.

I numeri esadecimali si scrivono premettendo il prefisso 0x. Ad esempio 0x235.

Puoi scrivere un numero nella notazione che preferisci ma attento ad interpretare correttamente il suo valore!

Ad esempio, nel video hai visto che il display oled rispondeva all’indirizzo 0x3C. Tradotto in decimale l’indirizzo è 60.