Problema con I2C entre PICs

Buenos días

Actualmente estoy iniciando en el tema de la comunicación por I2C. Buscando en internet encontré un ejemplo muy básico de la comunicación entre 2 PIC: el maestro tiene un teclado matricial 4X4 y el esclavo tiene una LCD.

El ejemplo en cuestión es el siguiente:



Maestro
Código:
////////////////////////////////////////////////////////////////////////////////
//                    COMUNICACIÓN I2C EN TRE DOS PIC                         //
//                                                                            //
//                      Aplicación para PIC MAESTRO                           //
//                                                                            //
//       El PIC maestro lee teclado y envía el dato al PIC esclavo via I2C    //
//                      que lo mostrará en un lcd.                            //
//                                                                            //
//                            (c) RobotyPic                                   //
////////////////////////////////////////////////////////////////////////////////

#include <16F876a.h>

#fuses XT,PUT,NOPROTECT,BROWNOUT,NOLVP,NOWDT
#use delay (clock=4000000)                      

#use i2c(MASTER, SDA=PIN_C4, SLOW, SCL=PIN_C3, NOFORCE_SW)

#define use_portb_kbd TRUE       //Configuración puerto b para lectura teclado
#include <kbd.c>                 //Carga archivo para control de teclado

#use standard_io(b)
#use standard_io(c)

int tecla;                       //Dato a transmitir
   
/******************************************************************************/
/***************************** Envío I2C **************************************/
    
void envio_I2C (){
   
      i2c_start();         //Comienzo de la comunicación I2C ...
      i2c_write(0xa0);     //...con la dirección del PIC esclavo...
      i2c_write(tecla);    // Envia dato
      i2c_stop();          //Finalización de la transmisión
  }

/******************************************************************************/
/*************************** FUNCIÓN PRINCIPAL ********************************/

void main(){
   kbd_init();                   //Inicializa función de teclado
   port_b_pullups(TRUE);         
    
   while (true){
      
// Lectura del teclado     
      tecla=kbd_getc();       //En "tecla" valor de la tecla pulsada
      if(tecla!=0){           //Si se pulsa teclado...
            envio_I2C();      //...se envía el dato
            delay_ms(100);
      }
   }
}

Esclavo
Código:
////////////////////////////////////////////////////////////////////////////////
//                    COMUNICACIÓN I2C EN TRE DOS PIC                         //
//                                                                            //
//                      Aplicación para PIC ESCLAVO                           //
//                                                                            //
//       El PIC maestro lee teclado y envía el dato al PIC esclavo via I2C    //
//                      que lo mostrará en un lcd.                            //
//                                                                            //
//                            (c) RobotyPic                                   //
////////////////////////////////////////////////////////////////////////////////

#include <16F876a.h>
#fuses XT
#use delay (clock=4000000)

#use standard_io(b)
#use standard_io(c)
#use I2C(SLAVE, SDA=PIN_C4 ,SLOW, SCL=PIN_C3, ADDRESS=0xa0, NOFORCE_SW)

#define use_portb_lcd TRUE
#include <lcd.c>

