- Què és el protocol de comunicació I2C?
- Com funciona la comunicació I2C?
- On utilitzar la comunicació I2C?
- I2C a Arduino
- Components necessaris
- Esquema de connexions
- Explicació de treball
- Programació I2C a Arduino
- Explicació de la programació mestra Arduino
- Explicació de la programació Slave Arduino
Al nostre tutorial anterior vam aprendre sobre la comunicació SPI a Arduino. Avui coneixerem un altre protocol de comunicació en sèrie: I2C (Inter Integrated Circuits). En comparar I2C amb SPI, I2C només té dos cables, mentre que SPI en fa quatre i I2C pot tenir Màster i Esclau múltiples, mentre que SPI només pot tenir un mestre i diversos esclaus. Així, doncs, hi ha més d’un microcontrolador en un projecte que ha de ser master perquè s’utilitza I2C. La comunicació I2C s'utilitza generalment per comunicar-se amb giroscopi, acceleròmetre, sensors de pressió baromètrica, pantalles LED, etc.
En aquest tutorial Arduino I2C utilitzarem la comunicació I2C entre dues plaques arduino i ens enviarem (0 a 127) valors entre si mitjançant un potenciòmetre. Els valors es mostraran a la pantalla LCD de 16x2 connectada a cadascun dels Arduino. Aquí un Arduino actuarà com a mestre i un altre actuarà com a esclau. Comencem, doncs, amb la introducció sobre la comunicació I2C.
Què és el protocol de comunicació I2C?
El terme IIC significa " Circuits integrats inter ". Normalment es denomina I2C o I al quadrat C o fins i tot com a protocol d'interfície de dos fils (TWI) en alguns llocs, però tot significa el mateix. I2C és un protocol de comunicació síncrona que significa que tots dos dispositius que comparteixen la informació han de compartir un senyal de rellotge comú. Només té dos cables per compartir informació, dels quals un s'utilitza per al senyal del gall i l'altre s'utilitza per enviar i rebre dades.
Com funciona la comunicació I2C?
Phillips va introduir per primera vegada la comunicació I2C. Com s'ha dit anteriorment, té dos cables, aquests dos cables es connectaran a través de dos dispositius. Aquí un dispositiu s’anomena mestre i l’altre es diu esclau. La comunicació s'ha de produir i es produirà sempre entre dos Mestres i Esclaus. L’avantatge de la comunicació I2C és que es pot connectar més d’un esclau a un mestre.

La comunicació completa es realitza a través d'aquests dos cables, a saber, el rellotge en sèrie (SCL) i les dades en sèrie (SDA).
Rellotge en sèrie (SCL): comparteix el senyal de rellotge generat pel mestre amb l’esclau
Dades de sèrie (SDA): envia les dades entre i des del mestre fins a l'esclau.
En qualsevol moment, només el mestre podrà iniciar la comunicació. Com que hi ha més d’un esclau al bus, el mestre ha de referir-se a cada esclau amb una adreça diferent. Quan s'adreça només l'esclau amb aquesta adreça en particular respondrà amb la informació mentre els altres continuen deixant de fumar. D’aquesta manera podem utilitzar el mateix bus per comunicar-nos amb diversos dispositius.
Els nivells de tensió de l'I2C no estan predefinits. La comunicació I2C és flexible, és a dir, el dispositiu que funciona amb 5 V de potència, pot utilitzar 5 V per a I2C i els dispositius de 3,3 V poden utilitzar 3 V per a la comunicació I2C. Però, i si dos dispositius que funcionen amb tensions diferents, necessiten comunicar-se mitjançant I2C? No es pot connectar un bus I2C de 5V amb un dispositiu de 3,3V. En aquest cas, els variadors de tensió s’utilitzen per fer coincidir els nivells de tensió entre dos busos I2C.
Hi ha un conjunt de condicions que emmarquen una transacció. La inicialització de la transmissió comença amb una vora descendent de SDA, que es defineix com a condició "START" al diagrama següent, on el mestre deixa SCL alt mentre posa SDA baix.

