- ¿Qué es el protocolo de comunicación I2C?
- ¿Cómo funciona la comunicación I2C?
- ¿Dónde utilizar la comunicación I2C?
- I2C en Arduino
- Componentes requeridos
- Diagrama de circuito
- Explicación de trabajo
- Programación I2C en Arduino
- Explicación de la programación maestra de Arduino
- Explicación de la programación del esclavo Arduino
En nuestro tutorial anterior aprendí sobre la comunicación SPI en Arduino. Hoy aprenderemos sobre otro protocolo de comunicación en serie: I2C (Inter Integrated Circuits). Comparando I2C con SPI, I2C tiene solo dos cables mientras que SPI usa cuatro e I2C puede tener múltiples maestros y esclavos, mientras que SPI puede tener solo un maestro y múltiples esclavos. Entonces, hay más de un microcontrolador en un proyecto que debe ser maestro y luego se usa I2C. La comunicación I2C se utiliza generalmente para comunicarse con giroscopio, acelerómetro, sensores de presión barométrica, pantallas LED, etc.
En este tutorial de Arduino I2C usaremos la comunicación I2C entre dos placas arduino y enviaremos valores (0 a 127) entre sí mediante el uso de un potenciómetro. Los valores se mostrarán en la pantalla LCD de 16x2 conectada a cada uno de los Arduino. Aquí un Arduino actuará como maestro y otro actuará como esclavo. Así que comencemos con la introducción sobre la comunicación I2C.
¿Qué es el protocolo de comunicación I2C?
El término IIC significa " Circuitos Inter integrados ". Normalmente se denota como I2C o I al cuadrado C o incluso como protocolo de interfaz de 2 cables (TWI) en algunos lugares, pero todo significa lo mismo. I2C es un protocolo de comunicación síncrono, lo que significa que ambos dispositivos que comparten la información deben compartir una señal de reloj común. Tiene solo dos cables para compartir información, de los cuales uno se usa para la señal del gallo y el otro se usa para enviar y recibir datos.
¿Cómo funciona la comunicación I2C?
La comunicación I2C fue introducida por primera vez por Phillips. Como se dijo anteriormente, tiene dos cables, estos dos cables se conectarán a través de dos dispositivos. Aquí un dispositivo se denomina maestro y el otro dispositivo se denomina esclavo. La comunicación debe ocurrir y siempre ocurrirá entre dos maestros y esclavos. La ventaja de la comunicación I2C es que se puede conectar más de un esclavo a un maestro.
La comunicación completa se lleva a cabo a través de estos dos cables, a saber, Serial Clock (SCL) y Serial Data (SDA).
Serial Clock (SCL): comparte la señal de reloj generada por el maestro con el esclavo
Datos en serie (SDA): envía los datos hacia y desde el maestro y el esclavo.
En un momento dado, solo el maestro podrá iniciar la comunicación. Dado que hay más de un esclavo en el bus, el maestro debe referirse a cada esclavo utilizando una dirección diferente. Cuando se le llame, solo el esclavo con esa dirección en particular responderá con la información, mientras que los demás seguirán saliendo. De esta forma podemos usar el mismo bus para comunicarnos con múltiples dispositivos.
Los niveles de voltaje de I2C no están predefinidos. La comunicación I2C es flexible, significa que el dispositivo que funciona con 5v voltios, puede usar 5v para I2C y los dispositivos de 3.3v pueden usar 3v para la comunicación I2C. Pero, ¿qué pasa si dos dispositivos que funcionan con diferentes voltajes necesitan comunicarse mediante I2C? Un bus I2C 5V no se puede conectar con 3.3V dispositivo. En este caso, se utilizan cambiadores de voltaje para igualar los niveles de voltaje entre dos buses I2C.
Hay un conjunto de condiciones que enmarcan una transacción. La inicialización de la transmisión comienza con un flanco descendente de SDA, que se define como la condición de 'INICIO' en el diagrama a continuación, donde el maestro deja SCL alto mientras configura SDA bajo.
Como se muestra en el diagrama anterior a continuación, El flanco descendente de SDA es el disparador de hardware para la condición de ARRANQUE. Después de esto, todos los dispositivos del mismo bus pasan al modo de escucha.
De la misma manera, el flanco ascendente de SDA detiene la transmisión, que se muestra como la condición 'STOP' en el diagrama anterior, donde el maestro deja SCL alto y también libera SDA para ir HIGH. Entonces, el flanco ascendente de SDA detiene la transmisión.
El bit R / W indica la dirección de transmisión de los siguientes bytes, si es ALTO significa que el esclavo transmitirá y si es bajo significa que el maestro transmitirá.
Cada bit se transmite en cada ciclo de reloj, por lo que se necesitan 8 ciclos de reloj para transmitir un byte. Después de cada byte enviado o recibido, se mantiene el noveno ciclo de reloj para el ACK / NACK (reconocido / no reconocido). Este bit ACK lo genera el esclavo o el maestro, según la situación. Para el bit ACK, el maestro o el esclavo establece el SDA en bajo en el noveno ciclo de reloj. Por lo tanto, se considera bajo como ACK, de lo contrario NACK.
¿Dónde utilizar la comunicación I2C?
La comunicación I2C se utiliza solo para comunicaciones de corta distancia. Ciertamente es confiable hasta cierto punto, ya que tiene un pulso de reloj sincronizado para hacerlo inteligente. Este protocolo se utiliza principalmente para comunicarse con sensores u otros dispositivos que tienen que enviar información a un maestro. Es muy útil cuando un microcontrolador tiene que comunicarse con muchos otros módulos esclavos utilizando un mínimo de solo cables. Si está buscando una comunicación de largo alcance, debe probar RS232 y si está buscando una comunicación más confiable, debe probar el protocolo SPI.
I2C en Arduino
La siguiente imagen muestra los pines I2C presentes en Arduino UNO.
Línea I2C | Pin en Arduino |
SDA | A4 |
SCL | A5 |
Antes de comenzar a programar I2C usando dos Arduino. Necesitamos aprender sobre la biblioteca Wire utilizada en Arduino IDE.
La biblioteca
1. Wire.begin (dirección):
Uso: esta biblioteca se utiliza para establecer comunicación con dispositivos I2C. Esto inicia la biblioteca Wire y se une al bus I2C como maestro o esclavo.
Dirección: La dirección del esclavo de 7 bits es opcional y si no se especifica la dirección, se une al bus como maestro de esta manera.
2. Wire.read ():
Uso: Esta función se utiliza para leer un byte que se recibió de un dispositivo maestro o esclavo, ya sea que se transmitió de un dispositivo esclavo a un dispositivo maestro después de una llamada a requestFrom () o se transmitió de un maestro a un esclavo.
3. Wire.write ():
Uso: esta función se utiliza para escribir datos en un dispositivo esclavo o maestro.
Slave to Master: Slave escribe datos en un maestro cuando se usa Wire.RequestFrom () en maestro.
Maestro a esclavo: para la transmisión de un dispositivo maestro a esclavo, Wire.write () se utiliza entre llamadas a Wire.beginTransmission () y Wire.endTransmission ().
Wire.write () se puede escribir como:
- Wire.write (valor)
valor: un valor para enviar como un solo byte.
- Wire.write (cadena):
cadena: una cadena para enviar como una serie de bytes.
- Wire.write (datos, longitud):
datos: una matriz de datos para enviar como bytes
longitud: el número de bytes a transmitir.
4. Wire.beginTransmission (dirección):
Uso: Esta función se utiliza para iniciar una transmisión al dispositivo I2C con la dirección esclava dada. Posteriormente, cree una cola de bytes para la transmisión con la función write () y luego transmítalos llamando a la función endTransmission () . Se transmite la dirección de 7 bits del dispositivo.
5. Wire.endTransmission ();
Uso: Esta función se usa para finalizar una transmisión a un dispositivo esclavo que fue iniciada por beginTransmission () y transmite los bytes que fueron puestos en cola por Wire.write ().
6. Wire.onRequest ();
Uso: esta función se llama cuando un maestro solicita datos usando Wire.requestFrom () del dispositivo esclavo. Aquí podemos incluir la función Wire.write () para enviar datos al maestro.
7. Wire.onReceive ();Uso: esta función se llama cuando un dispositivo esclavo recibe datos de un maestro. Aquí podemos incluir Wire.read (); función para leer los datos enviados desde el maestro.
8. Wire.requestFrom (dirección, cantidad);
Uso: esta función se utiliza en el maestro para solicitar bytes de un dispositivo esclavo. La función Wire.read () se utiliza para leer los datos enviados desde el dispositivo esclavo.
dirección: la dirección de 7 bits del dispositivo para solicitar bytes
cantidad: el número de bytes a solicitar
Componentes requeridos
- Arduino Uno (2 números)
- Módulo de pantalla LCD 16X2
- Potenciómetro de 10K (4 números)
- Tablero de circuitos
- Conexión de cables
Diagrama de circuito
Explicación de trabajo
Aquí para demostrar la comunicación I2C en Arduino, usamos dos Arduino UNO con dos pantallas LCD de 16X2 conectadas entre sí y usamos dos potenciómetros en ambos arduino para determinar los valores de envío (0 a 127) de maestro a esclavo y esclavo a maestro variando el potenciómetro.
Tomamos el valor analógico de entrada en el pin A0 de arduino de (0 a 5V) usando un potenciómetro y lo convertimos en valor analógico a digital (0 a 1023). Luego, estos valores de ADC se convierten en (0 a 127), ya que solo podemos enviar datos de 7 bits a través de la comunicación I2C. La comunicación I2C se realiza a través de dos cables en los pines A4 y A5 de ambos arduino.
Los valores en la pantalla LCD de Slave Arduino se cambiarán variando el POT en el lado maestro y viceversa.
Programación I2C en Arduino
Este tutorial tiene dos programas, uno para Arduino maestro y otro para Arduino esclavo. Los programas completos para ambos lados se dan al final de este proyecto con un video de demostración.
Explicación de la programación maestra de Arduino
1. En primer lugar, debemos incluir la biblioteca Wire para usar las funciones de comunicación I2C y la biblioteca LCD para usar las funciones LCD. También defina los pines LCD para LCD de 16x2. Obtenga más información sobre la interfaz de LCD con Arduino aquí.
#incluir
2. En configuración nula ()
- Comenzamos la comunicación en serie a una velocidad de 9600 baudios.
Serial.begin (9600);
- A continuación, iniciamos la comunicación I2C en el pin (A4, A5)
Wire.begin (); // Inicia la comunicación I2C en el pin (A4, A5)
- A continuación, inicializamos el módulo de pantalla LCD en modo 16X2 y mostramos el mensaje de bienvenida y lo borramos después de cinco segundos.
lcd.begin (16,2); // Iniciar la pantalla LCD lcd.setCursor (0,0); // Establece el cursor en la primera línea de la pantalla lcd.print ("Circuit Digest"); // Imprime CIRCUIT DIGEST en LCD lcd.setCursor (0,1); // Establece el cursor en la segunda línea de la pantalla lcd.print ("I2C 2 ARDUINO"); // Imprime I2C ARDUINO en retraso LCD (5000); // Retraso de 5 segundos lcd.clear (); // Borra la pantalla LCD
3. En bucle vacío ()
- Primero necesitamos obtener datos del esclavo, por lo que usamos requestFrom () con la dirección del esclavo 8 y solicitamos un byte
Wire.requestFrom (8,1);
El valor recibido se lee usando Wire.read ()
byte MasterReceive = Wire.read ();
- A continuación, necesitamos leer el valor analógico del maestro arduino POT adjunto al pin A0
int potvalue = analogRead (A0);
Convertimos ese valor en términos de un byte de 0 a 127.
byte MasterSend = map (potvalue, 0,1023,0,127);
- A continuación, debemos enviar esos valores convertidos para comenzar la transmisión con el arduino esclavo con 8 direcciones
Wire.beginTransmission (8); Wire.write (MasterSend); Wire.endTransmission ();
- A continuación, mostramos los valores recibidos del arduino esclavo con un retraso de 500 microsegundos y recibimos y mostramos continuamente esos valores.
lcd.setCursor (0,0); // Establece Currsor en la línea uno de LCD lcd.print (">> Master <<"); // Imprime >> Maestro << en LCD lcd.setCursor (0,1); // Establece el cursor en la línea dos de LCD lcd.print ("SlaveVal:"); // Imprime SlaveVal: en LCD lcd.print (MasterReceive); // Imprime MasterReceive en LCD recibido de Slave Serial.println ("Master Received From Slave"); // Imprime en Serial Monitor Serial.println (MasterReceive); retraso (500); lcd.clear ();
Explicación de la programación del esclavo Arduino
1. Al igual que el maestro, primero debemos incluir la biblioteca Wire para usar las funciones de comunicación I2C y la biblioteca LCD para usar las funciones LCD. También defina los pines LCD para LCD de 16x2.
#incluir
2. En configuración nula ()
- Comenzamos la comunicación en serie a una velocidad de 9600 baudios.
Serial.begin (9600);
- A continuación, iniciamos la comunicación I2C en el pin (A4, A5) con la dirección del esclavo como 8. Aquí es importante especificar la dirección del esclavo.
Wire.begin (8);
A continuación, debemos llamar a la función cuando el esclavo recibe un valor del maestro y cuando el maestro solicita el valor del esclavo
Wire.onReceive (ReceiveEvent); Wire.onRequest (requestEvent);
- A continuación, inicializamos el módulo de pantalla LCD en modo 16X2 y mostramos el mensaje de bienvenida y lo borramos después de cinco segundos.
lcd.begin (16,2); // Iniciar la pantalla LCD lcd.setCursor (0,0); // Establece el cursor en la primera línea de la pantalla lcd.print ("Circuit Digest"); // Imprime CIRCUIT DIGEST en LCD lcd.setCursor (0,1); // Establece el cursor en la segunda línea de la pantalla lcd.print ("I2C 2 ARDUINO"); // Imprime I2C ARDUINO en retraso LCD (5000); // Retraso de 5 segundos lcd.clear (); // Borra la pantalla LCD
3. A continuación, tenemos dos funciones, una para solicitar evento y otra para recibir evento.
Para solicitar evento
Cuando el maestro solicita el valor del esclavo, esta función se ejecutará. Esta función toma el valor de entrada del Slave POT y lo convierte en términos de 7 bits y envía ese valor al maestro.
vacío requestEvent () { int potvalue = analogRead (A0); byte SlaveSend = map (potvalue, 0,1023,0,127); Wire.write (SlaveSend); }
Para recibir evento
Cuando el maestro envía datos al esclavo con la dirección del esclavo (8), esta función se ejecutará. Esta función lee el valor recibido del maestro y lo almacena en una variable de tipo byte .
evento de recepción vacío (int howMany { SlaveReceived = Wire.read (); }
4. En bucle vacío ():
Mostramos el valor recibido del maestro continuamente en el módulo de pantalla LCD.
bucle vacío (vacío) { lcd.setCursor (0,0); // Establece Currsor en la línea uno de LCD lcd.print (">> Slave <<"); // Imprime >> Esclavo << en LCD lcd.setCursor (0,1); // Establece el cursor en la línea dos de LCD lcd.print ("MasterVal:"); // Imprime MasterVal: en LCD lcd.print (SlaveReceived); // Imprime el valor SlaveReceived en LCD recibido del Master Serial.println ("Slave Received From Master:"); // Imprime en Serial Monitor Serial.println (SlaveReceived); retraso (500); lcd.clear (); }
Al girar el potenciómetro a un lado, puede ver los valores variables en la pantalla LCD del otro lado:
Así es como se lleva a cabo la comunicación I2C en Arduino, aquí usamos dos Arduino para demostrar no solo el envío de datos, sino también la recepción de datos mediante la comunicación I2C. Así que ahora puede conectar cualquier sensor I2C a Arduino.
La codificación completa para Master y Slave Arduino se proporciona a continuación con un video de demostración