CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

I2C writing multiple variables from slave to master

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Student16



Joined: 02 Jan 2021
Posts: 5

View user's profile Send private message

I2C writing multiple variables from slave to master
PostPosted: Sat Jan 02, 2021 10:32 am     Reply with quote

Hi, I am stuck with a project.

With this project I have input pins on 1 16F877A (the slave) and I want to send these inputs to another 16F877A (the master).

I want to send these inputs using an Array. I found an example and I got these working for 8 input pins (like in the example). But I can't change it to my case where I have 16 input pins.

I hope someone can help me or guide me in the right direction because I am stuck on this for days.

Master code:
Code:

#include <16F877A.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)

   
#define SLAVE1_WRT_ADDR   0x12
#define SLAVE1_READ_ADDR  0x13

#define AANTAL_SENSORPINNEN 16

int huidigeVerdieping = 0;
int nieuweVerdieping = 0;
int8 sensorArray[AANTAL_SENSORPINNEN] = {0};

//====================================
void main(){

   int8 i;

   setup_timer_2(T2_DIV_BY_16, 250, 1);   // Set PWM frequency to 500Hz
   delay_ms(100);                         // Wait 100ms
   setup_ccp1(CCP_PWM);                   // Configure CCP1 as a PWM
   set_pwm1_duty(250);

   while(1){
      i2c_start();
      i2c_write(SLAVE1_READ_ADDR);

      for(i = 0; i < 7; i++){
         sensorArray[i] = i2c_read();  // Read first 7 bytes
      }
   
      sensorArray[7] = i2c_read(0); // Do a NACK on last byte read
      i2c_stop();

      if(sensorArray[4] == 1 || sensorArray[11] == 1){
         nieuweVerdieping = 0;
         if(nieuweVerdieping > huidigeVerdieping){
            set_pwm2_duty(250);
            setup_ccp2(CCP_PWM);               // Configure CCP2 as a PWM
         }else{
            set_pwm1_duty(250);
            setup_ccp1(CCP_PWM);
         }
      }
     
      if(sensorArray[5] == 1 || sensorArray[6] == 1 || sensorArray[12] == 1){
         nieuweVerdieping = 1;
         if(nieuweVerdieping > huidigeVerdieping){
            set_pwm2_duty(250);
            setup_ccp2(CCP_PWM);               // Configure CCP2 as a PWM
         }else{
            set_pwm1_duty(250);
            setup_ccp1(CCP_PWM);
         }
      }
     
      if(sensorArray[7] == 1 || sensorArray[8] == 1 || sensorArray[13] == 1){
         nieuweVerdieping = 2;
         if(nieuweVerdieping > huidigeVerdieping){
            set_pwm2_duty(250);
            setup_ccp2(CCP_PWM);               // Configure CCP2 as a PWM
         }else{
            set_pwm1_duty(250);
            setup_ccp1(CCP_PWM);
         }
      }
     
      if(sensorArray[9] == 1 || sensorArray[14] == 1){
         nieuweVerdieping = 3;
         if(nieuweVerdieping > huidigeVerdieping){
            set_pwm2_duty(250);
            setup_ccp2(CCP_PWM);               // Configure CCP2 as a PWM
         }else{
            set_pwm1_duty(250);
            setup_ccp1(CCP_PWM);
         }
      }
     
      if(sensorArray[nieuweVerdieping] == 1){
         setup_ccp1(CCP_OFF);               // CCP1 OFF
         setup_ccp2(CCP_OFF);               // CCP2 OFF
         huidigeVerdieping = nieuweVerdieping;
      }
   }
}


Slave code:
Code:

#include <16F877A.h>
#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x12)

#define AANTAL_SENSORPINNEN 16
#define REEDCONTACT0 PIN_A1
#define REEDCONTACT1 PIN_A2
#define REEDCONTACT2 PIN_A3
#define REEDCONTACT3 PIN_A4
#define DRUKKNOP_FRONT0 PIN_C0
#define DRUKKNOP_FRONT1_OMLAAG PIN_C1
#define DRUKKNOP_FRONT1_OMHOOG PIN_C2
#define DRUKKNOP_FRONT2_OMLAAG PIN_C5
#define DRUKKNOP_FRONT2_OMHOOG PIN_C6
#define DRUKKNOP_FRONT3 PIN_C7
#define DRUKKNOP_FRONT_NOODKNOP PIN_A5
#define DRUKKNOP_LIFT0 PIN_B0
#define DRUKKNOP_LIFT1 PIN_B1
#define DRUKKNOP_LIFT2 PIN_B2
#define DRUKKNOP_LIFT3 PIN_B3
#define DRUKKNOP_LIFT_NOODKNOP PIN_B4

