1 DE AGOSTO DE 2024
PROTOCOLO I2C
EN ARDUINO
MADISON JUÁREZ
ROBERTO LÓPEZ
Producción de contenidos digitales
Índice
Introducción ................................................................................................................ 4
¿Qué Es El Protocolo I2C? ......................................................................................... 5
Conceptos Básicos Del Protocolo I2C.................................................................... 6
Líneas de señal I2C............................................................................................. 6
Salidas de Drenaje Abierto ................................................................................. 6
Interfaces ............................................................................................................ 7
Tasa de transferencia de datos ............................................................................ 7
Otros conceptos .................................................................................................. 7
Transmisor: ......................................................................................................... 7
Beneficiario: ....................................................................................................... 7
Maestro: .............................................................................................................. 7
Recortar: ............................................................................................................. 7
Multimaestro: ..................................................................................................... 7
Arbitraje: ............................................................................................................. 7
Sincronización: ................................................................................................... 7
Comunicaciones I2C .............................................................................................. 8
¿Cómo comunicar el dispositivo maestro a esclavo? ............................................. 8
Paso 1: ................................................................................................................ 8
Paso 2: ................................................................................................................ 8
Paso 3.................................................................................................................. 8
Paso 4: ................................................................................................................ 8
Paso 5: ................................................................................................................ 8
Configuración de un bus I2C en Arduino ................................................................... 9
Pin I2C en ARDUINO UNO .................................................................................. 9
Funciones I2C en Arduino .................................................................................... 10
Wire.write (data) ............................................................................................... 10
Parameter .......................................................................................................... 10
Returns .............................................................................................................. 10
Wire.available() ................................................................................................ 10
Wire.read() ........................................................................................................ 10
Funciones maestro en Arduino ............................................................................. 10
Wire.begin () ..................................................................................................... 10
Wire.beginTransmission (slave address) .......................................................... 10
Wire. requestFrom(address, no of byte) o Wire. requestFrom(address, no of byte,
stop) .............................................................................................................................. 11
Parametros ........................................................................................................ 11
true – ................................................................................................................. 11
false – ................................................................................................................ 11
Returns .............................................................................................................. 11
Wire.endTransmission() ................................................................................... 11
Returns .............................................................................................................. 11
Funciones I2C Slave ............................................................................................. 12
Wire.begin (address) ......................................................................................... 12
Parametro .......................................................................................................... 12
Wire.onReceive(handler) .................................................................................. 12
Wire.onRequest (handler) ................................................................................. 12
Diagrama de interfaz ............................................................................................ 12
Comunicación entre dos placas Arduino .............................................................. 13
Señales SDA y SCL .......................................................................................... 13
Conexión a tierra .............................................................................................. 14
Sketch como dispositivo maestro ..................................................................... 14
Sketch como dispositivo esclavo ...................................................................... 15
¿Cómo funciona el código para el modo esclavo? ........................................... 16
Conexión de varios dispositivos al bus................................................................. 16
Conclusión ................................................................................................................ 18
Referencias ............................................................................................................... 19
Introducción
El Circuito Inter-Integrado (I2C) bus es una interfaz serial de dos hilos desarrollada
originalmente por Phillips Corporation para su uso en productos de consumo. Es un bus
bidireccional que se implementa fácilmente en cualquier proceso de IC (NMOS, CMOS,
bipolar) y permite una comunicación simple entre IC.
El protocolo de comunicación C sigue una jerarquía maestro/esclavo, en la que el
maestro se define como el dispositivo que cronometra el bus, se dirige a los esclavos y escribe
o lee datos hacia y desde los registros en los esclavos. Los esclavos son dispositivos que
responden solo cuando son interrogados por el maestro, a través de su dirección única. Por
lo tanto, es imperativo evitar la duplicación de direcciones entre los esclavos. Los esclavos
nunca inician una transferencia de datos.
El bus C usa solo dos líneas bidireccionales, línea de datos en serie (SDA) y una línea
de reloj en serie (SCL). Los dispositivos compatibles con C se conectan al bus con colector
abierto o pines de drenaje abiertos que tiran de la línea a nivel BAJO. Cuando no hay
transmisión de datos el I2C las líneas de bus inactivas en estado ALTO; las líneas se tiran
pasivamente hacia arriba.
El protocolo I2C es uno de los más utilizados para comunicarse con sensores
digitales, ya que a diferencia del puerto Serial, su arquitectura permite tener una confirmación
de los datos recibidos, dentro de la misma trama, entre otras ventajas.
La conexión de tantos dispositivos al mismo bus es una de las principales ventajas.
Además, si comparamos a I2C con otro protocolo serial, como Serial TTL, este incluye más
bits en su trama de comunicación que permite enviar mensajes más completos y detallados.
¿Qué Es El Protocolo I2C?
I2C es un puerto y protocolo de comunicación serial, define la trama de datos y las
conexiones físicas para transferir bits entre 2 dispositivos digitales. El puerto incluye dos
cables de comunicación, SDA y SCL. Además, el protocolo permite conectar hasta 127
dispositivos esclavos con esas dos líneas, con hasta velocidades de 100, 400 y 1000 kbits/s.
También es conocido como IIC ó TWI – Two Wire Interface.
Los mensajes que se envían mediante un puerto I2C, incluye además del byte de
información, una dirección tanto del registro como del sensor. Para la información que se
envía siempre existe una confirmación de recepción por parte del dispositivo. Por esta razón
es bueno diferenciar a los distintos elementos involucrados en este tipo de comunicación.
El protocolo de comunicación I2C se refiere al conjunto de bits que son necesarios
para enviar uno o varios bytes de información. En lo particular, para este protocolo existen
los siguientes bits importantes:
o Inicio ó Start – S.
o Parada – P.
o Confirmación – ACK.
o NoConfirmación – NACK.
o Lectura-/Escritura – L/W.
o 7 bits para la dirección del dispositivo esclavo/maestro.
o 8 bits de dirección (para algunos sensores pueden ser 16 bits).
o 8 bits de datos.
El conjunto de estos bits y su orden va formando distintas tramas de comunicación.
Existen distintos modos de comunicación dependiendo del arreglo de estos bits. Tanto el
maestro como el esclavo pueden o no generar los bits anteriores, según los modos de
comunicación.
El puerto I2C está disponible si las dos líneas, SDA y SCL están en un nivel lógico
alto.
Los modos de comunicación en I2C se refieren a las distintas tramas que pueden
formarse en el bus. Estas tramas o modos dependen de nuestro propósito u objetivo. Si
queremos leer al sensor esclavo, o si lo queremos configurar. Existen principalmente dos
modos de comunicación:
- Maestro-Transmisor y Esclavo-Receptor. Este modo se usa cuando se desea
configurar un registro del esclavo I2C.
- Maestro-Receptor Y Esclavo-Transmisor. Se usa cuando queremos leer
información del sensor I2C.
Conceptos Básicos Del Protocolo I2C
Líneas de señal I2C
Las líneas SCL y SDL, se utilizan para comunicarse con los dispositivos. El SCL
significa "línea de reloj en serie" y esta señal siempre es impulsada por el "dispositivo
maestro". SDL significa "línea de datos en serie", y esta señal es impulsada por el maestro o
por los dispositivos I2C. Estas dos líneas SCL y SDL están en estado de drenaje abierto
cuando no hay transferencia entre dispositivos I2C.
Salidas de Drenaje Abierto
El drenaje abierto es el concepto del transistor FET en el que el terminal de drenaje
del transistor está en estado abierto. Los pines SDL y SCL del dispositivo maestro están
diseñados con los transistores abiertos, por lo que la transferencia de datos solo es posible
cuando estos transistores están encendidos. Por lo tanto, estas líneas o terminales de drenaje
se conectan mediante resistencias pull-up a VCC para el modo de conducción.
Datos en serie (SDA): Es una línea de datos en serie que se utiliza para el intercambio
de datos entre el dispositivo maestro y el esclavo.
Interfaces
Muchos dispositivos esclavos se interconectan con el microcontrolador mediante el
bus I2C a través del CI de cambio de nivel I2C para transferir información entre ellos. El
protocolo I2C permite conectar un máximo de 128 dispositivos, todos ellos conectados para
comunicarse con las líneas SCL y SDL de la unidad maestra, así como con los dispositivos
esclavos. Es compatible con la comunicación multimaestro, lo que significa que se utilizan
dos maestros para comunicarse con los dispositivos externos.
Tasa de transferencia de datos
El protocolo I2C explota tres modos tales como: modo rápido, modo de alta velocidad
y modo estándar en el que la velocidad de datos en modo estándar varía de 0 Hz a 100 Hz, y
los datos en modo rápido se pueden transferir con una velocidad de 0 Hz a 400 KHz. y modo
de alta velocidad con 10 Hz. KHz a 100 KHz. Se envían datos de 9 bits para cada
transferencia en la que el transmisor MSB a LSB envía 8 bits, y el noveno bit es un bit de
reconocimiento enviado por el receptor.
Otros conceptos
Transmisor: El dispositivo que envía datos al bus se llama transmisor.
Beneficiario: El dispositivo que recibe datos del bus se llama receptor.
Maestro: El dispositivo que inicia las transferencias para generar señales de reloj y
completar una transferencia se denomina maestro.
Recortar: El dispositivo direccionado por un maestro se llama esclavo.
Multimaestro: Varios maestros pueden intentar controlar el bus al mismo tiempo sin
corromper el mensaje, esto se denomina multimaestro.
Arbitraje: Procedimiento para garantizar que, si varios maestros intentan controlar el
bus simultáneamente, solo uno está autorizado para hacerlo; el mensaje ganador no está
dañado.
Sincronización: El procedimiento para sincronizar los relojes de dos o más
dispositivos se denomina sincronización.
Comunicaciones I2C
El protocolo de bus I2C se usa usualmente en la comunicación maestro y esclavo en
la que el maestro se denomina "microcontrolador" y el esclavo se conoce como otros
dispositivos como ADC, EEPROM, DAC y dispositivos similares en el sistema integrado.
La cantidad de dispositivos esclavos se conectan al dispositivo maestro mediante el bus I2C,
en el que cada esclavo consta de una dirección única para comunicarlo.
¿Cómo comunicar el dispositivo maestro a esclavo?
Paso 1: Primero, el dispositivo maestro emite una condición de inicio para informar
a todos los dispositivos esclavos que escuchen en la línea de datos en serie.
Paso 2: El dispositivo maestro envía la dirección del dispositivo esclavo de destino
que se compara con todas las direcciones de los dispositivos esclavos conectados a las líneas
SCL y SDL. Si una dirección coincide, se selecciona ese dispositivo y todos los dispositivos
restantes se desconectan de las líneas SCL y SDL.
Paso 3: El dispositivo esclavo con una dirección correspondiente recibida del
maestro, responde con un reconocimiento al maestro, después de lo cual se establece la
comunicación entre el maestro y los dispositivos esclavos a través del bus de datos.
Paso 4: El maestro y el esclavo reciben y transmiten los datos dependiendo de si la
comunicación es de lectura o escritura.
Paso 5: Luego, el maestro puede transmitir 8 bits de datos al receptor, que responde
con un reconocimiento de 1 bit.
Configuración de un bus I2C en Arduino
Pin I2C en ARDUINO UNO
La placa Arduino Uno sólo tiene un módulo I2C, pero proporciona estas líneas SDA
y SCL en dos ubicaciones distintas. Al comunicarse con dispositivos que utilizan el protocolo
de comunicación I2C, se deben utilizar resistencias pull-up.
Para configurar los Arduino para la comunicación I2C, primero necesitamos definir
el rol de cada Arduino, es decir, si actuará como maestro o como esclavo. Luego, conectamos
ambos Arduinos utilizando los cables SDA y SCL correspondientes a cada dispositivo. Es
importante asegurarse de que ambos Arduinos estén conectados a tierra (GND) para
establecer una referencia común de voltaje.
Una vez que hemos conectado físicamente los Arduinos, debemos programar el
código correspondiente en cada uno de ellos. En el Arduino maestro, utilizamos la librería
Wire.h para iniciar la comunicación I2C, estableciendo la frecuencia de comunicación
deseada. Luego, podemos enviar y recibir datos utilizando las funciones provistas por la
librería, como Wire.beginTransmission() para iniciar una transmisión y Wire.write() para
enviar datos. En el Arduino esclavo, también utilizamos la librería Wire.h para iniciar la
comunicación y configurar una función de interrupción que se activará cuando se reciba una
transmisión I2C. Dentro de esta función, podemos utilizar la función Wire.available() para
verificar si hay datos disponibles y la función Wire.read() para recibir los datos enviados por
el maestro.
Funciones I2C en Arduino
Wire.write (data)
Se utiliza para escribir (transmitir) datos al dispositivo maestro o esclavo.
Parameter
data puede ser un valor de byte único, cadena, matriz de datos.
Returns
Número de bytes escritos.
Wire.available()
Esta función es utilizada por un maestro o un esclavo para comprobar si los datos
solicitados están disponibles o no. Devuelve el número de bytes disponibles.
Wire.read()
Permite leer los datos solicitados por el maestro del esclavo o leer los datos
transmitidos de un maestro a un esclavo.
Funciones maestro en Arduino
ada dispositivo esclavo I2C tiene una dirección única. Mientras se comunica usando
el protocolo I2C, esta dirección de esclavo debe ser usada por el Maestro.
Arduino tiene una Wire Library que nos permite comunicarnos con dispositivos
I2C.
Wire.begin ()
Inicia la biblioteca Wire y se une al bus como maestro.
Wire.beginTransmission (slave address)
Esta función inicia una transmisión con el dispositivo esclavo I2C con una dirección
de esclavo especificada.
slave address Dirección de 7 bits del dispositivo con el que queremos comunicarnos.
por ejemplo Wire.beginTransmisión (50) //comienza la transmisión con el esclavo
con dirección 50
Wire. requestFrom(address, no of byte) o Wire. requestFrom(address, no of byte,
stop)
Esta función es utilizada por el maestro para solicitar o recibir datos del dispositivo
esclavo. Los datos solicitados pueden ser leídos usando Wire.read().
Parametros
Address dirección del dispositivo con el que queremos comunicarnos
No. of byte número de bytes que necesita solicitar
Stop
Es un booleano.
true – envía un mensaje de parada después de la solicitud, liberando el autobús,
false – envía continuamente un reinicio después de la petición, manteniendo la
conexión activa
Returns
Número de bytes devueltos desde el dispositivo esclavo.
Wire.requestFrom(50, 4) //request 4 nº de bytes del esclavo con dirección 50
Wire.requestFrom(50, 4, true) // dejará de recibir datos después de 4 bytes, liberando
el bus
Wire.endTransmission()
Finaliza una transmisión a un dispositivo esclavo que fue iniciado por
beginTransmission() y transmite los bytes que estaban en cola por write().
Returns
Byte de retorno que indica el estado de la transmisión.
Funciones I2C Slave
Wire.begin (address)
Inicia la librería Wire y se une al bus I2C como un esclavo con dirección especificada.
Parametro
Address
Dirección del esclavo de 7 bits, si no se especifica, unirse al bus como maestro
Wire.onReceive(handler)
La función handler a la que se debe llamar cuando un dispositivo esclavo recibe datos
transmitidos de un maestro.
Wire.onRequest (handler)
Función handler a la que se debe llamar cuando el maestro lo solicita desde el
dispositivo esclavo, no toma ningún parámetro y no devuelve nada.
Diagrama de interfaz
Comunicación entre dos placas Arduino
Transferir datos desde el equipo maestro al esclavo. Aquí usaremos dos Arduino, uno
como maestro y otro como esclavo.
Usaremos el ejemplo incorporado de la librería Wire proporcionado por Arduino
junto con su IDE para la comunicación I2C.
Desde la librería Wire, estamos usando aquí master_writer para Arduino como
maestro y slave_receiver para Arduino como esclavo. Este ejemplo transferirá el número de
maestro a esclavo y el esclavo lo mostrará en un monitor serial.
Puede utilizar esta biblioteca desde
- File -> Examples -> Wire -> master_writer
- File -> Examples -> Wire -> master_receiver
Señales SDA y SCL
Para usar el modo I2C en el 16F88, los pines SDA y SCL deben inicializarse como
entradas (bit TRIS = 1) para que se cree un efecto de drenaje abierto. Al configurarlos como
entradas, no están manejando los cables y una resistencia de extracción externa hará que las
señales sean altas.
GND (Ground) Es la señal a masa que deben compartir todos los dispositivos
conectados al bus.
Conexión a tierra
Realmente la conexión es muy sencilla. Simplemente alimentamos la alimentación
(5V y GND) de ambos Arduinos, y los dos pines del I2C (SDA, SCL) de Arduinos a los pines
SDA y SCL del otro.
En el caso de alimentar ambos Arduinos por el micro USB, desconectar Vcc entre
ellos y dejar únicamente GND como referencia de voltaje común.
Tener en cuenta que el bus I2C está pensado para funcionar en distancias cortas,
típicamente 20-30 cm máximo. Aunque existen expansores de bus I2C que emplean cables
cruzados (similar al UART sobre RS485) que consiguen más de 300 m.
Sketch como dispositivo maestro
# include "SPI.h"
char str[ ]="Hello Slave, I'm Arduino Family\n";
void setup() {
Serial.begin(115200); // set baud rate to 115200 for usart
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV8); //divide the clock by 8
Serial.println("Hello I'm SPI Mega_Master");
}
void loop (void) {
digitalWrite(SS, LOW); // enable Slave Select
// send test string
for(int i=0; i< sizeof(str); i++)
SPI.transfer(str[i]);
digitalWrite(SS, HIGH); // disable Slave Select
delay(2000);
}
Sketch como dispositivo esclavo
#include "SPI.h"
char str[50];
volatile byte i;
volatile bool pin;
void setup()
{
Serial.begin (115200); // set baud rate to 115200 for usart
Serial.println("Hello I'm SPI UNO_SLAVE");
pinMode(MISO, OUTPUT); // have to send on Master in so it set as output
SPCR |= _BV(SPE); // turn on SPI in slave mode
i = 0; // buffer empty
pin = false;
SPI.attachInterrupt(); // turn on interrupt
}
void loop(){
static int count;
if (pin)
{
pin = false; //reset the pin
if(count++< 5){
Serial.print(count);
Serial.print(" : ");
Serial.println(str); //print the array on serial monitor
if(count==5)
{
delay(1000);
Serial.println("The end data");
}
delay(1000);
i= 0; //reset button to zero
}
}
// Interrupt function
ISR(SPI_STC_vect)
{
char c = SPDR; // read byte from SPI Data Register
if (i < sizeof(str)) {
str [i++] = c; // save data in the next index in the array buff
if ( (c == '\r') || (c == '\n') || (c=='\0') ) //check for the end of the word
pin = true;
}
}
¿Cómo funciona el código para el modo esclavo?
Para utilizar la placa Arduino como dispositivo esclavo, es necesario establecer el pin
MISO como salida y activar el modo esclavo. Además, es necesario adjuntar una interrupción
para poder manejar los datos recibidos por el Maestro.
pinMode(MISO, OUTPUT); // hay que enviar en Master in para que se establezca
como salida
SPCR |= _BV(SPE); // activar SPI en modo esclavo
SPI.attachInterrupt(); // activar la interrupción
Siempre que se genere una interrupción debido a los datos del dispositivo maestro,
en Slave, el puntero saltará a ISR con la dirección de SPI_STC_vect, y copiará los datos de
SPDR a la variable c y finalmente de c al array de str. Por último, en el bucle vacío, los datos
recibidos se imprimen en el terminal serie.
Conexión de varios dispositivos al bus
• Paso 1: Conectar los dispositivos: Para utilizar el Bus I2C, debes asegurarte de tener
los dispositivos que deseas conectar correctamente conectados físicamente. La
comunicación se realiza a través de dos pares de cables, uno para transmitir datos y
otro para transmitir la señal de reloj.
• Paso 2: Identificar los dispositivos: Antes de empezar a utilizar el Bus I2C, es
importante identificar los diferentes dispositivos conectados al bus. Cada dispositivo
tiene una dirección única asignada que se utiliza para dirigir los mensajes hacia el
dispositivo correcto.
• Paso 3: Iniciar la comunicación: Para iniciar la comunicación por el Bus I2C, se envía
una señal de inicio. Esto indica a todos los dispositivos conectados que se iniciará una
transferencia de datos.
• Paso 4: Enviar y recibir datos: Una vez iniciada la comunicación, puedes enviar y
recibir datos a través del Bus I2C. Para enviar datos, simplemente escribes los datos
que deseas enviar en el canal de transmisión. Para recibir datos, lees los datos que se
envían desde el dispositivo.
• Paso 5: Finalizar la comunicación: Una vez que hayas terminado de enviar y recibir
datos, debes finalizar la comunicación por el Bus I2C. Esto se realiza enviando una
señal de parada que indica a los dispositivos que se ha completado la transferencia de
datos.
Conclusión
o El protocolo I2C se trata de un protocolo adaptado a diversos dispositivos, entre ellos
el Arduino UNO, dicho protocolo se basa en una serie de normas, funciones y/o
asesorías para unir o establecer una conexión entre dos o más placas Arduino,
estableciendo un rol especifico para cada una. Entre estos roles está el dispositivo
maestro y el dispositivo esclavo, que como su mismo nombre lo indica, el dispositivo
maestro se puede describir de la manera más breve como una raíz y asesor de los
dispositivos esclavos los cuales dependen de su maestro. Así mismo utiliza
conexiones abiertas tales como SCL y SDA, también es importante resaltar la
importancia de la conexión compartida a tierra (GND).
Referencias
Andrés . (22 de febrero de 2018). HEPTRO. Obtenido de https://hetpro-
store.com/TUTORIALES/i2c/
Hiren Tailor . (20 de febrero de 2022). Makerguides . Obtenido de
https://www.makerguides.com/es/master-slave-spi-communication-arduino/
Luis Llamas . (25 de agosto de 2023). Luis Llamas . Obtenido de
https://www.luisllamas.es/esp32-i2c/
Oscar. (3 de marzo de 2020). codigoelectronica. Obtenido de
https://aprendiendoarduino.wordpress.com/category/i2c/
Sebastián Vidal. (9 de septiembre de 2019). Tecnobits. Obtenido de tecnobits.com
TuEquipoSeo. (2014). Descubrearduino. Obtenido de descubrearduino.com