El bus I2C (Inter-Integrated Circuit) o Interconexión de Circuitos Integrados es una tecnología o interfaz para comunicación serie por medio de dos conductores en una configuración maestro-esclavo (master-slave) con velocidades de transmisión que van desde los 100kbps (modo Estándar) hasta los 400kbps (modo Rápido) que se encuentra actualmente en la mayoría de microcontroladores PIC. Los dispositivos con modo Estándar o Rápido pueden operar en el mismo bus, siempre y cuando el bus trabaje a la velocidad del dispositivo más lento. Se ha desarrollado un protocolo para el bus I2C para asegurar que la transferencia de datos sea confiable (libre de errores).


¡Descubre el mundo de los microcontroladores PIC y lleva tus habilidades de programación al siguiente nivel! Obtén nuestro eBook y disfruta aprendiendo paso a paso desde cero, podrás realizar proyectos prácticos, encontrar soluciones a problemas comunes y explorar una amplia cobertura de temas desde lo más básico a lo más avanzado. Incluye software y ejemplos resueltos. ¡Cómpralo ahora y libera el increíble potencial de esta poderosa tecnología hoy mismo!

Microcontroladores PIC en PDF: Curso completo


Aquí se explica su uso del bus I2C con el microcontrolador PIC16F88 programado en mikroC PRO y la memoria EEPROM I2C 24LC256.

La especificación original, o modo Estándar, es para velocidades de transmisión de hasta 100kbps. También se ha desarrollado una especificación mejorada, o modo Rápido (400 kbps). Los dispositivos con modo Estándar o Rápido pueden operar en el mismo bus, si el bus opera a la velocidad del dispositivo más lento. El bus I2C emplea un protocolo para asegurar la transferencia confiable de los datos. Cuando se transmiten datos, uno de los dispositivos es el maestro (que suele ser un microcontrolador PIC), el cual inicia la transferencia en el bus y genera las señales de reloj para permitir esa transferencia, mientras que los otros dispositivos se comportan como esclavos.

La tabla siguiente define algunos de los términos del bus I2C. En el protocolo I2C cada dispositivo tiene una dirección que lo identifica. Cuando el maestro (microcontrolador PIC) desea iniciar la transferencia de datos, primero transmite la dirección del dispositivo con el cual desea comunicarse. Todos los dispositivos están atentos para determinar si es su dirección. Dentro de la dirección, un bit especifica si el maestro desea leer o escribir al esclavo. El maestro y el esclavo siempre están operando en modos complementarios (transmisor/receptor) durante una transferencia de datos. Es decir, pueden operar en cualquiera de los siguientes modos:

  • Maestro-transmisor y Esclavo-receptor
  • Esclavo-transmisor y Maestro-receptor

En los dos casos el maestro (microcontrolador PIC) genera la señal de reloj. Se emplean resistores externos de pull-up para asegurar un nivel alto cuando ninguno de los dispositivos  lleva las líneas a un nivel bajo. Un valor de 4k7 es satisfactorio para la mayoría de las aplicaciones.

Terminologia del bus i2c

Especificaciones del bus I2C

Se ha definido el siguiente protocolo de bus:

  • La transferencia de datos se puede iniciar únicamente cuando el bus I2C no está ocupado.
  • Durante la transferencia de datos, la línea de datos tiene que permanecer estable siempre que la línea de reloj esté en nivel ALTO. Si se producen cambios en la línea de datos mientras la línea de reloj está en ALTO, será interpretado como una condición de START o STOP.

De acuerdo a esto se han definido las siguientes condiciones:

Bus I2C desocupado (A). Las líneas de reloj y datos permanecen en ALTO.

Inicio de transferencia de datos. Condición de START (B) Una transición ALTO-BAJO en la línea SDA mientras la línea de reloj (SCL) está en ALTO determina la condición de START. Todos los comandos deben estar precedidos por una condición de START.

Fin de transferencia de datos. Condición de STOP (C) Una transición BAJO-ALTO en la línea SDA mientras la línea de reloj (SCL) está en ALTO determina la condición de STOP. Todas las operaciones deben finalizar con una condición de STOP.

Dato válido (D). El estado de la línea de datos representa datos válidos cuando, después de una condición de START, la línea de datos permanece estable durante el tiempo de nivel ALTO de la señal de reloj. Los datos en la línea tienen que cambiarse durante el tiempo de nivel BAJO de la señal de reloj. Hay un bit de datos por cada pulso del reloj. Cada transferencia de datos comienza con una condición de START y finaliza con una condición de STOP. El número de bytes de datos transferido está determinado por el dispositivo maestro.

Transferencia bus i2c

Reconocimiento ACK. Cada dispositivo receptor, cuando es direccionado, está obligado a generar una señal de reconocimiento ACK después de la recepción de cada byte. El dispositivo maestro tiene que generar un pulso de reloj adicional que está asociado con este bit de reconocimiento. El dispositivo que genera el reconocimiento tiene que colocar en BAJO la línea SDA durante el pulso de reloj correspondiente de tal manera que la línea SDA tenga un nivel BAJO estable durante el tiempo de nivel ALTO del ciclo de reloj. Durante las lecturas, el maestro tiene que informar al esclavo la finalización de los datos recibidos al NO generar un bit ACK en el último byte. En este caso, el esclavo dejará la línea de datos en ALTO para habilitar al maestro para que genere la condición de STOP.

Temporizacion bus i2c

El transmisor tiene que liberar la línea SDA al final del dato transmitido para permitir que el receptor lleve la línea a nivel BAJO como reconocimiento de los ocho bits de datos previos. El receptor tiene que liberar la línea al final del pulso de reloj para que el transmisor continúe enviando datos.

