Utilización del protocolo I2C



En esta nota se mostrara la utilización simple del protocolo I2C de un microcontrolador que posee un puerto especial para dicho protocolo.
Las funciones Básicas del protocolo dentro del compilador CCS son:

i2c_start(); //Inicialización de la trama
i2c_stop(); //Finalización de la trama
i2c_read(); //Lectura de los datos
i2c_write(); //Escritura de los datos
i2c_poll(); //Espera a que exista un byte y cuando lo encuentra se activa como verdadero

La configuración del protocolo puede ser Rápida o Lenta, Maestra o Esclava,

En el caso de que sea una configuración Maestra (Master) será de la siguiente forma:
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
En esta configuración podemos notar que se encuentra en modo Maestro, modo Rápido, y que asigna los pines SDA y SCL a los pines físicos del microcontrolador, que de todas formas son los que poseen el puerto internamente.

En el caso de que sea una configuración Esclava (Slave) será de la siguiente forma:
#use i2c(Slave,Fast,sda=PIN_C4,scl=PIN_C3,address=0x10)
En esta configuración podemos notar que se encuentra en modo Esclavo, modo Rápido, y que asigna los pines SDA y SCL a los pines físicos del microcontrolador, que de todas formas son los que poseen el puerto internamente. Pero también notamos un nuevo comando que es “Address” donde en este caso y a modo ejemplo posee el valor hexadecimal 0x10, el cual puede ser modificado a gusto por el programador. Este valor de dirección será el “nombre” del esclavo.
Como este protocolo es un bus, podemos montar sobre el mismo bus varios esclavos, pero cada uno con un address diferente, de esta forma el maestro puede acceder a cada uno utilizando la dirección, es decir, envió la dirección de quien quiero acceder y luego el dato.

Estas configuraciones son por Hardware, CCS también posee una librería para utilizar el protocolo I2C por Software.

A continuación les mostrare dos programas de ejemplo, el primero es un programa Maestro y el segundo es un programa Esclavo.
Lo que hace el maestro es leer el puerto analógico del microcontrolador y enviar el valor leído por medio del protocolo I2C, Luego el Esclavo toma este valor y lo muestra en un LCD, es muy simple pero funciona muy bien a modo ejemplo.

MAESTRO
#include <16F883.h>
#FUSES NOWDT
#FUSES RC_IO
#FUSES NOMCLR
#device adc=8
#use delay(clock=4000000)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
#define IDslave 0x10
void main()
{
   setup_adc_ports(sAN0|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_2);
   int8 varAdc;
   while(true){  
      set_adc_channel(0);
      varAdc = read_adc(); //Lee puerto ADC
      i2c_start();         //Inicializa
      i2c_write(IDslave);  //Envia el Address del Esclavo
      i2c_write(varAdc);   //Envia valor leido ADC
      i2c_stop();          //Finaliza
      delay_ms(100);
   }
}

Podemos ver que en el programa Maestro tenemos configurado el pin AN0 como entrada análoga de 8bit la cual se guardara en la variable varAdc, luego de esto aparecen las funciones básicas del i2c de CCS, primero iniciamos la trama con i2c_start(); luego enviamos los datos mediante i2c_write(); ,la dirección 0x10 que la he definido como IDslave por prolijidad pero pueden poner directamente el valor 0x10 y no definir nada arriba, luego de este valor viene el segundo dato que es el valor de lectura del ADC y luego el i2c_stop(); que finaliza la trama.

ESCLAVO 
#include <16F883.h>
#device adc=8
#FUSES NOWDT
#FUSES RC_IO
#FUSES NOMCLR
#use delay(int=4000000)
#use i2c(Slave,Fast,sda=PIN_C4,scl=PIN_C3,address=0x10)
#include <LCD.C>
void main()
{
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_2);
   lcd_init();
   while(TRUE){ 
      if(i2c_poll())   //Pregunta si hay un byte presente      
         printf(lcd_putc,"VALOR I2C: %d   \a",i2c_read());
                      //Muestra el valor enviado por el maestro
   }
}

En el programa Esclavo podemos ver que es mas sencillo aun, el mismo consulta mediante un if si la función i2c_poll(); es verdadera o falsa, si es verdadera es porque hay un dato en la entrada del puerto I2C, de esta forma procedemos a mostrar el valor del dato enviado por el maestro en nuestro LCD.
NOTA: observe que en la impresión del LCD se ha finalizado el sistema con \a, esto es para que en el LCD solo se muestre el ultimo valor de la memoria pisando el anterior, ya que si no utilizamos esto nos mostrara el primer valor que seria 16, ya que como el Maestro envía dos datos (el IDslave o Address , y el dato que proviene del ADC) mostraría el 16 que es  0x10 convertido en decimal.

Podemos ver el circuito que es muy simple, solamente hay que tener en cuenta que la salida del protocolo I2C es a Emisor Común, por lo que debe utilizarse siempre las resistencias de Pull-Up, como se ve en el circuito son de 4k7, es un valor recomendado por Microchip pero puede ser otro valor, claramente si es menor aumentara la corriente del puerto lo que disminuirá la vida útil del microcontrolador, y si es mayor la resistencia aumentara el nivel de ruido eléctrico en el bus.