int8 sensorArray[AANTAL_SENSORPINNEN] = {0};
int8 index;


#INT_SSP
void ssp_interrupt(){

   int8 incoming, state;

   state = i2c_isr_state();
   
   if(state < 0x80){     // Master is sending data
      incoming = i2c_read();
  }

   if(state >= 0x80){   // Master is requesting data from slave
      index = state & 7;  // Lower 3 bits of state = the index
      i2c_write(sensorArray[index]);
  }
}

void main (){
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);

   while(1){
      sensorArray[0] = input(REEDCONTACT0);
      sensorArray[1] = input(REEDCONTACT1);
      sensorArray[2] = input(REEDCONTACT2);
      sensorArray[3] = input(REEDCONTACT3);
      sensorArray[4] = 1 - input(DRUKKNOP_FRONT0);
      sensorArray[5] = 1 - input(DRUKKNOP_FRONT1_OMLAAG);
      sensorArray[6] = 1 - input(DRUKKNOP_FRONT1_OMHOOG);
      sensorArray[7] = 1 - input(DRUKKNOP_FRONT2_OMLAAG);
      sensorArray[8] = 1 - input(DRUKKNOP_FRONT2_OMHOOG);
      sensorArray[9] = 1 - input(DRUKKNOP_FRONT3);
      sensorArray[10] = 1 - input(DRUKKNOP_FRONT_NOODKNOP);
      sensorArray[11] = 1 - input(DRUKKNOP_LIFT0);
      sensorArray[12] = 1 - input(DRUKKNOP_LIFT1);
      sensorArray[13] = 1 - input(DRUKKNOP_LIFT2);
      sensorArray[14] = 1 - input(DRUKKNOP_LIFT3);
      sensorArray[15] = 1 - input(DRUKKNOP_LIFT_NOODKNOP);
      delay_ms(5);
   }
}


Thanks in advance! Surprised
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Jan 02, 2021 12:35 pm     Reply with quote

You want to send/receive 16 elements instead of 8.
Quote:
for(i = 0; i < 7; i++){
sensorArray[i] = i2c_read(); // Read first 7 bytes
}

sensorArray[7] = i2c_read(0); // Do a NACK on last byte read
i2c_stop();

You have a loop in your Master code as shown above.
Why not just change the 7 to 15 ?


Quote:
index = state & 7; // Lower 3 bits of state = the index
i2c_write(sensorArray[index]);

Then in your slave code above, why not just use the lower 4 bits and
AND 'state' with 15 instead of 7 ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sat Jan 02, 2021 1:06 pm     Reply with quote

Two further comments.

In the I2C slave, state 0x80, should also do a read before the write.
Not doing so can give issues.
You also seem to be wasting a huge amount of actual space. Several
of your inputs are single bits. You could send 8 of these in a single byte.
Sending 8 bytes to send just 8 bits, takes a lot more time, and uses
a lot more storage than is needed.....
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Jan 03, 2021 6:06 am     Reply with quote

To add to the comments....
1) consider putting the 16 bits of sensor data into 2 bytes. That way the master only has to read 2 bytes to get all the data. As Mr. T says faster and space saving.

2) in the 'Master' create a 'Union' of sensor data. The 'word'(16bits) consists of both bytes of data. By giving each bit a name, your program can refer to the name and not the array position. This means you don't have to remember what xxx[4] is or use xxx[8] instead of xxx[3],since they look real similar after 4-5 hours oflooking at the screen. BTDT, several times.......sigh..old eyes.
By having names, it's easier for you to see WHAT sensors are controlling the PWM functions too !
Also, if you change a sensor location ( different pin ) ,it's less typing to update the code !
Student16



Joined: 02 Jan 2021
Posts: 5

View user's profile Send private message

PostPosted: Sun Jan 03, 2021 6:15 am     Reply with quote

