Page 1 of 3

PIC 2 PIC Master/Slave Communication using I2C... Enjoy

Posted: 06 Dec 2006 05:04
by TomSSS
Hi all, here is some simple code for Master/Slave I2C projects. I can't take all of the credit for writing this. I used mB and mP code/methods that I found on the forum and translated it into this. Feel free to comment, but I might not be quick to respond because I only get on here about 1-2 times a week.

Here's the Master code

Code: Select all

/*
 * Project name:
     Master
 * Description:
     Master control for PIC 2 PIC I2C Communication
 * Configuration:
     MCU:             PIC16F876A
     SW:              mikroC v6.0
 * NOTES:
*/

//------------------------------------------------------------------------------
const Slave_Addy = 0x69;

void send(unsigned short send_data){
  I2C_Init(100000);
  I2C_Start();
  I2C_Wr(Slave_Addy);
  I2C_Wr(send_data);
  I2C_Stop();
}

unsigned short read(){
  unsigned short read_data;
  I2C_Init(100000);
  I2C_Start();
  I2C_Wr(Slave_Addy + 1);
  read_data = I2C_Rd(0);
  delay_ms(100);
  I2C_Stop();
  return read_data;
}

void main(){
 // Main program code place here.  
 // Use sub-routine "send" to send data to slave.
 // Use "read" to read data from slave.
}
Here's the Slave code

Code: Select all

/*
 * Project name:
     Slave
 * Description:
     Slave code for PIC 2 PIC I2C Communication
     Write data from Master to PORTB
     Send PORTC data to Master
 * Configuration:
     MCU:             PIC16F876A
     SW:              mikroC v6.0
 * NOTES:
*/

//------------------------------------------------------------------------------
const Addy = 0x69;                    // set I2C device address
const Delay_Time = 250;               // port check delay
//------------------------------------------------------------------------------
//                      Global Processing Variables
//------------------------------------------------------------------------------
unsigned short j;                      // just dummy for buffer read
unsigned short rxbuffer;               // 
unsigned short tx_data;                //
//------------------------------------------------------------------------------
void Init(){
  ADCON1 = 0;                          // All ports set to digital
  TRISA = 0;                           // Set PORTA as output
  TRISB = 0;                           // Set PORTB as output
  TRISC = 0xFF;                        // Set PORTC as input
  SSPADD =  Addy;                      // Get address (7bit). Lsb is read/write flag
  SSPCON = 0x36;                       // Set to I2C slave with 7-bit address
  PIE1.SSPIF = 1;                      // enable SSP interrupts
  INTCON = 0xC0;                       // enable INTCON.GIE
}
//------------------------------------------------------------------------------
void interrupt(){                      // I2C slave interrupt handler
  if (PIR1.SSPIF == 1){                // I2C Interrupt
    PIR1.SSPIF = 0;                    // reset SSP interrupt flag

    //transmit data to master
    if (SSPSTAT.R_W == 1){             // Read request from master
      SSPBUF = tx_data;                // Get data to send
      SSPCON.CKP = 1;                  // Release SCL line
      j = SSPBUF;                      // That's it
      return;
    }
    if (SSPSTAT.BF == 0){              // all done,
      j = SSPBUF;                      // Nothing in buffer so exit
      return;
    }

    //recieve data from master
    if (SSPSTAT.D_A == 1){             // Data [not address]
      rxbuffer = SSPBUF;               // get data
      j = SSPBUF;                      // read buffer to clear flag [address]
      return;
    }
  }
  j = SSPBUF;                              // read buffer to clear flag [address]
}
//------------------------------------------------------------------------------
void main(){
  Init();
  while(1){
    PORTB   = rxbuffer;
    tx_data = PORTC;
    Delay_ms(Delay_Time);
  }
}
Enjoy,
Tom

Re: PIC 2 PIC Master/Slave Communication using I2C... Enjoy

Posted: 06 Dec 2006 09:04
by zristic
Thanks.

Posted: 07 Dec 2006 13:48
by gedo
thanx. but i send data from master do not read on slave portB.
master PortC.F3 to Slave PortC.F4 & M PortC.F4 To S PortC.F3 is right shematic.

Posted: 08 Dec 2006 01:08
by TomSSS
gedo wrote:thanx. but i send data from master do not read on slave portB.
master PortC.F3 to Slave PortC.F4 & M PortC.F4 To S PortC.F3 is right shematic.
I'm not sure if you are asking a question here or trying to state something but I'll try to explain a little bit more.

You send serial data from the Master to the Slave using these two lines.
PORTC.F3 is the SCL line
PORTC.F4 is the SDA line


The pin mapping (schematic) should be:
Master PORTC.F3 -> Slave PORTC.F3
Master PORTC.F4 -> Slave PORTC.F4

Those are the I2C lines on the 16F876A.

The slave program takes the serial data from the master, 8-bits, and sets the PORTB output of the slave device based on this.

Example:
-------------
The master sends the following data stream 00110011
The slave would set its PORTB = 00110011

If the slave recieves a "read" command the slave will read its PORTC and compile this into serial data to be sent via I2C to the master.