Com es mostra al diagrama anterior, La vora descendent de SDA és el disparador de maquinari per a la condició START. Després d'això, tots els dispositius del mateix bus passen al mode d'escolta.
De la mateixa manera, la vora ascendent de SDA atura la transmissió que es mostra com a condició "STOP" al diagrama superior, on el mestre deixa SCL alt i també allibera SDA per passar a HIGH. De manera que la vora ascendent de SDA atura la transmissió.

El bit R / W indica la direcció de transmissió dels següents bytes, si és ALTA significa que l’esclau transmetrà i si és baix significa que transmetrà el mestre.
Cada bit es transmet en cada cicle de rellotge, de manera que es necessiten 8 cicles de rellotge per transmetre un byte. Després de cada byte enviat o rebut, es manté el novè cicle de rellotge per a l'ACK / NACK (reconegut / no reconegut). Aquest bit ACK el genera l'esclau o el mestre en funció de la situació. Per ACK va mossegar, SDA s'estableix en baix pel mestre o esclau en 9 º cicle de rellotge. Per tant, és baix, es considera ACK en cas contrari.

On utilitzar la comunicació I2C?
La comunicació I2C només s’utilitza per a comunicacions a curta distància. Sens dubte, és fiable fins a un cert punt, ja que té un pols de rellotge sincronitzat per fer-lo intel·ligent. Aquest protocol s’utilitza principalment per comunicar-se amb sensors o altres dispositius que han d’enviar informació a un mestre. És molt útil quan un microcontrolador ha de comunicar-se amb molts altres mòduls esclaus mitjançant un mínim de només cables. Si busqueu una comunicació de llarg abast, proveu RS232 i si busqueu una comunicació més fiable, proveu el protocol SPI.
I2C a Arduino
La imatge següent mostra els pins I2C presents a Arduino UNO.

| Línia I2C | Pin a Arduino |
| SDA | A4 |
| SCL | A5 |
Abans de començar a programar I2C mitjançant dos Arduino. Hem de conèixer la biblioteca Wire que s’utilitza a Arduino IDE.
La biblioteca
1. Wire.begin (adreça):
Ús: aquesta biblioteca s'utilitza per fer comunicacions amb dispositius I2C. Inicieu la biblioteca Wire i uniu-vos al bus I2C com a mestre o esclau.
Adreça: l'adreça esclava de 7 bits és opcional i, si no s'especifica l'adreça, s'uneix al bus com a mestre com aquest.
2. Wire.read ():
Ús: aquesta funció s’utilitza per llegir un byte que es va rebre des del dispositiu mestre o esclau, ja sigui que es va transmetre des d’un dispositiu esclau a un dispositiu mestre després d’una trucada a requestFrom () o es va transmetre des d’un mestre a un esclau.
3. Wire.write ():
Ús: aquesta funció s’utilitza per escriure dades a un dispositiu esclau o mestre.
Slave to Master: Slave escriu dades a un master quan s’utilitza Wire.RequestFrom () al master.
Mestre a esclau: per a la transmissió d’un dispositiu mestre a esclau, s’utilitza Wire.write () entre trucades a Wire.beginTransmission () i Wire.endTransmission ().
Wire.write () es pot escriure com:
- Wire.write (valor)
valor: un valor per enviar com a únic byte.
- Wire.write (cadena):
string: una cadena per enviar com una sèrie de bytes.
- Wire.write (dades, longitud):
dades: un conjunt de dades per enviar com a bytes
longitud: el nombre de bytes a transmetre.
4. Wire.beginTransmission (adreça):
Ús: aquesta funció s'utilitza per iniciar una transmissió al dispositiu I2C amb l'adreça esclava indicada. Posteriorment, creeu cua de bytes per a la transmissió amb la funció write () i, a continuació, transmeteu-los trucant a la funció endTransmission () . Es transmet l'adreça de 7 bits del dispositiu.
5. Wire.endTransmission ();
Ús: aquesta funció s'utilitza per finalitzar una transmissió a un dispositiu esclau que va començar per beginTransmission () i transmet els bytes que es trobaven a la cua de Wire.write ().
6. Wire.onRequest ();
Ús: aquesta funció es crida quan un mestre sol·licita dades mitjançant Wire.requestFrom () des del dispositiu esclau. Aquí podem incloure la funció Wire.write () per enviar dades al mestre.
7. Wire.onReceive ();Ús: aquesta funció es crida quan un dispositiu esclau rep dades d'un mestre. Aquí podem incloure Wire.read (); funció per llegir les dades enviades des del mestre.
8. Wire.requestFrom (adreça, quantitat);
Ús: aquesta funció s'utilitza al mestre per sol·licitar bytes d'un dispositiu esclau. La funció Wire.read () s’utilitza per llegir les dades enviades des del dispositiu esclau.
address: l'adreça de 7 bits del dispositiu a la qual sol·licitar bytes
quantitat: el nombre de bytes a sol·licitar
Components necessaris
- Arduino Uno (2-Nos)
- Mòdul de pantalla LCD 16X2
- Potenciòmetre de 10K (4 nusos)
- Taula de pa
- Connexió de cables
Esquema de connexions