Ttelmah wrote:
Two further comments.

In the I2C slave, state 0x80, should also do a read before the write.
Not doing so can give issues.
You also seem to be wasting a huge amount of actual space. Several
of your inputs are single bits. You could send 8 of these in a single byte.
Sending 8 bytes to send just 8 bits, takes a lot more time, and uses
a lot more storage than is needed.....


Thank you for the feedback.
So originally I wanted to send the variables 1 by 1 with I2C. I only have to send from slave to master. I expected that it would work like this:

Master code:
Code:

#include <16F877a.h>
#fuses HS, NOWDT
#use delay(clock=4000000)
#use I2C(MASTER, sda=PIN_C4, scl=PIN_C3)

#define SLAVE1_WRT_ADDR   0x12
#define SLAVE1_READ_ADDR  0x13

int1 data1, data2, data3, data4, data5, data6, data7, data8, data9,
data10, data11, data12, data13, data14, data15, data16, data17,
data18, data19, data20, data21, data22, data23, data24;

void main(){
   
   while (1){
      /* Master */
      i2c_start();      // Start condition
      i2c_write(SLAVE1_READ_ADDR);   // Device address
      data1 = i2c_read();
      data2 = i2c_read();
      data3 = i2c_read();
      data4 = i2c_read();
      data5 = i2c_read();
      data6 = i2c_read();
      data7 = i2c_read();
      data8 = i2c_read();
      data9 = i2c_read();
      data10 = i2c_read();
      data11 = i2c_read();
      data12 = i2c_read();
      data13 = i2c_read();
      data14 = i2c_read();
      data15 = i2c_read();
      data16 = i2c_read();
      data17 = i2c_read();
      data18 = i2c_read();
      data19 = i2c_read();
      data20 = i2c_read();
      data21 = i2c_read();
      data22 = i2c_read();
      data23 = i2c_read();
      data24 = i2c_read();
      i2c_stop();      // Stop condition
   } 
}


Slave code:
Code:

#include <16F877a.h>
#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x12)

#define REEDCONTACT0 PIN_A1
#define REEDCONTACT1 PIN_A2
#define REEDCONTACT2 PIN_A3
#define REEDCONTACT3 PIN_A4
#define DRUKKNOP_FRONT0 PIN_C0
#define DRUKKNOP_FRONT1_OMLAAG PIN_C1
#define DRUKKNOP_FRONT1_OMHOOG PIN_C2
#define DRUKKNOP_FRONT2_OMLAAG PIN_C5
#define DRUKKNOP_FRONT2_OMHOOG PIN_C6
#define DRUKKNOP_FRONT3 PIN_C7
#define DRUKKNOP_FRONT_NOODKNOP PIN_A5
#define DRUKKNOP_LIFT0 PIN_B0
#define DRUKKNOP_LIFT1 PIN_B1
#define DRUKKNOP_LIFT2 PIN_B2
#define DRUKKNOP_LIFT3 PIN_B3
#define DRUKKNOP_LIFT_NOODKNOP PIN_B4
#define KEYPAD1 PIN_D1
#define KEYPAD2 PIN_D2
#define KEYPAD3 PIN_D3
#define KEYPAD4 PIN_D4
#define KEYPAD5 PIN_D5
#define KEYPAD6 PIN_D6
#define KEYPAD7 PIN_D7
#define TEMP_SENSOR PIN_A0

int1 contact1, contact2, contact3, contact4, contact5, contact6, contact7, contact8,
contact9, contact10, contact11, contact12, contact13, contact14, contact15, contact16,
contact17, contact18, contact19, contact20, contact21, contact22, contact23, contact24;

#INT_SSP
void ssp_interrupt()
{
   i2c_write(contact1);
   i2c_write(contact2);
   i2c_write(contact3);
   i2c_write(contact4);
   i2c_write(contact5);
   i2c_write(contact6);
   i2c_write(contact7);
   i2c_write(contact8);
   i2c_write(contact9);
   i2c_write(contact10);
   i2c_write(contact11);
   i2c_write(contact12);
   i2c_write(contact13);
   i2c_write(contact14);
   i2c_write(contact15);
   i2c_write(contact16);
   i2c_write(contact17);
   i2c_write(contact18);
   i2c_write(contact19);
   i2c_write(contact20);
   i2c_write(contact21);
   i2c_write(contact22);
   i2c_write(contact23);
   i2c_write(contact24);
}