Librería Software_I2C de mikroC PRO para el bus I2C

La biblioteca Software_I2C de mikroC PRO contiene las funciones necesarias para establecer la comunicación  con dispositivos I2C. Estas funciones pueden emplearse con cualquier microcontrolador PIC (aunque no disponga de módulos I2C). Las funciones incorporadas permiten que el usuario emplee un microcontrolador PIC como maestro (el modo multi-maestro no está disponible). La tabla siguiente muestra las funciones que pueden ser utilizadas para la comunicación I2C.

Las interrupciones tienen que estar deshabilitadas cuando se emplea la biblioteca Software_I2C. Los pines empleados para la comunicación deben estar conectados a los resistores de pull-up. 

Funciones de mikroC PRO para bus i2c

Memoria EEPROM 24LC256 en bus I2C

En algunos proyectos es necesario almacenar gran cantidad de datos en memoria EEPROM, sin embargo, la memoria disponible para los microcontroladores es muy limitada. Este problema se puede solucionar fácilmente con las memorias EEPROM serie, manteniendo la simplicidad del hardware, debido a que un solo chip de 8 pines puede almacenar gran cantidad de información. Se ha seleccionado la EEPROM serie 24LC256 de Microchip, que es muy popular, con una capacidad de memoria de 32kbyte.

eeprom i2c 24lc256pinout memoria eeprom i2c 24lc256

La EEPROM debe considerarse como un ejemplo fundamental, y puede ser tomado como referencia para la comunicación del microcontrolador PIC con otros dispositivos que acepten el protocolo I2C: termómetro (DS1624), reloj calendario (DS1307), conversor AD/DA (PCF8591), etc.

Ejemplo en mikroC PRO con el PIC16F88

En lenguaje C los strings o cadenas de caracteres terminan en el carácter NULO (0x00), lo cual se aprovecha en los siguientes ejemplos para determinar el final de la transferencia, tanto en operaciones de escritura como de lectura.

Ejemplo-I2C_01.c: Programa que escribe un mensaje de hasta 16 caracteres en la memoria 24LC256 a partir de la dirección 0x3B00. El mensaje se encuentra inicialmente en la memoria de programa del microcontrolador PIC. Luego el PIC lee el mensaje grabado anteriormente en la memoria y lo visualiza en el módulo LCD.

I2C con microcontrolador PIC

//I2C_01.c
//Variables de conexión I2C
sbit Soft_I2C_Scl at RB1_bit;
sbit Soft_I2C_Sda at RB2_bit;
sbit Soft_I2C_Scl_Direction at TRISB1_bit;
sbit Soft_I2C_Sda_Direction at TRISB2_bit;

//Variables  de conexión del módulo LCD. 
sbit LCD_RS at RA4_bit;
sbit LCD_EN at RA6_bit;
sbit LCD_D4 at RA0_bit;
sbit LCD_D5 at RA1_bit;
sbit LCD_D6 at RA2_bit;
sbit LCD_D7 at RA3_bit;

sbit LCD_RS_Direction at TRISA4_bit; 
sbit LCD_EN_Direction at TRISA6_bit;
sbit LCD_D4_Direction at TRISA0_bit;
sbit LCD_D5_Direction at TRISA1_bit;
sbit LCD_D6_Direction at TRISA2_bit;
sbit LCD_D7_Direction at TRISA3_bit;
// Fin de declaración de variables de conexión.

char dato, texto[]="Programe en C.", i=0; 

void main(){ 
  OSCCON=0x60;                //Oscilador interno a 4MHz (TCI=1 us).
  //while (OSCCON.IOFS==0);     //Esperar mientras el oscilador está inestable.
  ANSEL=0x00;                 //Bits AN6:AN0 como E/S digital.
  Soft_I2C_Init();            //Inicializa la comunicación I2C.
  Lcd_Init();                 //Inicializa el LCD.
  Lcd_Cmd(_LCD_CLEAR);        //Borra el display.
  Lcd_Cmd(_LCD_CURSOR_OFF);   //Apaga el cursor.

  //Escritura de una página. 
  Soft_I2C_Start();           //Envía una señal de START.
  Soft_I2C_Write(0b10100000); //Byte de Control. Operación de escritura.
  Soft_I2C_Write(0x3B);       //MSByte de dirección.
  Soft_I2C_Write(0x00);       //LSByte de dirección.
  while (texto[i] != 0x00){
    Soft_I2C_Write(texto[i]);  //Dato.
    i++;
  }
  Soft_I2C_Write(0x00);       //Dato (carácter NULO).
  Soft_I2C_Stop();            //Envía una señal de STOP.
  Delay_ms(5);                //Ciclo interno de escritura.

  //Lectura secuencial. 
  Soft_I2C_Start();           //Envía una señal de START.
  Soft_I2C_Write(0b10100000); //Byte de Control. Operación de escritura.
  Soft_I2C_Write(0x3B);       //MSByte de dirección.
  Soft_I2C_Write(0x00);       //LSByte de dirección.
  Soft_I2C_Start();
  Soft_I2C_Write(0b10100001); //Byte de Control. Operación de lectura.
  do{
    dato=Soft_I2C_Read(1);     //Lee un dato y responde con ACK.
    Lcd_Chr_CP(dato);          //Envía el carácter al LCD.
  }
  while (dato != 0x00);
  dato=Soft_I2C_Read(0);      //Lee el último dato (NULO) y responde con NO ACK.
  Soft_I2C_Stop();            //Envía una señal de STOP.
}