Explicació de treball
Aquí per demostrar la comunicació I2C a Arduino, fem servir Two Arduino UNO amb dues pantalles LCD de 16X2 connectades entre si i fem servir dos potenciòmetres a ambdós arduino per determinar els valors d’enviament (0 a 127) de mestre a esclau i d’esclau a mestre variant potenciòmetre.
Prenem el valor analògic d’entrada al pin arduino A0 de (0 a 5V) mitjançant un potenciòmetre i els convertim en valor analògic a digital (de 0 a 1023). A continuació, aquests valors ADC es converteixen en (0 a 127), ja que només podem enviar dades de 7 bits mitjançant la comunicació I2C. La comunicació I2C té lloc a través de dos cables als pins A4 i A5 de tots dos arduino.
Els valors de la pantalla LCD de Slave Arduino es canviaran variant el POT al costat principal i viceversa.

Programació I2C a Arduino
Aquest tutorial té dos programes, un per al mestre Arduino i un altre per al Arduino esclau. Al final d’aquest projecte es donen programes complets per a les dues parts amb un vídeo de demostració.
Explicació de la programació mestra Arduino
1. Primer de tot, hem d’ incloure la biblioteca Wire per utilitzar les funcions de comunicació I2C i la biblioteca LCD per utilitzar les funcions LCD. Definiu també pins LCD per a LCD de 16x2. Obteniu més informació sobre la interfície de la pantalla LCD amb Arduino aquí.
#incloure
2. Configuració nul·la ()
- Comencem la comunicació en sèrie a Baud Rate 9600.
Serial.begin (9600);
- A continuació, iniciem la comunicació I2C al pin (A4, A5)
Wire.begin (); // Comença la comunicació I2C al pin (A4, A5)
- A continuació, inicialitzem el mòdul de pantalla LCD en mode 16X2 i mostrem el missatge de benvinguda i esborrem al cap de cinc segons.
lcd.begin (16,2); // Inicialitzar la pantalla LCD lcd.setCursor (0,0); // Estableix el cursor a la primera línia de Display lcd.print ("Circuit Digest"); // Imprimeix CIRCUIT DIGEST a LCD lcd.setCursor (0,1); // Estableix el cursor a la segona línia de Display lcd.print ("I2C 2 ARDUINO"); // Imprimeix I2C ARDUINO en retard LCD (5000); // Retard de 5 segons lcd.clear (); // Esborra la pantalla LCD
3. En bucle buit ()
- Primer, hem d’obtenir dades de l’esclau, de manera que fem servir requestFrom () amb l’adreça esclava 8 i sol·licitem un byte
Wire.requestFrom (8,1);
El valor rebut es llegeix mitjançant Wire.read ()
byte MasterReceive = Wire.read ();
- A continuació, hem de llegir el valor analògic del POT arduino mestre connectat al pin A0
int potvalue = analogRead (A0);
Convertim aquest valor en termes d’un byte de 0 a 127.
byte MasterSend = mapa (potvalue, 0,1023,0,127);
- A continuació, hem d'enviar aquests valors convertits per començar la transmissió amb arduino esclau amb 8 adreces
Wire.beginTransmission (8); Wire.write (MasterSend); Wire.endTransmission ();
- A continuació, mostrem els valors rebuts de l'arduino esclau amb un retard de 500 microsegons i rebem i mostrem contínuament aquests valors.
lcd.setCursor (0,0); // Estableix Currsor a la primera línia de LCD lcd.print (">> Màster <<"); // Imprimeix >> Mestre << a LCD lcd.setCursor (0,1); // Estableix el cursor a la segona línia de LCD lcd.print ("SlaveVal:"); // Imprimeix SlaveVal: en pantalla LCD lcd.print (MasterReceive); // Imprimeix MasterReceive en pantalla LCD rebuda de Slave Serial.println ("Màster rebut de l'esclau"); // Imprimeix a Serial Monitor Serial.println (MasterReceive); retard (500); lcd.clear ();
Explicació de la programació Slave Arduino
1. Igual que el mestre, primer de tot hem d’ incloure la biblioteca de fil per utilitzar les funcions de comunicació I2C i la biblioteca LCD per fer servir les funcions LCD. Definiu també pins LCD per a LCD de 16x2.
#incloure
2. Configuració nul·la ()
- Comencem la comunicació en sèrie a Baud Rate 9600.
Serial.begin (9600);
- A continuació, iniciem la comunicació I2C al pin (A4, A5) amb l'adreça esclava com a 8. Aquí és important especificar l'adreça esclava.
Wire.begin (8);
A continuació, hem de trucar a la funció quan Slave rep el valor del mestre i quan el Mestre sol·licita el valor del mestre
Wire.onReceive (receiveEvent); Wire.onRequest (requestEvent);
- A continuació, inicialitzem el mòdul de pantalla LCD en mode 16X2 i mostrem el missatge de benvinguda i esborrem al cap de cinc segons.
lcd.begin (16,2); // Inicialitzar la pantalla LCD lcd.setCursor (0,0); // Estableix el cursor a la primera línia de Display lcd.print ("Circuit Digest"); // Imprimeix CIRCUIT DIGEST a LCD lcd.setCursor (0,1); // Estableix el cursor a la segona línia de Display lcd.print ("I2C 2 ARDUINO"); // Imprimeix I2C ARDUINO en retard LCD (5000); // Retard de 5 segons lcd.clear (); // Esborra la pantalla LCD
3. A continuació, tenim dues funcions, una per a un esdeveniment de sol·licitud i una per a un esdeveniment de recepció
Per a sol·licitud Esdeveniment
Quan el valor de la sol·licitud mestra de l'esclau s'executarà aquesta funció. Aquesta funció pren el valor d'entrada del Slave POT i el converteix en termes de 7 bits i envia aquest valor al mestre.
void requestEvent () { int potvalue = analogRead (A0); byte SlaveSend = map (potvalue, 0,1023,0,127); Wire.write (SlaveSend); }
Per rebre un esdeveniment
Quan el Mestre envia dades a l'esclau amb adreça esclava (8) s'executarà aquesta funció. Aquesta funció llegeix el valor rebut del mestre i emmagatzema en una variable de tipus byte .
void receiveEvent (int howMany { SlaveReceived = Wire.read (); }
4. Al bucle buit ():
Visualitzem contínuament el valor rebut del mestre al mòdul de pantalla LCD.
bucle buit (buit) { lcd.setCursor (0,0); // Estableix Currsor a la primera línia de LCD lcd.print (">> Esclau <<"); // Imprimeix >> Esclau << a LCD lcd.setCursor (0,1); // Estableix el cursor a la segona línia de LCD lcd.print ("MasterVal:"); // Imprimeix MasterVal: en pantalla LCD lcd.print (SlaveReceived); // Imprimeix el valor SlaveReceived a la pantalla LCD rebuda de Master Serial.println ("Slave Received From Master:"); // Imprimeix a Serial Monitor Serial.println (SlaveReceived); retard (500); lcd.clear (); }
En girar el potenciòmetre per un costat, podeu veure els diferents valors a la pantalla LCD d’un altre costat:

Així doncs, així es produeix la comunicació I2C a Arduino, aquí hem utilitzat dos Arduinos per demostrar no només l’enviament de dades, sinó també la recepció de les dades mitjançant la comunicació I2C. Ara podeu connectar qualsevol sensor I2C a Arduino.
A continuació es mostra la codificació completa per a Master i Slave Arduino amb un vídeo de demostració