void main() {
 
   int dato;
   lcd_init();  
   
   while (1) {
   
      // Recepción por comunicación I2C     
      if(i2c_poll()) {
         dato=i2c_read();
         lcd_putc(dato);                  //Muestra dato recibido por pantalla
         if (dato==\'*\') lcd_putc("\\f");   //Si es * borra la pantalla lcd
         }
   }
}

Este ejemplo funciona correctamente.

Ahora bien, el PIC que yo voy a utilizar es un PIC16F1827, por lo que realicé algunos cambios en el programa:



Maestro
Código:
#include <16F1827.h>
#fuses XT,PUT,NOPROTECT,BROWNOUT,NOLVP,NOWDT
#use delay(clock=32M)
#use RS232(BAUD=9600, XMIT=PIN_B2, RCV=PIN_B1, stream=com,errors)
//#use i2c(MASTER, SDA=PIN_B1, SLOW, SCL=PIN_B4, NOFORCE_SW)

char i = 0;

/*void envio_I2C (){
   i2c_start();
   i2c_write(0xA0);
   i2c_write(i);
   i2c_stop();
}*/

void main(){
   output_LOW(PIN_B6);
   while(true){
      if(input(PIN_A0)){
         //envio_I2C();
         putc(i);
         output_toggle(PIN_B6);
         i++;
         if(i>9){i=0;}
         while(input(PIN_A0)){;}
      }
   }
}

Esclavo
Código:
#include <16F1827.h>
#fuses XT
#use delay(clock=32M)
#use RS232(BAUD=9600, XMIT=PIN_B2, RCV=PIN_B1, stream=com,errors)
//#use I2C(SLAVE, SDA=PIN_B2 ,SLOW, SCL=PIN_B5, ADDRESS=0xA0, NOFORCE_SW)

void main(){
   int num[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x83,0xB8,0x80,0x98};
   
   //set_tris_a(0);
   
   output_LOW(PIN_B6);
   
   while(true){
       /*if(i2c_poll()){
         output_a(num[i2c_read()]);
         output_toggle(PIN_B6);
       }*/
       if(kbhit(com)){
         output_a(num[getc()]);
         output_toggle(PIN_B6);
       }
   }
}

Aún siendo un esquema tan sencillo, lo probé antes por comunicación serial (están las líneas de código tanto para comunicación serial como para I2C) y funcionó correctamente.
Luego de unas pruebas con el I2C, y ningún resultado exitoso, le puse un LED a cada PIC para saber cuándo envía un dato, en caso del maestro, y cuando recibe un dato, en caso del esclavo.
En la comunicación serial funcionan correctamente los dos LED.
En la comunicación por I2C, el LED del PIC maestro enciende y apaga correctamente, pero el del PIC esclavo no hace nada.

Dónde podría estar el error ??? He comparado con el código del ejemplo y no veo alguna diferencia con la comunicación.

Pd: el Display 7 Segmentos, por alguna razón, no enciende el segmento del medio ("g") ni en la comunicación serial. Aunque no es indispensable para el proyecto, también tengo esta duda. ...
 

Adjuntos

  • I2C.rar
    15.8 KB · Visitas: 5
Última edición:
.


No olvides que ambas líneas de I2C deben llevar las resistencias Pull-Up !!!!!

En la primer imagen son las R2 y R3 que no figuran en tu ejemplo del 16F1827. Tengo entendido que no sirve colocar las Pull-Up internas de cada µControlador.




Saludos, JuanKa.-
 

D@rkbytes

Moderador
Aún siendo un esquema tan sencillo, lo probé antes por comunicación serial (están las líneas de código tanto para comunicación serial como para I2C) y funcionó correctamente.
Luego de unas pruebas con el I2C, y ningún resultado exitoso, le puse un LED a cada PIC para saber cuándo envía un dato, en caso del maestro, y cuando recibe un dato, en caso del esclavo.
En la comunicación serial funcionan correctamente los dos LED.
En la comunicación por I2C, el LED del PIC maestro enciende y apaga correctamente, pero el del PIC esclavo no hace nada.
La función I2C_POLL(Stream) se usa cuando la transmisión es por hardware.
La ayuda de PIC C dijo:
The I2C_POLL() function should only be used when the built-in SSP is used.
This function returns TRUE if the hardware has a received byte in the buffer.
When a TRUE is returned, a call to I2C_READ() will immediately return the byte that was received.
Entonces la configuración del esclavo debe ser esta:
Código:
[B][COLOR=Red]#include [/COLOR]<[COLOR=SeaGreen]16[/COLOR]F1827.h>
[COLOR=Red]#fuses[/COLOR]   NOMCLR
[COLOR=Red]#use[/COLOR]     delay(internal = [COLOR=SeaGreen]32[/COLOR]MHz)
[COLOR=Red]#use[/COLOR]     I2C(I2C1, SLAVE, SLOW, ADDRESS = [COLOR=SeaGreen]0xA0[/COLOR])[/B]
¿Dónde podría estar el error?
He comparado con el código del ejemplo y no veo alguna diferencia con la comunicación.
Se usaron otros PIC y he ahí la gran diferencia.
Siempre se debe tener consideración sobre los puertos involucrados para poder adaptar un programa.
Pd: el Display 7 Segmentos, por alguna razón, no enciende el segmento del medio (ni en la comunicación serial.
Aunque no es indispensable para el proyecto, también tengo esta duda.
El PIC Esclavo está configurado para usar oscilador a cristal, y estás usando los pines del oscilador para controlar el display.
Cuando se usa el oscilador a cristal, esos pines ya no están disponibles como I/O
Aparte, el pin RA5 (MCLR) es únicamente entrada y también lo tienes conectado al display.

Otro detalle a tener en cuenta cuando se simula I2C en proteus, es que se deben configurar las resistencias Pull-Up como digitales, y en tu esquema las dejaste como análogas. (R2, R3 del archivo RAR adjunto.)
 
Última edición:
Hola, Buenos Días. Soy nuevo en el foro y este es mi primer post.
Soy Ing. en Electrónica y quisiera que me ayuden a resolver una duda que tengo.
Empecé a practicar el protocolo i2c con algunos microcontroladores que tenía a la mano, entonces empecé a investigar cómo funcionaba el bus y todo de su teoría a fondo.

Programo con CCS C compiler y me he basado mucho con sus comandos de ayuda, pero he llegado a un punto que no sé como resolverlo.
He checado en otros lados esto pero no entiendo cómo resolver este problema.

Estoy utilizando un microcontrolador PIC16F84A como maestro, su única función es controlar un teclado de 4x4 y mandar el carácter por el bus a un PIC18F4550 como esclavo que controla una LCD de 16x2
La comunicación se da de manera correcta, puedo mandar datos y visualizarlos pero el problema radica en que la tecla que yo elijo se ve duplicada en la LCD aun cuando nada más está seleccionado el primer espacio del segundo renglón de la pantalla y este se duplica en el segundo espacio.

¿Alguien me podría ayudar a resolver esto?
He movido el código de ambos PIC para ver si el error radica en ellos o quizás es algo que ignoro por completo en alguna instrucción del bus.

Gracias. Aquí dejo los códigos.

Maestro
C:
#include <16F84A.h>

#fuses XT,NOWDT,NOPUT,NOPROTECT

#use delay(clock=4,000,000)

#use i2c(master,slow ,sda=pin_a0, scl=pin_a1,force_sw)

#define use_portb_kbd

#include <KBD4x4.c>


char k;  //Caracter que se presiona


void main(){

kbd_init(); //Inicializa el teclado

port_b_pullups(true);// Activamos las pullups internas del puerto B


while(TRUE){

k=kbd_getc(); // Si alguna tecla se presiona es almacenada en la variable k.


if(k!=0){

  i2c_start();        // Comienzo de la comunicación I2C

  i2c_write(0xa0);    // Dirección del PIC esclavo la direccion se la asignamos nosotros puede ser cualquiera

  i2c_write(k);       // Dato enviado

  i2c_stop();         // Detenemos la comunicacion

//  delay_ms(100);      // Asigno un tiempo de espera para recuperar

} 

}

}
Esclavo
C:
#include <18F4550.h>

#fuses INTRC_IO,NOPROTECT,NOWDT,NOMCLR

#use i2c(SLAVE, SLOW, SDA=PIN_B0 ,SCL=PIN_B1, ADDRESS=0xa0)

#use delay(internal=8M)

#include <LCD.C>

#define use_portd_lcd TRUE


char dato;


void main(){

lcd_init();


while(TRUE){

      if(i2c_poll()){

         dato=i2c_read();

         lcd_putc(dato);

         lcd_gotoxy(1,1);

         printf(lcd_putc,"Tecla:");

         lcd_gotoxy(1,2);

         printf(lcd_putc,"%c",dato);

       }

}

}
 

D@rkbytes

Moderador
Falta el esquema y la librería KBD4x4.c
Para recibir mejor colaboración siempre es conveniente subir el proyecto completo dentro de un archivo comprimido.
 

Dr. Zoidberg

Well-known-Papá Pitufo
C:
dato=i2c_read();
         [B]lcd_putc(dato);[/B]
         lcd_gotoxy(1,1);
         printf(lcd_putc,"Tecla:");
         lcd_gotoxy(1,2);
         [B]printf(lcd_putc,"%c",dato);[/B]
Yo veo que en el esclavo hay una invocacion a lcd_putc(dato) y una llamada a printf( lcd_putc, "%c", dato)....ergo, estas mostrando dos veces lo mismo....
 
C:
dato=i2c_read();
         [B]lcd_putc(dato);[/B]
         lcd_gotoxy(1,1);
         printf(lcd_putc,"Tecla:");
         lcd_gotoxy(1,2);
         [B]printf(lcd_putc,"%c",dato);[/B]
Yo veo que en el esclavo hay una invocacion a lcd_putc(dato) y una llamada a printf( lcd_putc, "%c", dato)....ergo, estas mostrando dos veces lo mismo....
Aqui lo que hago es mostrar un unico texto que diga la palabra "tecla" y en la segunda el dato enviado, esto afecta en algo??
 

D@rkbytes

Moderador
Si usas: lcd_putc(dato); estarás mostrando datos sin formato.
O sea que no se verá nada en la pantalla hasta el número 33, que empezará por ser el carácter "!"
Al formatear con "%c" estás realizando prácticamente lo mismo.
En dado caso que quieras visualizar el valor de un carácter tendrías que formatear con "%u" y será desde 0 hasta 255

Ver Tabla ASCII
 
Falta el esquema y la librería KBD4x4.c
Para recibir mejor colaboración siempre es conveniente subir el proyecto completo dentro de un archivo comprimido.
De acuerdo lo tomare en cuenta en futuros post
Falta el esquema y la librería KBD4x4.c
Para recibir mejor colaboración siempre es conveniente subir el proyecto completo dentro de un archivo comprimido.
De acuerdo lo tomare en cuenta en futuros post
Gracias voy a probar
 
Arriba