//======================================
void main (){

   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   
   while(1){
      contact1 = input(REEDCONTACT0);
      contact2 = input(REEDCONTACT1);
      contact3 = input(REEDCONTACT2);
      contact4 = input(REEDCONTACT3);
      contact5 = 1 - input(DRUKKNOP_FRONT0);
      contact6 = 1 - input(DRUKKNOP_FRONT1_OMLAAG);
      contact7 = 1 - input(DRUKKNOP_FRONT1_OMHOOG); //input(DRUKKNOP_FRONT2_OMLAAG);
      contact8 = 1 - input(DRUKKNOP_FRONT2_OMLAAG); //input(DRUKKNOP_FRONT3);
      contact9 = 1 - input(DRUKKNOP_FRONT2_OMHOOG);
      contact10 = 1 - input(DRUKKNOP_FRONT3);
      contact11 = 1 - input(DRUKKNOP_FRONT_NOODKNOP);
      contact12 = 1 - input(DRUKKNOP_LIFT0);
      contact13 = 1 - input(DRUKKNOP_LIFT1);
      contact14 = 1 - input(DRUKKNOP_LIFT2);
      contact15 = 1 - input(DRUKKNOP_LIFT3);
      contact16 = 1 - input(DRUKKNOP_LIFT_NOODKNOP);
      contact17 = input(KEYPAD1);
      contact18 = input(KEYPAD2);
      contact19 = input(KEYPAD3);
      contact20 = input(KEYPAD4);
      contact21 = input(KEYPAD5);
      contact22 = input(KEYPAD6);
      contact23 = input(KEYPAD7);
      contact24 = input(TEMP_SENSOR);
      delay_ms(5);
   }
}


But that didn't work, so that's how I got to the code I posted here, with the use of an Array. But if I change this array to an int1 it doesn't work anymore. What is the best way to solve this problem?

And what read statement do you need to use when in state 0x80?

Thank you in advance.
Student16



Joined: 02 Jan 2021
Posts: 5

View user's profile Send private message

PostPosted: Sun Jan 03, 2021 6:19 am     Reply with quote

PCM programmer wrote:
You want to send/receive 16 elements instead of 8.
Quote:
for(i = 0; i < 7; i++){
sensorArray[i] = i2c_read(); // Read first 7 bytes
}

sensorArray[7] = i2c_read(0); // Do a NACK on last byte read
i2c_stop();

You have a loop in your Master code as shown above.
Why not just change the 7 to 15 ?


Quote:
index = state & 7; // Lower 3 bits of state = the index
i2c_write(sensorArray[index]);

Then in your slave code above, why not just use the lower 4 bits and
AND 'state' with 15 instead of 7 ?


Thank you for your reply, I got it working now for 16 variables in the array. But I found out I need to send 24 variables to the master, you can't & the state with 23 right? How can you solve this?

New master code:
Code:

#include <16F877A.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
 
#define SLAVE1_WRT_ADDR   0x12
#define SLAVE1_READ_ADDR  0x13

#define AANTAL_SENSORPINNEN 24
int1 sensorArray[AANTAL_SENSORPINNEN] = {0};

void main(){
   int8 i;

   while(1){
      i2c_start();
      i2c_write(SLAVE1_READ_ADDR);

      for(i = 0; i < AANTAL_SENSORPINNEN-1; i++){
         sensorArray[i] = i2c_read();
      }
   
      sensorArray[AANTAL_SENSORPINNEN-1] = i2c_read(0); // Do a NACK on last byte read
      i2c_stop();
   }
}


New Slave code:
Code:

#include <16F877A.h>
#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x12)