Note: Bits 3 and 4 of the PORTC data sent from the slave to the master should be ignored by the master because these are the I2C lines.

No Interrupt in I2C slave

Posted: 12 Aug 2008 07:18
by Remoeggel
Hello Tom

I try to put your code in my program for a slave I2C pic.
But i get never a interrupt.
Do you know what could be the problem?

Code if interrupt has occured:

Code: Select all

void interrupt(){
   
    if (PIR1.SSPIF = 1){
    
        static unsigned short reg = SERVO_REG_MAX;
    
        PIR1.SSPIF = 0;
        PORTD.F0 = 1;
       
        //transmit data to master
        if (SSPSTAT.R_W == 1){             // Read request from master
          if (reg < SERVO_REG_MAX){
             SSPBUF = servo_register[reg]; // Get data to send
             reg = SERVO_REG_MAX;
             SSPCON.CKP = 1;               // Release SCL line
             j = SSPBUF;
          }                                // That's it
          return;
        }
        if (SSPSTAT.BF == 0){              // all done,
          j = SSPBUF;                      // Nothing in buffer so exit
          return;
        }

        //recieve data from master
        if (SSPSTAT.D_A == 1){             // Data [not address]
          //PORTD.F0 = 0;
          if (reg < SERVO_REG_MAX){
               servo_register[reg] = SSPBUF;  // get data
               j = SSPBUF;                    // read buffer to clear flag [address]
               reg = SERVO_REG_MAX;
          }
          else {
               reg = SSPBUF;
               j = SSPBUF;                    // read buffer to clear flag [address]
          return;
        }
        }
        j = SSPBUF;                              // read buffer to clear flag [address]
       
    }
}

Code for init:

Code: Select all

//* iniyialisieren des I2C Interface *//
    SSPADD =  0xC2;                      // Get address (7bit). Lsb is read/write flag
    SSPCON = 0x34;                       // Set to I2C slave with 7-bit address
    
    //* Interrupts erlauben *//
    INTCON.GIE = 1;
    INTCON.PEIE = 1;
    PIE1.SSPIE = 1;                      // enable SSP interrupts
    PIE1.TMR1IE = 1;
    PIR1.TMR1IF = 0;
    PIR1.SSPIF = 0;

Best regards

Remo Hug

Thank you a lot

Posted: 12 Aug 2008 10:27
by prancius
Thank you a lot for example.

It is exactly what i need. I will chect it via proteus soon.

Regards,
Pranas

Error

Posted: 12 Aug 2008 12:16
by prancius
Strange but i have some problem.

I am using 4k7 external rezistors and 8MGhz frequency


Image

Trying to find out the problem

Posted: 12 Aug 2008 14:15
by Remoeggel
Hi Pranas

I use the PIC 16F877A (8MHz) with the EasyPIC5-Board.

Regards,
Remo

about second pic

Posted: 12 Aug 2008 15:05
by prancius
Hello,

Can you give some explanation how you connected second PIC16F877A?

Thank you
Pranas

Re: about second pic

Posted: 12 Aug 2008 15:17
by MasterBlaster
prancius wrote:Can you give some explanation how you connected second PIC16F877A?
Hi prancius,

simply connect 8):

SDA (Master RC4) <==> SDA (RC4 Slave)
SCL (Master RC3) <==> SCL (RC3 Slave)

Don't forget GND connected to all devices as like as Master and Slave (with resistors from SDA and SCL to Vcc). :roll:

Only the "Master" is the one and only who determines who has anything to send and/or receive. :shock:

Posted: 12 Aug 2008 15:41
by Remoeggel
Hello Pranas

I use the "PC to I2C-Bus Adapter" as Master, not a PIC.

(http://www.shop.robotikhardware.de/shop ... ucts_id=68)

Best Regards

Remo

So

Posted: 12 Aug 2008 15:58
by prancius
So as i understand one pic you a placed on easypic5 second on some dev board. And you connected like this?

Are you using external pull ups or just pull up jumper on port c?

Image

Thank you
Pranas

Posted: 12 Aug 2008 17:08
by Remoeggel
No.
I the PIC on the Board (EasyPic5) is the slave.

I send data from a VB-Programm to the pic over the "PC to I2C-Bus Adapter".

Link to "PC to I2C-Bus Adapter":
http://www.shop.robotikhardware.de/shop ... ucts_id=68

Best Regards

Remo

Re: No Interrupt in I2C slave

Posted: 14 Aug 2008 01:34
by TomSSS
Remoeggel wrote:Hello Tom

I try to put your code in my program for a slave I2C pic.
But i get never a interrupt.
Do you know what could be the problem?

Code if interrupt has occured:

Code: Select all

void interrupt(){
   
    if (PIR1.SSPIF = 1){
    
 
I believe this should be changed to

Code: Select all

void interrupt(){
   
    if (PIR1.SSPIF == 1){
    
 
Give it a try and let me know

It works now!!!

Posted: 14 Aug 2008 14:09
by Remoeggel
Hello Tom

It works now.
The problem was a false value in the register SSPCON.
:oops: :x :oops:

thanks for all

Remo