Autor Tema: i2c entre pic  (Leído 5974 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado NelsonPIC

  • PIC10
  • *
  • Mensajes: 12
i2c entre pic
« en: 06 de Septiembre de 2004, 10:52:00 »
Saludos Amigos

He probado una serie de configuraciones que supuestamente, me permitirian lograr la comunicacion entre un 18f452 y un 16f877a por el bus i2c, el primero como maestro y el segundo como esclavo.
Hasta el momento he logrado que el maestro lea y escriba sobre una eeprom 24LC256, pero sobre el esclavo 16f877a No.
El unico ejemplo que he implementado es EX_Slave.c, el compilador que estoy usando es PCWH 206 y el debugger es ICD-U40.
Si alguien ha experimentado exitosamente la comm i2c y pueda orientarme mas.

Gracias al foro, he logrado muchas cosas interesantes.

NelsonPIC

Desconectado pacalaconcurso

  • PIC24F
  • *****
  • Mensajes: 718
RE: i2c entre pic
« Respuesta #1 en: 07 de Septiembre de 2004, 14:52:00 »
deberias subir el codigo que escribiste para el maestro, a ver si asi sacamos algo..

saludos

Desconectado NelsonPIC

  • PIC10
  • *
  • Mensajes: 12
RE: i2c entre pic
« Respuesta #2 en: 07 de Septiembre de 2004, 16:11:00 »
Ok Pacala

Aqui va el codigo del maestro y el esclavo, acabo de comprobar que esta rutina si escribe en el esclavo (lo comprove con el ICD-U40), pero la lectura no.

************Maestro********************

#include <18F452.h>
#device icd=true
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)  // Jumpers: 8 to 11, 7 to 12

#include <input.c>
#include <2402.c>


