Questa pagina mostra il bus I2C in laboratorio: verranno analizzati i segnali SDA e SCL e la struttura del frame usando un oscilloscopio; negli esempi è utilizzato un Picoscope 2205A MSO, ma vanno bene anche altri strumenti purché dotati di capacità di decodifica dei segnali seriali I2C. Se non disponete di un un oscilloscopio, trovate alcune forme d'onda esemplificative.
Molti degli esempi fanno riferimento a due sensori di temperatura (TC74 e LM75A) scelti per il semplice motivo che... li avevo nel cassetto.
Nel sito potete trovare anche una pagina con simili contenuti che utilizza ESP8266 e BMP280.
Arduino gestisce i dispositivi I2C per mezzo della libreria Wire che contiene i metodi per leggere e scrivere messaggi generici secondo questo protocollo. Ovviamente sono disponibili anche molte librerie specializzate che rendono semplice l'uso di una miriade di dispositivi.
Arduino può essere configurato per comportarsi come Master I2C oppure come Slave I2C, ovviamente in momenti e contesti diversi.
L'hardware da realizzare è piuttosto semplice, soprattutto se si utilizza un circuito stampato che contiene già alcuni degli elementi necessari al funzionamento del circuito. Lo schema seguente mostra un Master (normalmente Arduino, Raspberry Pi, un PIC o un altro dispositivo programmabile) e due Slave (in numero variabile tra 1 e qualche decina):
I collegamenti necessari sono:
Il valore delle due resistenze non è critico ed in genere si sceglie di qualche kΩ, in funzione della velocità di comunicazione e del consumo di corrente.
La fotografia di apertura mostra una possibile realizzazione in cui Arduino usa il circuito PIC-WL-Sen, dopo aver tolto il processore a bordo, la batteria ed il modulo radio. In alternativa è possibile usare A2B oppure realizzare il circuito su breadboard.
In genere la prima operazione da fare è quella di individuare gli indirizzi degli Slave I2C connessi, verificando così anche la funzionalità complessiva del circuito.
Questa operazione è fatta semplicemente iniziando una trasmissione verso ciascuno dei 127 indirizzi possibili, da 0x00 a 0x7F, senza poi trasmettere nulla (nota 1):
Se il byte contenente l'indirizzo viene riscontrato da un ACK = 0 significa che esiste uno Slave con quell'indirizzo. Ovviamente occorre verificare che gli indirizzi trovati siano effettivamente quelli da progetto...
Se il Master non riceve un riscontro, e quindi la funzione ritorna un errore, significa che nessuno Slave ha quell'indirizzo
L'output tipico potrebbe essere qualcosa di simile alla seguente schermata che mostra la presenza di quattro dispositivi con indirizzo (esadecimale) 0x48, 0x4A, 0x4D e 0x4F:
Nell'esempio si tratta di quattro sensori di temperatura (tre TC74 e un LM75A), ma questa informazione è deducibile solo osservando direttamente circuito fisico.
(approfondimento, da riprendere al termine delle attività descritte in questa pagina) Un errore tipico è le presenza di due Slave con lo stesso indirizzo. La scansione con la metodologia precedente rileva semplicemente la presenza di almeno uno Slave con quell'indirizzo e quindi non segnala nulla di anomalo. Cosa potrebbe succedere durante l'uso? Un suggerimento: un tempo i collegamenti diretti di più porte logiche con una resistenza di pull-up erano indicati con il termine AND cablato...
Collegando un oscilloscopio ai due segnali SDA (D1) e SCL (D0) si vede come gli indirizzi riscontrati (ACK = 0) sono quelli degli Slave presenti nel dettaglio del diagramma temporale:
TC74 è un sensore di temperatura con modeste caratteristiche: risoluzione di 1 °C, accuratezza a temperatura ambiente di ± 2 °C.
Questo circuito può utilizzare un solo indirizzo I2C, scelto dal produttore e stampato sul contenitore. La documentazione è riportata al termine del foglio tecnico (nota 5).
Il codice per leggere la temperatura è piuttosto semplice: basta semplicemente leggere il contenuto del registro 0x00. Di seguito un esempio:
#include <Arduino.h>
#include <Wire.h>
#define TC_ADDRESS 0x4F
#define T_REGISTER 0x00
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println( "" );
Serial.println("Start");
}
void loop() {
Wire.beginTransmission( TC_ADDRESS );
Wire.write( T_REGISTER );
Wire.endTransmission( false );
Wire.requestFrom( TC_ADDRESS, 1);
int T = Wire.read();
Serial.print(T,DEC);
Serial.println(" °C");
delay(1000);
}
LM75A è un sensore di temperatura piuttosto diffuso, semplice da utilizzare anche senza librerie specifiche. Per esempio il seguente codice legge dal registro 0x00 i due byte che contengono la parte intera e quella frazionaria della temperatura, stampandola sul monitor seriale. Per i dettagli è necessario leggere i fogli tecnici del componente utilizzato, per esempio il paragrafo 7.4.3 del data sheet NXP.
#include <Arduino.h>
#include <Wire.h>
#define LM_ADDRESS 0x48
#define T_REGISTER 0x00
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println( "" );
Serial.println("Start");
}
void loop() {
Wire.beginTransmission( LM_ADDRESS );
Wire.write( T_REGISTER );
Wire.endTransmission( false );
Wire.requestFrom( LM_ADDRESS, 2);
int H = Wire.read();
int L = Wire.read();
Serial.print ( H*256 + L, HEX );
Serial.print (" ");
float T = (float) L / 256 + H ;
Serial.print(T);
Serial.println(" °C");
delay(1000);
}
Utile osservare con l'oscilloscopio i dati presenti sul bus durante l'esecuzione del programma. Di seguito un esempio:
Ovviamente l'uso di una libreria specifica semplifica l'uso di LM75A ed evita la presenza di errori, come quello presente nel codice sopra mostrato (nota 3).
Di seguito l'output del programma di esempio BasicUsage.ino fornito con la libreria M2M_LM75A:
Il file i2c.zip contiene tre diversi esempi da utilizzare con la versione demo di Picoscope:
Pagina creata nell'aprile 2021
Ultima modifica: 8 marzo 2025
Appunti scolastici - Versione 0.1030 - Marzo 2025
Copyright 2012-2025, Vincenzo Villa (https://www.vincenzov.net)
Creative Commons | Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)