Tutorial Arduino : I2C
En este tutorial se explicara el funcionamiento del bus I2C, entrando en detalle en como se transmite la trama así como las diferencias con otros buses. Además se explicara su uso con Arduino con varios ejemplos de funcionamiento.
I2C (Inter-Integrated Circuit) es un bus de comunicación muy utilizado para comunicar circuitos integrados, uno de sus usos mas comunes es la comunicación entre un microcontrolador y sensores periféricos. El I2C es un bus multi-maestro es decir permite que haya múltiples maestros y múltiples esclavos en el mismo bus.
El bus I2C cuenta con dos lineas SDA(datos) y SCL(clock) ademas de masa. Como hemos visto en SPI a cada flanco de SCL se captura un bit de SDA, aunque la forma de transmitir la información es diferente. Ademas hay que tener en cuenta que la linea SDA solo puede cambiar de valor en caso de que la linea SCL este a 0.
I2C (Inter-Integrated Circuit) es un bus de comunicación muy utilizado para comunicar circuitos integrados, uno de sus usos mas comunes es la comunicación entre un microcontrolador y sensores periféricos. El I2C es un bus multi-maestro es decir permite que haya múltiples maestros y múltiples esclavos en el mismo bus.
El bus I2C cuenta con dos lineas SDA(datos) y SCL(clock) ademas de masa. Como hemos visto en SPI a cada flanco de SCL se captura un bit de SDA, aunque la forma de transmitir la información es diferente. Ademas hay que tener en cuenta que la linea SDA solo puede cambiar de valor en caso de que la linea SCL este a 0.
En este caso la misma linea de datos envia la información en las dos direcciones, por lo que es necesario un control de acceso al bus y un direccionamiento de cada elemento.
En I2C hay un valor fuerte y otro valor débil, normalmente el 0 es el valor fuerte y el 1 el débil Esto es así porque el 0 se consigue forzando la linea a esa tensión pero por contra el 1 se consigue con pull-up, por lo tanto en caso de que alguien transmita un 0 y otro un 1, en la linea solo se vera reflejado el 0. Por lo tanto se define como el valor de reposo del bus como el 1, ya que si alguien quiere empezar a comunicar siempre podrá modificar el estado del bus y los demás se darán cuenta.
Otro aspecto a tener en cuenta en I2C es que los maestros o maestro son los únicos que pueden controlar la linea de SCL, eso implica que solo un maestro puede iniciar una transmisión por lo que un Slave tendrá que esperar a que un maestro le pregunte por un dato para poder enviarlo.
Así en I2C cada dispositivo tiene una dirección de 7 bits, es decir se pueden tener hasta 128 dispositivos conectados al mismo bus, hay que tener en cuenta que existen versiones extendidas de I2C con direccionamiento a 8,10 y 12 bits.
En el caso del I2C el protocolo del bus si reserva unos campos para poder realizar la transmisión, cosa totalmente diferente con el SPI donde podíamos enviar en cada byte el dato que queramos.
Una trama I2C esta comprendida por los siguientes campos.
En I2C hay un valor fuerte y otro valor débil, normalmente el 0 es el valor fuerte y el 1 el débil Esto es así porque el 0 se consigue forzando la linea a esa tensión pero por contra el 1 se consigue con pull-up, por lo tanto en caso de que alguien transmita un 0 y otro un 1, en la linea solo se vera reflejado el 0. Por lo tanto se define como el valor de reposo del bus como el 1, ya que si alguien quiere empezar a comunicar siempre podrá modificar el estado del bus y los demás se darán cuenta.
Otro aspecto a tener en cuenta en I2C es que los maestros o maestro son los únicos que pueden controlar la linea de SCL, eso implica que solo un maestro puede iniciar una transmisión por lo que un Slave tendrá que esperar a que un maestro le pregunte por un dato para poder enviarlo.
Así en I2C cada dispositivo tiene una dirección de 7 bits, es decir se pueden tener hasta 128 dispositivos conectados al mismo bus, hay que tener en cuenta que existen versiones extendidas de I2C con direccionamiento a 8,10 y 12 bits.
En el caso del I2C el protocolo del bus si reserva unos campos para poder realizar la transmisión, cosa totalmente diferente con el SPI donde podíamos enviar en cada byte el dato que queramos.
Una trama I2C esta comprendida por los siguientes campos.
- Bit de start: Este es un bit especial ya que como hemos dicho antes la linea SDA no puede cambiar a menos que SCL este a 0. Este bit rompe dicha norma y provoca un cambio de 1 a 0 cuando SCL esta a nivel alto.
- Address: El primer byte enviado empieza con 7 bits de dirección, el cual indica a quien enviamos o solicitamos el dato.
- R/W (Read/Write): El siguiente bit indica si vamos a realizar una operación de lectura o escritura.
- ACK: Este bit esta presente al final de cada byte que enviamos y nos permite asegurarnos que el byte ha llegado a su destino. De este modo el que envía deja el bit a 1 y si alguien a recibido el mensaje fuerza ese bit a 0. De esta manera confirma que le ha llegado el byte y la transmisión puede continuar.
- 1º Byte de datos: Este es el primer byte de datos propiamente dicho ya que lo anterior no lo podemos elegir nosotros y nos viene impuesto por el protocolo. Aquí podemos poner el dato que queramos en caso de comunicación con sensores remotos un uso habitual es poner el numero de registro al que queremos escribir o leer. Después del byte de datos se espera otro ACK del receptor.
- Se repite el paso 5 tantas veces como sea necesario.
- Bit de Stop. En este caso ocurre lo contrario al bit de Start, se pasa de 0 a 1 cuando la linea SCL se encuentra en alto. Esto termina la transmisión y deja el bus libre para que otro puede empezar a transmitir.
Lo explicado anteriormente es una trama típica de I2C aunque en realidad puede haber algunas variantes, ya que en caso de que el mismo Master quiera seguir comunicándose no es necesario terminar la transmisión con un Stop y luego volver a empezar una transmisión .El protocolo permite que en medio de una trama se realice otro Start por lo que se tendrá que volver a enviar la dirección y el R/W, así que se puede cambiar el modo de comunicación y pasar a una lectura o a otra escritura y acceder a otro sensor o a otro registro del mismo sensor. En la siguiente imagen se puede ver una trama de este tipo.
Uso en Arduino.
Vista la teoría del bus I2C es el momento de ver como podemos usarlo en nuestro Arduino. En el Arduino Uno los pines del I2C se encuentran en el pin analógico 4(SDA) y el pin analógico 5(SCL). En el Arduino Mega se encuentran en los pines 20 (SDA) y en el 21(SCL). Finalmente en el nuevo Arduino Leonardo los pines I2C están pintados al lado de AREF.
En lo referente a conexiones conectamos los SDA y los SCL de los dispositivos entre ellos y a la vez una pull-up por cada linea. Estas resistencias pueden tener valores entre 1k y 10 k, dependiendo de la velocidad de comunicación. Un buen valor para esta velocidad es 4.7K. Aunque es cierto que se pueden conectar sin las pull-up y funciona, en el osciloscopio la señal no se veía muy bien, así que para evitar posibles errores lo mejor es asegurarse poniendo las pull-up.
En lo referente a conexiones conectamos los SDA y los SCL de los dispositivos entre ellos y a la vez una pull-up por cada linea. Estas resistencias pueden tener valores entre 1k y 10 k, dependiendo de la velocidad de comunicación. Un buen valor para esta velocidad es 4.7K. Aunque es cierto que se pueden conectar sin las pull-up y funciona, en el osciloscopio la señal no se veía muy bien, así que para evitar posibles errores lo mejor es asegurarse poniendo las pull-up.
Para usar el bus I2C en Arduino hay que incluir la librería Wire con #include <Wire.h>. A continuación en el setup hay que usar la función Wire.begin() esto inicia el bus I2C y nos define como maestros. Dentro del begin se puede poner una dirección aunque si solo hay un master no es necesario ya que nadie nos va a solicitar datos sino que seremos nosotros los que siempre iniciemos la comunicación.
Una vez iniciado el bus podemos empezar a transmitir. Para ello se usan 3 instrucciones:
Una vez iniciado el bus podemos empezar a transmitir. Para ello se usan 3 instrucciones:
- Wire.beginTransmission(dirección) :Inicia el bus y ponemos con que dirección vamos a comunicarnos.
- Wire.write(bytes): Esta función envía uno o varios bytes a la dirección anterior.
- Wire.endTransmission(): Finaliza la comunicación con un STOP y deja el bus libre.