void main() {

   BYTE value, cmd;
   EEPROM_ADDRESS address;

   init_ext_eeprom();

   do {
      do {
         printf("
Read or Write: ";
         cmd=getc();
         cmd=toupper(cmd);
         putc(cmd);
      } while ( (cmd!="R") && (cmd!="W") );

      printf("
Location: ";

#if sizeof(EEPROM_ADDRESS)==1
      address = gethex();
#else
#if EEPROM_SIZE>0xfff
      address = gethex();
#else
      address = gethex1();
#endif
      address = (address<<8)+gethex();
#endif

      if(cmd=="R")
         printf("
Value: %X
",READ_EXT_EEPROM( address ) );

      if(cmd=="W") {
         printf("
New value: ";
         value = gethex();
         printf("
";
         WRITE_EXT_EEPROM( address, value );
      }
   } while (TRUE);
}


********************Esclavo********************

#include <16F877A.h>
#device ICD=TRUE
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)  // Jumpers: 8 to 11, 7 to 12


#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0, slow)

typedef enum {NOTHING, CONTROL_READ,
              ADDRESS_READ, READ_COMMAND_READ} I2C_STATE;

I2C_STATE fState;
BYTE address, buffer[0x10];

#INT_SSP
void ssp_interupt ()
{
   BYTE incoming;

   output_bit (pin_b0, true);

   if (i2c_poll() == FALSE) {
      if (fState == ADDRESS_READ) {  //i2c_poll() returns false on the
         i2c_write (buffer[address]);//interupt receiving the second
         fState = NOTHING;           //command byte for random read operation
      }
   }
   else {
      incoming = i2c_read();

      if (fState == NOTHING){
         fState = CONTROL_READ;
      }
      else if (fState == CONTROL_READ) {
         address = incoming;
         fState = ADDRESS_READ;
      }
      else if (fState == ADDRESS_READ) {
         buffer[address] = incoming;
         fState = NOTHING;
      }
   }
}

void main ()
{
   int i;

   fState = NOTHING;
   address = 0x00;
   for (i=0;i<0x10;i++)
      buffer = 0x00;

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_SSP);

   while (TRUE) {

   delay_ms(1000);
   output_bit (pin_b0, false);
   }
}


Cuando elijo la opcion de leer "R" (a travez de Hiperterminal) este me devuelve el valor FF, por su puesto no es el dato que mande a escribir.

NelsonPIC


Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7918
RE: i2c entre pic
« Respuesta #3 en: 07 de Septiembre de 2004, 16:18:00 »
Estas seguro que esta bien implementado el I2C entre ellos??
No te olvides que el maestro en este caso usa una direccion y protocolo de una memoria serial...
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7918
RE: i2c entre pic
« Respuesta #4 en: 07 de Septiembre de 2004, 16:20:00 »
Otra cosa:
Pusiste dos resistencias a +5v ??
Deberias tener ambas lineas SCL y SDA a nivel alto, para ello se necesitan dos resistencias (creo que 4K7 Ohm ) a +5V....
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado NelsonPIC

  • PIC10
  • *
  • Mensajes: 12
RE: i2c entre pic
« Respuesta #5 en: 08 de Septiembre de 2004, 07:37:00 »
Respondiendo la primera inquetud de MGLSOFT, correcto eso se llama codigo de identificacion, dentro del byte de direccion, para la memorias seriales serian un 1010 A2 A1 A0 R/W, en este caso se sigue utilizando este mismo codigo en la emulacion de Esclavo, en cuanto a la resistencias de Pull Up se pueden utilizar dependiendo de la velocidad de transmision       < 100kbps   100kps    400kps
Resistencias en SDA y SCK a Vcc de      4.7k         2.2k        1k

Les adjunto el link de un documento de Microchip para sus comentarios http://ww1.microchip.com/downloads/en/DeviceDoc/i2c.pdf

NelsonPIC

Desconectado oshow

  • PIC18
  • ****
  • Mensajes: 321
RE: i2c entre pic
« Respuesta #6 en: 08 de Septiembre de 2004, 07:50:00 »
Si me permitís.... una pregunta de novato en i2c, donde esta la linea que identifica al 18 como master?, esa de #use i2c (master,....); o es que no hace falta?


Saludos.

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7918
RE: i2c entre pic
« Respuesta #7 en: 08 de Septiembre de 2004, 10:19:00 »
Esta incluida en la libreria de la memoria I2C....
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado oshow

  • PIC18
  • ****
  • Mensajes: 321
RE: i2c entre pic
« Respuesta #8 en: 08 de Septiembre de 2004, 10:23:00 »
jejeje, que despiste el mio, ya me parecia raro ver el codigo sin esa directiva....

Gracias MGL

Saludos.

Desconectado Tec_Claudio_Perez

  • PIC12
  • **
  • Mensajes: 62
RE: i2c entre pic
« Respuesta #9 en: 22 de Septiembre de 2004, 20:00:00 »
Hola,

Para un projecto intenté comunicar por I2C un 16F873 como maestro y un 16F876 como esclavo. Creo que usaba el mismo código que el tuyo.
En mi rutina el esclavo tiene un LCD y un teclado matricial, y el maestro lee del AD y envía variables al esclavo para su visualización cada 250 ms.
El maestro escribía muy bien el valor, y por lo general también lee bien, pero de vez en cuando al leer el esclavo, no solo leía 0xFF sino que también se cuelga el módulo I2C del esclavo, y el maestro deja de transmitir.

Encontré en el foro de CCS una referencia a un problema similar que adjudica el fallo a un error de silicio del módulo SSP de algunos modelos de microcontroladores pic, donde efectivamente la falla parece ser la misma:

http://ww1.microchip.com/downloads/en/DeviceDoc/80132c.pdf

Alguien tuvo un problema similar ?

En este link también se describe el mismo problema:
http://www.ccsinfo.com/forum/viewtopic.php?t=19256&highlight=ssp+errata

Yo todavía estroy tratando de resolverlo, no sé si la falla es por las rutinas I2C del CCS, una alternativa es no utilizar las librerías I2C por defecto y reescribir las rutinas utilizando las notas de aplicación 734 y 735 de Microchip.

Otra opción es usar PicBasic Pro para el código del esclavo, o directamente hacerlo en assembler. Pero si es una falla del silicio...

Me gustaría saber de tus progresos.

       Téc. Claudio J. Pérez
interrupt_request@hotmail.com
 Ciberar-Sistemas y Desarrollos

Desconectado juno303

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 103
RE: i2c entre pic
« Respuesta #10 en: 23 de Septiembre de 2004, 10:03:00 »
ya que estamos.  Cual es la distancia maxima que pueden tenes los cables del i2c ???

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7918
RE: i2c entre pic
« Respuesta #11 en: 24 de Septiembre de 2004, 10:12:00 »
Utilizan el RESTART_WDT dentro de la llamada al I2C en C ??
Eso hay que tenerlo en cuenta en los esclavos....
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado NelsonPIC

  • PIC10
  • *
  • Mensajes: 12
RE: i2c entre pic
« Respuesta #12 en: 27 de Septiembre de 2004, 08:10:00 »
Saludos

Respondiendo luego de una semana de ausencia (por Trabajo ), bueno efectivamente lo que comenta Tec_Claudio_Perez con respecto de la aparicion en la lectura de bytes 0xFF me sucede en este mismo momento, hasta el momento he logrado y comprobado que la escritura si funciona, pero la lectura no.
Estoy retomando el problema ya que lo que pretendo hacer, me es fundamental tener una bus para los perifericos manejados por un sola maestro que los pueda interrogar, gracias por el interes y lo mas seguro que daremos con este problema.

NelsonPIC


Desconectado Tec_Claudio_Perez

  • PIC12
  • **
  • Mensajes: 62
RE: i2c entre pic
« Respuesta #13 en: 13 de Octubre de 2004, 08:59:00 »
Hola, este es el codigo lee y graba en el esclavo, pero de vez en cuando si el esclavo modifica el valor en la posicion 0 de su mapa de memoria I2C, al leer este valor desde el maestro, el esclavo se cuelga, y desde el maestro solo se lee 0xFF. Si se resetea el esclavo, la comunicacion se reestablece.

Este es el código del maestro:

/*
;***************************************************************************************
;Proyecto: Comunicacion I2C entre un PIC 16F873 (maestro) y un PIC16F876 (esclavo).
;Versión: 0.1
;Autor: Claudio J. Pérez (interrupt_request@hotmail.com)
;***************************************************************************************
;Descripción:
;       Este es el codigo del maestro.
;
;   Watchdog: Off          Power Up Timer: On
;    Cristal: 20 Mhz        Tipo de Reloj: HS
;Code Protection: Off
;***************************************************************************************
*/
#include <16F873.h>
#use delay(clock=20000000)
#fuses HS,PUT,LVP, WRT,NOWDT  //LVP y WRT para el bootloader, poner pulldown 10K en RB3.

//Driver del RS-232.
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7)

//Driver del I2C.
#use i2c(master, sda=PIN_C4, scl=PIN_C3)

//Declaracion de variables globales.
byte Dato_escribir;      // Almacena el byte a grabar en el esclavo.
byte Dato_leer;      // Almacena el byte leido desde es el esclavo.
short int BandEscribir=FALSE;   // Esta bandera indica que se debe escribir en el esclavo.

//----------------------------------------------------------------------
//Esta rutina se ejecuta cada vez que se recibe un byte por la USART.
//----------------------------------------------------------------------
#int_rda
void UartRX_isr() {
    Dato_escribir=getc();   //Leer el byte del buffer.
    BandEscribir=TRUE;   //Indicar que se recibio un byte.
}

//Esta rutina inicializa los pines del bus I2C.
void init_slave() {
    output_float(PIN_C3);
    output_float(PIN_C4);
}

//Esta rutina escribe un byte en el esclavo.
//chadd es la direccion del esclavo 0-7 (0xA0 hasta 0xA7).
//address es la posicion de memoria.
//data es el byte a escribir.
void write_slave(byte chadd, int address, byte data) {
    short int status;
    chadd = (chadd<<1) + 0xa0;
    i2c_start();
    i2c_write(chadd);
    i2c_write(address);
    i2c_write(data);
    i2c_stop();
}

//Esta rutina lee un byte desde el esclavo.
//chadd es la direccion del esclavo 0-7 (0xA0 hasta 0xA7).
//address es la posicion de memoria.
//La función devuelve el byte leido.
byte read_slave(byte chadd, int address) {
   byte data;
    chadd = (chadd<<1) + 0xa0;
    i2c_start();
    i2c_write(chadd);
    i2c_write(address);
    i2c_start();
    chadd = chadd | 1;
    i2c_write(chadd);
    data=i2c_read(0);
    i2c_stop();
    return(data);
}

void main() {

    //Inicializar los puertos.
    set_tris_a(0b11111111); // todo el puerto A como entradas.
    set_tris_b(0b00000000); // todo el puerto B como salidas.
    set_tris_c(0b10000000); // RX como entrada, el resto salidas.

    init_slave();

    enable_interrupts(INT_RDA);
    enable_interrupts(GLOBAL);

    do {
        if (BandEscribir==TRUE) {
        BandEscribir=FALSE;
        write_slave(0x00,0x00,Dato_escribir);   //Escribir el byte recibido por RS-232 en la posicion 0.
        Dato_leer=read_slave(0x00, 0x00);       //Leer el byte en la posicion 0 del esclavo.
        putc(Dato_leer);                        //Enviar el byte por RS-232.
       }
    } while(TRUE);
}


Y este es el código del esclavo:
/*
;***************************************************************************************
;Proyecto: Comunicacion I2C entre un PIC 16F873 (maestro) y un PIC16F876 (esclavo).
;Versión: 0.1
;Autor: Claudio J. Pérez (interrupt_request@hotmail.com)
;***************************************************************************************
;Descripción:
;       Este es el codigo del esclavo.
;
;   Watchdog: Off          Power Up Timer: On
;    Cristal: 20 Mhz        Tipo de Reloj: HS
;Code Protection: Off
;***************************************************************************************
*/
#include <16F876.h>
#use delay(clock=20000000)
#fuses HS,PUT,LVP,WRT,NOWDT  //LVP y WRT para el bootloader, poner pulldown 10K en RB3.

//Driver del RS-232.
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7)

// Driver para la comunicación I2C en modo esclavo.
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0)

