I2C, Wire.h Communication between 2 arduinos problem

Hello all,
I have a problem with communication between 2 arduino nano v3.
Communication is done by 1st arduino is a Slave Sender and 2nd arduino is a Master Reader.
On the 1st arduino i have connected weight sensor which measure weight from load cell.
On the next step data are sending by i2c to master reader arduino.
Everything is allright when i put known weight on the load cell up to 255 kg.
If I put 100kg 1st arduino shows (in serial monitor )100kg and 2nd arduino shows 100kg too.
If I put 255 kg 1st arduino shows 255kg and 2nd arduino shows 255kg too.
Problems are when I put more than 255kg, for example when I put knows weight ex. 300kg 1st arduino shows 300kg and 2nd arduino after i2c communication get only 45 kg - now i know it is 300-255=45 kg its just a rest difference.
I searched everywere and as i know everything that is the reason write topic here.

Look in my code.
Slave sender :

#include "HX711.h"
#include "Wire.h"
// HX711.DOUT - pin #A1
// HX711.PD_SCK - pin #A0
HX711 scale(A1,A0);	// parameter "gain" is ommited; the default value 128 is used by the library
long A;

void setup() 
  {
    Serial.begin(9600);
      scale.set_scale(3350.f); // this value is obtained by calibrating the scale with known weights; see the README for details
      scale.tare();	// reset the scale to 0
      Wire.begin(2);                // join i2c bus with address #2
      Wire.onRequest(requestEvent); // register event     
  }
  
void loop() 
  {
    A = scale.get_units(),0;
    Serial.print("\t| average:\t");
    Serial.println(A);  
    scale.power_down();	// put the ADC in sleep mode
    delay(500);
    scale.power_up();
    }
    
void requestEvent()
{
Wire.write(A);
}

Master Reader :

#include "LiquidCrystal.h"
#include "Wire.h"
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

void setup()
    {
      Wire.begin();        // join i2c bus (address optional for master)
      lcd.begin(20, 4); // ustawienie wielkosci wyswietlacza
      Serial.begin(9600); 


    }

void waga1()
    {
 
      Wire.requestFrom(2,2);    // request 2 bytes from slave device #2
      while(Wire.available())    // slave may send less than requested
          {
            long c = Wire.read(); // receive a byte as character
            Serial.print(c);         // print the weight

          }

     delay(500);
    }
   

void loop()
  {

     waga1();
     delay(1000); 
  }

I don't have any more patience for that and any more ideas how to fix that.
Maybe from You Guys somebady will know how to help me.

p.s Sorry for my English but i think all is understand.

Best Regards Mariusz.

hawryszka:
Hello all,
I have a problem with communication between 2 arduino nano v3.

void requestEvent()

{
Wire.write(A);
}





Best Regards Mariusz.

Mariusz,
you have ran into a problem with the Wire library.

In your requestEvent() function, the Wire.write(A) will only send one byte, change it to:

void requestEvent(){
uint8_t * bp =(uint8_t*)&A;  // setup pointer to address of A

 Wire.write(bp,2);
// or you could incorporate the type casting in the write.
  Wire.write((uint8_t*)&A,2);
// either of these is acceptable 
}

Also be advised in the requestEvent() only the LAST Wire.write() operation is actually sent.
If you changed your requestEvent() to

void requestEvent(){
Wire.write(lowByte(A));
Wire.write(highByte(A));
}

only the highbyte(A) would be sent. you would only receive the value 1. when A= 300; lowByte(A) = 44, highByte(A) = 1.

Chuck.


Check out my Kickstarter Project Memory Panes an expansion RAM Shield for Mega2560's. It adds 1MB of RAM for those projects where 8KB is not enough.
[/code]

Good Bless You Chuck ! :slight_smile: Big Thx for answer to me ! :slight_smile:
On the Slave sender - 1st arduino i have void requestEvent() and i use Wire.write(A); and,
on the Master Reciver - 2nd arduino i have Wire.requestFrom(2,2) and i neet to use Wire.read, You suggest me to use on the Slave sender :

