Interface two (2) PIC micro controller by using I2c Protocol

Status
Not open for further replies.
Can anybody help me with code of Master and Slave i2c programming ?

See this is the part that actually confuses me the most. I2C code is a fairly straight forward protocol and the hardware interface is fairly minimal and well documented. I am pretty sure that you could google it. Also microchip implements hardware routines for things like the I2C bus on most all of the processors supported by the C compilers. So you could just use those or dissect them for implementation or clues.

Now if you have never used I2C, my guess is there is some confusion over things like start vs restart, addressing, etc. A good detail of this is documented in detail online.
 
Reactions: desgin

    desgin

    Points: 2
    Helpful Answer Positive Rating
Can anybody help me with code of Master and Slave i2c programming ?

Many valuable tips have been given, but no evidence of even attempting to start anything has been presented so far. By the repetitive pattern of your questions, I would not be surprised to see the same question above rephrased in a different fashion. Review this thread and start coding and debuging something.
 


thanks for the reply.
ya i am following this link
**broken link removed**
but some problem with code.

Thanks in advance!!
Desgin
 
Last edited by a moderator:

but some problem with code.

Still no evidence of anything, except for the growing impression that you are still trying to get something out of the least effort, actually no-effort.


**broken link removed**

Broken URL, but you are obviously aware of that.
 
Last edited by a moderator:

Here is my Master i2c Code:

Code:
#include "xc.h"
#include "lcd.h"
#include "i2c.h"

#pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)

// CONFIG1H
#pragma config FOSC = INTOSC_HS//XT_XT//XT_XT     // Oscillator Selection bits (XT oscillator (XT))
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = ON         // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting)
#pragma config VREGEN = OFF     // USB Voltage Regulator Enable bit (USB voltage regulator disabled)

// CONFIG2H
#pragma config WDT = OFF//ON         // Watchdog Timer Enable bit (WDT enabled)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF//ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks)


#define _XTAL_FREQ 8e6

void main()
{
  nRBPU = 0;                    //Enable PORTB internal pull up resistor
  TRISB = 0xFF;                 //PORTB as input
  TRISD = 0x00;                 //PORTD as output
  PORTD = 0x00;                 //All LEDs OFF
  I2C_Master_Init(100000);      //Initialize I2C Master with 100KHz clock
  while(1)
  {
    I2C_Master_Start();         //Start condition
    I2C_Master_Write(0x30);     //7 bit address + Write
    I2C_Master_Write(PORTB);    //Write data
    I2C_Master_Stop();          //Stop condition
    __delay_ms(200);
    I2C_Master_Start();         //Start condition
    I2C_Master_Write(0x31);     //7 bit address + Read
    PORTD = I2C_Master_Read(0); //Read + Acknowledge
    I2C_Master_Stop();          //Stop condition
    __delay_ms(200);
  }
}

This is my slave i2c code
Code:
#include "xc.h"
#include "lcd.h"
#include "i2c.h"


#pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)

// CONFIG1H
#pragma config FOSC = INTOSC_HS//XT_XT//XT_XT     // Oscillator Selection bits (XT oscillator (XT))
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = ON         // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting)
#pragma config VREGEN = OFF     // USB Voltage Regulator Enable bit (USB voltage regulator disabled)

// CONFIG2H
#pragma config WDT = OFF//ON         // Watchdog Timer Enable bit (WDT enabled)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF//ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks)


#define _XTAL_FREQ 8e6


void main()
{
  nRBPU = 0;            //Enables PORTB internal pull up resistors
  TRISB = 0xFF;         //PORTB as input
  TRISD = 0x00;         //PORTD as output
  PORTD = 0x00;         //All LEDs OFF
  I2C_Slave_Init(0x30); //Initialize as a I2C Slave with address 0x30
  while(1);
}

i2c Master source file:

Code:
#include "xc.h"
#include "lcd.h"
#include "i2c.h"


void I2C_Master_Init(const unsigned long c)
{
  SSPCON = 0b00101000;            //SSP Module as Master
  SSPCON2 = 0;
  SSPADD = (_XTAL_FREQ/(4*c))-1; //Setting Clock Speed
  SSPSTAT = 0;
//  TRISCbits.TRISC0 = 1;                   //Setting as input as given in datasheet
//  TRISCbits.TRISC1 = 1;                   //Setting as input as given in datasheet
}

void I2C_Master_Wait()
{
  while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); //Transmit is in progress
}
 
void I2C_Master_Start()
{
  I2C_Master_Wait();    
  SEN = 1;             //Initiate start condition
}

void I2C_Master_RepeatedStart()
{
  I2C_Master_Wait();
  RSEN = 1;           //Initiate repeated start condition
}

void I2C_Master_Stop()
{
  I2C_Master_Wait();
  PEN = 1;           //Initiate stop condition
}