// Variables del bus I2C.
typedef enum {NOTHING, CONTROL_READ, ADDRESS_READ, READ_COMMAND_READ} I2C_STATE;
I2C_STATE fState;
int address;            //Almacena la posicion de memoria a leer o escribir.
int buffer[0x25];       //Buffer de memoria.

short int BandGrabado=FALSE;   // Esta bandera indica que se escribio la posicion 0.
short int BandLeido=FALSE;       // Esta bandera indica que se leyo la posicion 0.

//------------------------------------------------------------------------------
//Esta es la rutina de servicio de la interupción del modulo SSP.
//------------------------------------------------------------------------------
#int_ssp
void ssp_interupt() {
   byte incoming;                   // Almacena el byte leido recibido del bus I2C.

   if (i2c_poll() == FALSE) {
      if (fState == ADDRESS_READ) {  // i2c_poll() devuelve falso en la segunda
         i2c_write (buffer[address]);// interrupcion al recibir el byte de comando para
         fState = NOTHING;           // lectura en modo aleatorio.
         // Si se terminó de leer la posicion 0.
         if (address==0x00) {
            BandLeido=TRUE;
         }
      }
   }
   else {
      incoming = i2c_read();        // Leer el byte del buffer de recepción I2C.
      if (fState == NOTHING){
         fState = CONTROL_READ;
      }
      else if (fState == CONTROL_READ) {
         address = incoming;
         fState = ADDRESS_READ;
      }
      else if (fState == ADDRESS_READ) {
         buffer[address] = incoming;
         fState = NOTHING;
         // Si se terminó de escribir la posicion 0.
         if (address==0x00) {
            BandGrabado=TRUE;
         }
      }
   }
}


void main() {
    int i;

    //Inicializar los puertos.
     set_tris_a(0b11111111);         // todo el puerto A como entradas.
      set_tris_b(0b00000000);         // todo el puerto B como salidas.
   set_tris_c(0b10011000);         // RX, SDA y SCL como entradas, el resto salidas.

   //Inicializar el buffer de la comunicacion I2C.
    fState = NOTHING;
    address = 0x00;
    for (i=0;i<26;i++)
        buffer = 0x00;             // Borrar todo el buffer.

    //Habilitar la interrupción del puerto I2C.
    enable_interrupts(INT_SSP);
    // Habilitar las interrupciones.
    enable_interrupts(GLOBAL);

    do {
        //Si se escribio algo en la posicion 0, indicarlo por RS-232.
        if (BandGrabado==TRUE) {
        BandGrabado=FALSE;
        printf ("Byte grabado en posicion 0:");
          putc(buffer[0]);
       }
        //Si se leyo la posicion 0, indicarlo por RS-232.
      if (BandLeido==TRUE) {
          BandLeido=FALSE;
          printf ("Byte leido de posicion 0:");
          putc(buffer[0]);
      }
    } while(TRUE);
}

Prueben si ven algo raro.
Téc. Claudio J. Pérez