En el circuito se ha puesto un debugger del bus I2C el cual muestra con el color Verde los bits de Start y de Parada, Con el color Azul se puede ver el dato 0x10 que es el Address que se envia al esclavo y con el color Rojo el valor que esta siendo enviado por el bus, en este caso el ADC esta enviando el valor 0x30 el cual al pasar por el printf en el Esclavo se convierte a decimal como el valor 48.




12 comentarios:

  1. Hola Sebastián,

    He leido tu artículo y visto tu video.

    Me queda una duda con respecto con respecto al envío de la dirección Address por parte del Maestro:

    En el caso del LCD, el mismo es direccionado por la dirección IDslave, en este caso, el Esclavo como se agencia que su dirección es la mencionada por IDslave?

    Te lo pregunto por que no me doy cuenta como es que se envía la dirección Addres primero e inmediatamente el dato.

    Se me ocurre que internamente el LCD tiene alguna manera de determinar si aceptará el dato o no.

    Disculpa si la pregunta parece sencilla pero estoy tratando de entender el i2c para una aplicación y necesito saber como implementarla adecuadamente.

    Desde ya muchas gracias,

    Un saludo cordial,

    Pablo Silvoni

    ResponderBorrar
    Respuestas
    1. Hola, buen día!, el LCD no tiene nada que ver con el I2C en este caso, el Master es uno de los microcontroladores y el Slave es el otro de los microcontroladores, fíjate que en la configuración del i2c en el microcontrolador Slave tiene aparte de la definición de pines y velocidad, la dirección del Slave (0x10).
      Después el Master tiene que enviar primero la dirección y luego el dato para que el dato enviado por el Master sea recogido solo por el Slave que tiene esa dirección, porque podrías tener varios dispositivos en el mismo bus y tendría que responder solo al que el Master seleccione y no los demás. Pero el LCD es independiente del proyecto, podría haber usado LEDs o algún otro dispositivo de salida.
      Saludos!

      Borrar
  2. Hola Sebastian

    Muy bueno tu artículo.

    Quisiera ayuda pero para utilizar un Micro controlador como Maestro y un Arduino Como esclavo.

    Muchas gracias, Saludos.

    ResponderBorrar
    Respuestas
    1. Hola, si, no hay problema, siempre que tengas la misma velocidad en el bus y el mismo ID, no deberías tener problemas
      Saludos.

      Borrar
  3. hola sebas
    una consulta como seria si el esclavo sensa el adc y el maestro lo muestra en el lcd y solo es de 8 bits por lo que noto si uso el adc10 como aria en ese caso gracias de ante mano

    ResponderBorrar
    Respuestas
    1. Hola como estas?, podes mandar mas de 8 bit si queres, tenes que enviar mas paquetes de datos, por ejemplo podrías mandar dos paquetes de 8bit donde en uno mandas la parte alta del ADC y en el otro la parte baja. Después en el receptor lo reconstruis y lo mostras.
      Saludos.

      Borrar
  4. en tu ejemplo usas el esclavo para mostrar pero como seria si el maestro es el que usa el lcd y el esclavo sensa el adc de ante mano gracias. no entiendo mucho eso del lo de los paquetes en programar si entiendo la idea. de enviar dos paquetes y luego sumarlas al llegar

    ResponderBorrar
    Respuestas
    1. Hola el display es independiente, podes ponerlo en el master o el esclavo, da igual, lo importante es el dato que mandas. En realidad en i2c se denomina que el master "consulta" al esclavo y el esclavo le "responde", de ahi viene la idea.
      Despues el display puede estar en el master y mostrar los datos "respondidos" del esclavo.
      Saludos

      Borrar
  5. HOLA QUE TAL UNA CONSULTA COMO SERIA SI PONGO TRES MAESTROS Y UN SOLO ESCLAVO NO EXISTIRA COLICIONES O ALGO ASI Y SI PODRIAS HACER UN TUTO SOBRE ESO EN YOUTUBE ESTARIA GENIAL GRACIAS DE ANTEMANO TUS INFORMACIONES SON GENIALES...

    ResponderBorrar
    Respuestas
    1. Hola, si de echo no deberías hacer eso, deberías tener siempre un master y después los esclavos que quieras. lo que se suele hacer es dar jerarquía a la red, por ejemplo tener alguno que este entre el máster y el esclavo, pero la toplogia de i2c es de master a muchos a esclavos. Podes hacer la prueba, vas a tener problemas con los ACK y demas... pero bueno romper no vas a romper nada porque son salidas opendrain/opencolector, entonces siempre estan en 1 mediante un pullup y solo controlas cuando bajas la linea.. lo peor que puede pasar es que no se comunique bien. Saludos.

      Borrar
  6. muy buen trabajo me resolviste muchas dudas gracias

    ResponderBorrar
  7. Hola disculpa como puedo descargar la librería.

    ResponderBorrar