void I2C_Master_Write(unsigned d)
{
  I2C_Master_Wait();
  SSPBUF = d;         //Write data to SSPBUF
}

unsigned short I2C_Master_Read(unsigned short a)
{
  unsigned short temp;
  I2C_Master_Wait();
  RCEN = 1;
  I2C_Master_Wait();
  temp = SSPBUF;      //Read data from SSPBUF
  I2C_Master_Wait();
  ACKDT = (a)?0:1;    //Acknowledge bit
  ACKEN = 1;          //Acknowledge sequence
  return temp;
}

i2c Slave source file:

Code:
#include "common.h"
#include "lcd.h"
#include "i2c.h""common.h"

short z;
void I2C_Slave_Init(short address) 
{
  SSPSTAT = 0x80;    
  SSPADD = address; //Setting address
  SSPCON = 0x36;    //As a slave device
  SSPCON2 = 0x01;
  TRISC3 = 1;       //Setting as input as given in datasheet
  TRISC4 = 1;       //Setting as input as given in datasheet
  GIE = 1;          //Global interrupt enable
  PEIE = 1;         //Peripheral interrupt enable
  SSPIF = 0;        //Clear interrupt flag
  SSPIE = 1;        //Synchronous serial port interrupt enable
}

void interrupt I2C_Slave_Read()
{
  if(SSPIF == 1)
  {
    SSPCONbits.CKP = 0;

    if ((SSPCONbits.SSPOV) || (SSPCONbits.WCOL)) //If overflow or collision
    {
      z = SSPBUF; // Read the previous value to clear the buffer
      SSPCONbits.SSPOV = 0; // Clear the overflow flag
      SSPCONbits.WCOL = 0; // Clear the collision bit
      SSPCONbits.CKP = 1;
    }
  }

  if(!SSPSTATbits.D_nA && !SSPSTATbits.R_nW) //If last byte was Address + Write
  {
    z = SSPBUF;
    while(!BF);
    PORTD = SSPBUF;
    SSPCONbits.CKP = 1;
  }
  else if(!SSPSTATbits.D_nA && SSPSTATbits.R_nW) //If last byte was Address + Read
  {
    z = SSPBUF;
    BF = 0;
    SSPBUF = PORTB ;
    SSPCONbits.CKP = 1;
    while(SSPSTATbits.BF);
  }

  SSPIF = 0;
  }
 

Hi,

Code...and no additional information.
Does it work, or not?
What do you expect, what works like expected, what does not work like expected, what did you do to debug, what are the debugging results?

Klaus
 

Hi,

Code...and no additional information.
Does it work, or not?
What do you expect, what works like expected, what does not work like expected, what did you do to debug, what are the debugging results?

Klaus

Thanks for reply!!
First of all let me tell about the hardware:
I have two PIC18F4550 Controller
I am just connecting RC3 of master controller to RC3 of Slave controller.
and, RC4 of master controller to RC4 of Slave controller.
and, GND of master controller to GND of Slave controller.
IS these connections are enough ??
Then i can proceed for my programming questions.

Thanks in advance!!
Desgin
 

A couple of things:

1) You need pull-up resistors on the SCL and SDA lines. You didn't mention that.

2) Your code is using the I2C hardware on the PIC (not bit-banging). You should be using RB0 (SDA) and RB1 (SCL). This information is in the very first paragraph of the I2C section (19.4) of the data sheet.
 
Reactions: desgin

    desgin

    Points: 2
    Helpful Answer Positive Rating

Yes i did the same connection as you said.
But still no output at slave.
i connected 10kohms register ar scl and sda lines.

Thanks in advance!!
Desgin
 

i connected 10kohms register ar scl and sda lines.

you can decrease Pull up resitors on SDA and SCL lines , down to 2,7K without problems.

explain what do you want exchange between Master & Slave ..
What request the main ?
What does your slave ...
No action, no answer in the main (slave) ?
 
Last edited:

you can decrease Pull up resitors on SDA and SCL lines , down to 2,7K without problems.

explain what do you want exchange between Master & Slave ..
What request the main ?
What does your slave ...
No action, no answer in the main (slave) ?

Ok, Fine I will use 2.7K ohm register.
My intention is to send characters from Master to Slave by I2C.
Requirement: i am connecting Temperature sensor with one controller (Master) and want to receive the temperature on other controller (Slave) by i2c.
I did it successfully by UART but i2c i am not getting anything.
I posted my code also.

Thanks in advance.
Desgin
 

Hi,

Requirement: i am connecting Temperature sensor with one controller (Master) and want to receive the temperature on other controller (Slave) by i2c.
Do you mean:
* the temperature sensor is connected to I2C, too?
* and you want to do all the communication at once (three devices are involved in one I2C access)?
--> this is not how I2C is meant to work.

Do it this way:
* I2C master (PIC1) communicates with slave1 (Temperature sensor) to read temperature data
* I2C master (PIC1) communicates with slave2 (PIC2) to write temperature data

