Search code examples
pici2c

Data from PIC to PIC via I2C. It works in proteus but not in real life. Why?


Hello im having some problems trying to send data from a pic18f4550 to a pic16f818 by I2C ...

This project uses a 4x4kbd and a lcd library, but this part works fine in real life too.

When you press '1' the master chip will send a byte to the slave IC addressed as 0xA0,

the slave, will receive this byte,store it in the ram or rom (both programs included), and will be readed by the master.

This works fine in Proteus 8, but not in the real life.

I got three different results on three tries, with THE SAME HEX file.

1.PROTEUS 8: It works fine, perfect.

2.PROTEUS 7: It doesnt work but it doesnt hang

3.REAL LIFE: The chip hangs and wont run any other instruction until I reset it.

My compiler is PCW 4.106.

You can download all the project files from here. [proteus simulation + ccs source code]

Can somebody help me with this? Its being a long time since im trying to make this project run and is being a nightmare.

What makes impossible the communication between both microcontrollers?

Why the chip gets hanged?

Thanks for your attention.

Here my master code:

#include <18f4550.h>
#fuses INTRC_IO,NOPROTECT,NOMCLR,NOWDT
#use delay(clock= 4000000)         
#use i2c(Master,fast,sda=PIN_E0,scl=PIN_E1) 
#define LCD_DATA_PORT getenv("SFR:PORTB")
#byte portd=0xf83
#include <lcd18.c>
#include <jkbd4x4d.c>
#include <i2c.c>         
void SEND_I2C(direccion, posicion, dato){

   i2c_start();            // Comienzo comunicación
   i2c_write(direccion);   // Dirección del esclavo en el bus I2C
   i2c_write(posicion);    // Posición donde se guardara el dato transmitido
   i2c_write(dato);        // Dato a transmitir
   i2c_stop();             // Fin comunicación
   delay_ms(50);
 }
 byte READ_I2C (byte direccion, byte posicion) {
byte dato;
   i2c_start();            // Comienzo de la comunicación
   i2c_write(direccion);   // Dirección del esclavo en el bus I2C
   i2c_write(posicion);    // Posición de donde se leerá el dato en el esclavo
   i2c_start();            // Reinicio
   i2c_write(direccion+1); // Dirección del esclavo en modo lectura
   dato=i2c_read(0);       // Lectura del dato
   i2c_stop();             // Fin comunicación
   delay_ms(50);           // Espera finalización del envio
   return dato;
}

void main() {
 char k;  
  lcd_init(); 
  kbd_init(); 
  port_b_pullups(TRUE);  
 lcd_putc("\fPress '1' for \r\nI2C test"); 
 while (TRUE) {
k=  getkey();
if(k=='x'){}else{                                      // Detecting the  key
printf(lcd_putc,"\f%c",k);                             // Print the  key
delay_ms(200);                                         // An anti-re-pressing delay
if(k=='1'){                                            // key 1 detected     
printf(lcd_putc,"\fSent AA to 00");                    // some info
SEND_I2C(0xA0, 0x00, 0xAA);                           // send i2c(chip Address, eeprom address, data)
delay_ms(100);                                         // Giving ages to slave to work
printf(lcd_putc,"\nRead %x",READ_I2C(0xA0, 0x00));  // read i2c (chip Address, eeprom address)

}  }  }} 

And here my slave code

#include <16F818.h>
#device adc=10
#fuses INTRC_IO,NOWDT,NOPROTECT,NOLVP,NOMCLR

#use delay(clock=4000000) 

#use i2c(slave, fast, sda=PIN_B1, scl=PIN_B4, address=0xA0,FORCE_HW)


byte fstate;       //I2C bus state
byte posicion;     //Memory buffer index
byte buffer[0x10]; //Ram address   
#INT_SSP
void ssp_interupt (){

   int incoming;                     //Everithing the master sends is gonna be placed here 
   fstate = i2c_isr_state();         //get I2C bus state 
   if(fstate == 0x80) {              // If master asks for data      
   i2c_write(buffer[posicion]);      // the slave will write the asked data to the I2C bus 
   } 
   else {                            //If the master sends data 
      incoming = i2c_read();         //we read it
  if (fState == 1) {                 //if the information is about the position
         posicion = incoming;        //We save it as a position
      }
      else if (fState == 2) {        //The info is a data
      buffer[posicion]=incoming;     // We save the data in the right position
    }  }  }

void main (){ 
   fState = 0; 
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
  while(true){     }}

Solution

  • #include <18f4550.h>
    #fuses INTRC_IO,NOPROTECT,NOMCLR,NOWDT
    
    #use delay(clock=4000000) 
    

    It seems that my 18f4550 is broken or the fuse config is not ok for the 18f4550 because its not working on the stablished clock speed.

    Somehow the micro is working to 1/4 of the #use delay clock.

    I made a test program using a max 232 and the pc. I built a software in vb.net with scans all baudrate speeds by sending a data to a pic who just makes an echo of the byte received.

    So the vb.net scanner can detect when the right data is being sent back.

    By this way, I ve discovered that the chip (or the baudrate generator) is working to a quarter of the baudrate stablished in the line:

    #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
    

    I have tried with multiple oscillator configurations and never worked properly.

    Then i just have adapted the code to a 18f448 and it worked okay.

    I ll upload all the mentioned software if somebody asks for.

    Thanks to all.