#define AANTAL_SENSORPINNEN 24
#define REEDCONTACT0 PIN_A1
#define REEDCONTACT1 PIN_A2
#define REEDCONTACT2 PIN_A3
#define REEDCONTACT3 PIN_A4
#define DRUKKNOP_FRONT0 PIN_C0
#define DRUKKNOP_FRONT1_OMLAAG PIN_C1
#define DRUKKNOP_FRONT1_OMHOOG PIN_C2
#define DRUKKNOP_FRONT2_OMLAAG PIN_C5
#define DRUKKNOP_FRONT2_OMHOOG PIN_C6
#define DRUKKNOP_FRONT3 PIN_C7
#define DRUKKNOP_FRONT_NOODKNOP PIN_A5
#define DRUKKNOP_LIFT0 PIN_B0
#define DRUKKNOP_LIFT1 PIN_B1
#define DRUKKNOP_LIFT2 PIN_B2
#define DRUKKNOP_LIFT3 PIN_B3
#define DRUKKNOP_LIFT_NOODKNOP PIN_B4
#define KEYPAD1 PIN_D1
#define KEYPAD2 PIN_D2
#define KEYPAD3 PIN_D3
#define KEYPAD4 PIN_D4
#define KEYPAD5 PIN_D5
#define KEYPAD6 PIN_D6
#define KEYPAD7 PIN_D7
#define TEMP_SENSOR PIN_A0

int1 sensorArray[AANTAL_SENSORPINNEN] = {0};
int8 index;

#INT_SSP
void ssp_interrupt(){

   int8 incoming, state;

   state = i2c_isr_state();
   
   if(state < 0x80){     // Master is sending data
      incoming = i2c_read();
  }

   if(state >= 0x80){   // Master is requesting data from slave
      index = state & 23;
      i2c_write(sensorArray[index]);
  }
}

void main (){
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);

   while(1){
      sensorArray[0] = input(REEDCONTACT0);
      sensorArray[1] = input(REEDCONTACT1);
      sensorArray[2] = input(REEDCONTACT2);
      sensorArray[3] = input(REEDCONTACT3);
      sensorArray[4] = 1 - input(DRUKKNOP_FRONT0);
      sensorArray[5] = 1 - input(DRUKKNOP_FRONT1_OMLAAG);
      sensorArray[6] = 1 - input(DRUKKNOP_FRONT1_OMHOOG); //input(DRUKKNOP_FRONT2_OMLAAG);
      sensorArray[7] = 1 - input(DRUKKNOP_FRONT2_OMLAAG); //input(DRUKKNOP_FRONT3);
      sensorArray[8] = 1 - input(DRUKKNOP_FRONT2_OMHOOG);
      sensorArray[9] = 1 - input(DRUKKNOP_FRONT3);
      sensorArray[10] = 1 - input(DRUKKNOP_FRONT_NOODKNOP);
      sensorArray[11] = 1 - input(DRUKKNOP_LIFT0);
      sensorArray[12] = 1 - input(DRUKKNOP_LIFT1);
      sensorArray[13] = 1 - input(DRUKKNOP_LIFT2);
      sensorArray[14] = 1 - input(DRUKKNOP_LIFT3);
      sensorArray[15] = input(DRUKKNOP_LIFT_NOODKNOP);
      sensorArray[16] = input(KEYPAD1); //input(DRUKKNOP_FRONT3);
      sensorArray[17] = input(KEYPAD2);
      sensorArray[18] = input(KEYPAD3);
      sensorArray[19] = input(KEYPAD4);
      sensorArray[20] = input(KEYPAD5);
      sensorArray[21] = input(KEYPAD6);
      sensorArray[22] = input(KEYPAD7);
      sensorArray[23] = input(TEMP_SENSOR);
      delay_ms(5);
   }
}


Thanks in advance.
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sun Jan 03, 2021 8:57 am     Reply with quote

Code:

#INT_SSP
void ssp_interrupt(){

   int8 incoming, state;
   static int8 count=0;

   state = i2c_isr_state();
   
   if(state < 0x80)
   {     // Master is sending data
      incoming = i2c_read();
   }

   if(state == 0x80)
   {
       count=0;
       incoming = i2c_read(2);  //perform the read on state==0x80
       //note special read that does not release the CKP
   }

   if (state>=0x80)
   {   // Master is requesting data from slave
      i2c_write(sensorArray[count++]);
  }
}


Now note the changes. It now reads on state==0x80, before writing.
Not doing this on some of the PIC's will cause problems. The read used
is a special version that does not release the clock.
Then instead of using 'index', it now uses the static variable 'count'.
This is incremented after each write, so can support any number of
bytes (within the limitations of an int8). This is set to 0 on state==0x80,
so counts every transmitted byte after this point.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group