void requestEvent()
{
uint8_t * bp =(uint8_t*)&A;  // setup pointer to address of A
Wire.write(bp,2);                // or you could incorporate the type casting in the write.
Wire.write((uint8_t*)&A,2);   // either of these is acceptable
}

both, means : Wire.write(bp,2); AND Wire.write((uint8_t*)&A,2); function
or Wire.write(bp,2); OR Wire.write((uint8_t*)&A,2);
to send data on the 2 bytes and on the Master reader side

void requestEvent()
{
Wire.write(lowByte(A));
Wire.write(highByte(A));
}

same request...function ?and then write it to "A" ?
Iam right ?

hawryszka:
Good Bless You Chuck ! :slight_smile: Big Thx for answer to me ! :slight_smile:
On the Slave sender - 1st arduino i have void requestEvent() and i use Wire.write(A); and,
on the Master Reciver - 2nd arduino i have Wire.requestFrom(2,2) and i neet to use Wire.read, You suggest me to use on the Slave sender :

Sorry to confuse you. Use Either of these code snippets. I gave you multiple example because I did not know which you would understand. Type casting with pointers confuses me sometimes.

This one:

void requestEvent()
{
uint8_t * bp =(uint8_t*)&A;  // setup pointer to address of A
// the 2 is sizeof(int) Wire.write(bp,2); 
Wire.write(bp,sizeof A); // much better
}

or this one:

void requestEvent()
{
//  Wire.write((uint8_t*)&A,2);   // type cast the Long to a byte Array pointer
Wire.write((uint8_t*)&A,sizeof A); // much Better!!!
}

The Wire Library has inline functions for all int type that to ME are FAILURES.
Code from Wire.h

inline size_t write(unsigned long n) { return write((uint8_t)n); }
inline size_t write(long n) { return write((uint8_t)n); }
inline size_t write(unsigned int n) { return write((uint8_t)n); }
inline size_t write(int n) { return write((uint8_t)n); }

Each one of the functions only use the FIRST byte (LSB) of the data type, they should be for example:

/* snide comment on
inline size_t write(unsigned long n) {return write((uint8_t*)&n,sizeof n);} // this would actually send ALL
// of the bytes not just the LSB!

*/ snide comment off

Inside the Wire Library all write() calls during the SLAVE_Request ISR overwrite the TX_BUFFER.
tx_buffpos=0;
tx_buflen=length of write() data.
tx_buff[0]=write_data[];

during the normal MASTER Write operation each Wire.write() call APPENDS its data to the tx_buff[],;
tx_buff[tx_bufflen]=write_data[];
tx_bufflen += length of write() data.

This tx_buffer is then transmitted by endTransmission(). During a ISR the tx_buff is transmitted when requestEvent() exits.

hawryszka:

void requestEvent()

{
Wire.write(lowByte(A));
Wire.write(highByte(A));
}

This code snippet SHOULD work, BUT IT WILL NOT!

Logically these two write() function calls will transfer the all of A to Wire, but WHILE in the ISR Wire.write() initializes the tx_buffer[] every time it is called, this results in the tx_buffer[] containing only the LAST Wire.write() data.

It is a BAD, STUPID, ERROR inducing 'feature' of the Wire Library!

Attached is my 'fixed' Wire Library.

hawryszka:
same request...function ?and then write it to "A" ?
Iam right ?

The requestFrom() needs to assemble the int from individual bytes. With my modified Wire,
there is a couple of template that make this really easy.

I2C_readAnything(A); will call Wire.read() as many times a necessary to 'fill' 'A'.
'A' can be any type, including struc's. As long as the type will fit in 32 bytes it will work(the size of internal Wire buffers).

look in Wire.h, at the end. {but alas, no error tests }

Chuck.


Check out my Kickstarter Project Memory Panes an expansion RAM Shield for Mega2560's. It adds 1MB of RAM for those projects where 8KB is not enough.

Wire.zip (19.7 KB)