Klaus
 


Thanks for reply.
Ya, i am almost doing like 2nd way.
* UART Tx (PIC1) communicates with RX (Temperature sensor) to read temperature data by using UART communication.
* I2C master (PIC1) communicates with slave1 (PIC2) to send temperature data from PIC1 to PIC2.
This is my requirement and i am doing also.

Thanks in advance!!
Desgin
 

I did it successfully by UART but i2c i am not getting anything.
I posted my code also.

So far, I have not seen any evidence of any test procedure, debug, or any other activity toward identifying the cause of the problem in an eliminatory manner. The only thing I'm seeing is you randomly making ( blind ) tests without following a more consistent logic even after each attempt do not work. Given your apparent lack of domain of the subject, I strongly suggest that you consider moving your tests to an environment that is easier to monitor, such as in a software simulation (Proteus, for example) in order to see the contents of the variables within each routine in order to be able to check step-by-step the progress of your program.
 

* I2C master (PIC1) communicates with slave1 (PIC2) to send temperature data from PIC1 to PIC2.


look at this **broken link removed** ..
Master send a ADC value to the Slave
Slave convert it in floating point (Volts) and send back to the Master
Slave also, do an ADC measure , convert it in degres °C and send to the master
Master send 2 values (bytes) , slave do the addition, and send back the result as an integer
Slave send also a string 16 cars message to the master
.. an exchange table of 32 bytes is used for that.


i am using a mikroC package based on Application Note AN734 ,
you can find it on libstock Mikroe :1470586910_i2c_master_slave_mikroc_pic.zip
it Works very well.

i think you can use this basic program to adapt to your situation, even with different PIC.
 

This is my Master code, where i need to send character from master to slave
But how to check whether my character is send from master or not ?
This is my master main code

Code:
void main()
{
    unsigned char data;
    ADCON1 = 0x0F;     
    INTCON2bits.RBPU = 0; 
    lcd_initialize();
    lcd_command(CLRSCR);
    I2C_Master_Init(100000);     
    
    while(1)
    {
        I2C_Master_Start();         
        I2C_Master_Write(0x30);     
        I2C_Master_Write(data);    // I WANT TO SEND SOME CHARACTER FROM MASTER TO SLAVE
        data = 'd';
        I2C_Master_Stop();               
        __delay_ms(200);
        
        
        I2C_Master_Start();        
        I2C_Master_Write(0x31);    
        data = I2C_Master_Read(0);  // Why here, MASTER READCame In  picture ? please anybody explain this :-(
        I2C_Master_Stop();         
        __delay_ms(200);
    }
}

And this is my source file of Master main


Code:
void I2C_Master_Init(const unsigned long c)
{
    TRISBbits.RB0 = 1;        
    TRISBbits.RB1 = 1;
    SSPSTAT = 0; 
    SSPCON1 = 0b00101000; 
    SSPADD = (_XTAL_FREQ/(4*c))-1;
}
    
void I2C_Master_Start()
{    
    I2C_Master_Wait();
    SEN = 1;            
}

void I2C_Master_Write(unsigned d)
{    
    I2C_Master_Wait();  
    SSPBUF = d;      
}

void I2C_Master_Stop()
{
    I2C_Master_Wait();
    PEN = 1;            
}

void I2C_Master_RepeatedStart()
{
    I2C_Master_Wait();
    RSEN = 1;         
}

void I2C_Master_Wait()
{
  while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));  [B] // What is meaning of this statement, I DONT UNDERSTAND THIS :-([/B]
}

unsigned short I2C_Master_Read(unsigned short a)
{
  unsigned short temp;
  I2C_Master_Wait();
  RCEN = 1; 
  I2C_Master_Wait();
  temp = SSPBUF;     
  I2C_Master_Wait();
  ACKDT = (a)?0:1;   
  ACKEN = 1;          
  return temp;
}

So now please anybody can help me for this Master code first ?
Because once master code will be OK, i will ask doubts for SLAVE file.
Please help me out.
Its very urgent.

Thanks in advance
Desgin
 

You said that UART is already working for you, and if you are not sure whether the above code work or not, just run Master and Slave routines within the same uC, and send debug reports from serial port to your desktop, as for example defining ASCII charaters to flag the current status ( e.g : "S"=>Starting to send / "R"=>Received from Slave / etc...)
 


Thanks for the reply.
For UART only 2 pins, Rx and Tx .
and i was able to check by hyper terminal window also that whether Transmission happened or not ? Receiver received data or not ?
But how to check in i2C ??
So much confusion in this i2C. :-(
Have you checked my Master code, is it correct ???

Thanks in advance
Desgin
 

Hi,

* first tell your communication sequence
* then tell the slave ACK states
* show scope picture

Then you might find more users to reply your questions (hardware and software guys).

Klaus
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…