|
|
View previous topic :: View next topic |
Author |
Message |
Student16
Joined: 02 Jan 2021 Posts: 5
|
I2C writing multiple variables from slave to master |
Posted: Sat Jan 02, 2021 10:32 am |
|
|
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! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jan 02, 2021 12:35 pm |
|
|
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
|
|
Posted: Sat Jan 02, 2021 1:06 pm |
|
|
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
|
|
Posted: Sun Jan 03, 2021 6:06 am |
|
|
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
|
|
Posted: Sun Jan 03, 2021 6:15 am |
|
|
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
|
|
Posted: Sun Jan 03, 2021 6:19 am |
|
|
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
|
|
Posted: Sun Jan 03, 2021 8:57 am |
|
|
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. |
|
|
|
|
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
|