i2c_1.zip | |
File Size: | 0 kb |
File Type: | zip |
Ahora vamos a ver el resultado con el osciloscopio, en el este caso no hay nadie conectado al otro lado por lo que no se recibirá un ACK y se abortara la transmisión. Así podemos ver como con I2C podemos saber si el mensaje a llegado a su destino.
Se puede observar como la velocidad de comunicación es de 100 Kbps esto es debido a que a diferencia del SPI el protocolo I2C en el modo estándar la velocidad máxima es de 100 Kpbs, aunque se puede llegar hasta 3.4 Mbps en otras configuraciones.
En el siguiente ejemplo vamos a conectar dos Arduinos , uno sera configurado como esclavo y otro como maestro. El código del maestro sera el mismo que el anterior y ahora vamos a programar el esclavo para que nos enseñe por el monitor Serial lo que recibe por I2C.
En el siguiente ejemplo vamos a conectar dos Arduinos , uno sera configurado como esclavo y otro como maestro. El código del maestro sera el mismo que el anterior y ahora vamos a programar el esclavo para que nos enseñe por el monitor Serial lo que recibe por I2C.

i2c_2.zip | |
File Size: | 0 kb |
File Type: | zip |
Vemos como configuramos el Arduino para actuar como Slave y ademas configuramos la recepcion por Evento. De esta forma al llegar una trama nos saltara a la interrupción y podremos leer los datos almacenados en el buffer. En nuestro ejemplo solo se envía el byte 0x52 por lo que con el Serial.print(rec,HEX) nos permite ver ese valor en hexadecimal por el monitor.
Envió con Slave.
Finalmente nos queda por ver como enviar datos desde un slave y recibirlos en un master. Desde el master enviaremos dos números en este caso el 5 y el 7. Y en el Slave los recibiremos y los sumaremos, posteriormente cuando el master nos lo pida se enviara el resultado de la suma al Master.

i2c_3.zip | |
File Size: | 0 kb |
File Type: | zip |

i2c_4.zip | |
File Size: | 0 kb |
File Type: | zip |
Con estos dos programas en el Arduino, vemos como podemos interactuar entre dos microcontroladores. Podemos ver el resultado en el osciloscopio donde se distinguen las tramas de envió y de recepción.
Finalmente el resultado por el monitor Serial.
Para terminar vamos a exponer las principales ventajas e inconvenientes que presenta el bus I2C.
Ventajas:
Desventajas:
Ventajas:
- 2 hilos + masa para funcionar.
- Control de flujo.
- Mecanismo para asegurar que el mensaje ha llegado a su destino mediante ACK.
- Muy usado en sensores y otros circuitos integrados.
- Velocidad media-alta en Arduino 100 Kbps aunque existe otro modo a 3.4 Mbits pero no en Arduino.
- Cada nodo posee una dirección con el cual podemos comunicarnos individualmente
Desventajas: