I2C send multiple times

I have a large piece of data.
String data = "Serialnumber,Brand,Model,RatedValue,Vvalue,Rvalue,Avalue,Cvalue,Hvalue";

This piece of data is to large to send over the I2c protocol in one go ( at least in my project)
So i try to break it up and send one piece at a time.

void SendSerial()
{
String dts = SN + ",";
Wire.beginTransmission(SLAVE_ADDR);
byte data[dts.length()];
for(byte i = 0; i < dts.length();i++)
{
data[i] = (byte)dts.charAt(i);
}
Wire.write(data, sizeof(data));
Wire.endTransmission(false);
SendBrand();
}

void SendBrand()
{
String dts = BB + "," ;
//Wire.beginTransmission(SLAVE_ADDR);
byte data[dts.length()];
for(byte i = 0; i < dts.length();i++)
{
data[i] = (byte)dts.charAt(i);
}
Wire.write(data, sizeof(data));
Wire.endTransmission();
delay(1000);
}

And so on.
But this does not work,.

On my Slave i have a string that just adds the received data to it
String all = "";

void receiveEvent()
{
while( 1 < Wire.available())
{
char c = Wire.read();
all += c;
}
Serial.println(all);
}

How can i send all my data?

Several ways, but my preference would be to NOT use Strings for this. Just use the 'native' data types and send each variable separately.

But that's the thing, calling SendSerial only sends the serial number and it does not send the rest of the data

This suggests you have a String made up of several variables. My suggestion is to do away with the String entirely (or parse it into its constituent variables) and send the numerical variables over I2C.

Especially on the slave side you have a real risk of memory management issues the way you're receiving the String. Although it depends on how it's actually implemented, which I cannot see since you only posted snippets of code instead of complete sketches.

Anyway, I don't see any advantage to using a String in this case. Quite the opposite in fact.

So sending the data to the slave only happens once, on my master i read data from a MFRC522 and store that data. The reason i send the data as a string is because most of the data recieved via the MFRC522 are just that, text. Also on the slave side, once the data is recieved, it saves it to a sd card. The entire thing is then removed from power and everything clears except for the sd data. My problem is that if i call it as shown above, i do not recieve the data after the serial number, its like once i call the Wire.endTransmission(false) then it doesnt send anymore data

here is an example where you split a cString into packets

char message[] = "Serialnumber,Brand,Model,RatedValue,Vvalue,Rvalue,Avalue,Cvalue,Hvalue";

void sendPacket(const char* buffer, size_t bufferLength) {
  for (size_t i = 0; i < bufferLength; i++) Serial.write(buffer[i]);
  Serial.println(F("⏎")); // just so we can see the breaks
}

void splitMessage(const char* buffer, size_t bufferLength, size_t splitSize) {
  if (splitSize >= bufferLength) sendPacket(buffer, bufferLength);
  else
    for (size_t i = 0; i < bufferLength; i += splitSize)
      sendPacket(buffer + i, min(splitSize, bufferLength - i));
}

void setup() {
  Serial.begin(115200); Serial.println();
  splitMessage(message, strlen(message), 6);
}

void loop() {}

Serial Monitor (@ 115200 bauds) will show

Serial⏎
number⏎
,Brand⏎
,Model⏎
,Rated⏎
Value,⏎
Vvalue⏎
,Rvalu⏎
e,Aval⏎
ue,Cva⏎
lue,Hv⏎
alue⏎

The I2C bus is used with packages of binary data of a fixed size.

Can you tell more about your project ?
Where does that text come from ?
Which Arduino boards do you use ?
What is the distance for the I2C bus ? Do you want to use a cable ?

The best way is to use a single Arduino board and write your sketch in such a way that multiple things can done at the same time.

If you really want I2C communication then you could make two small sketches for the Master and the Slave and try to make it work. Please show them between code-tags.

If you have that information as binary data, then you can send a struct of a fixed size. That is possible, but a Arduino as a I2C Slave is not easy. You have to do everything right.

If it is absolutely necessary to send readable ASCII data with a variable length over I2C, then it suddenly becomes complicated:

  • The Slave has to know which parts below together when when everything is received.
  • Every part has to be smaller than the maximum allowed number of bytes.
  • You have to define very clearly what is send. Is there something at the end (a LineFeed for example). Is the zero-terminator of the string transmitted or not, and so on.

The text is read from a RFID card using the MFRC522.
That text is a 'char' but i need to convert that into a String for my internal code ie : to display it on my LCD.
I use 2 Arduino nano's.
The arduino's are soldered to a pcb board with a distance of around 50mm between them.

I need to use 2 arduino nano's because i use the LCD crystal Library, MFRC522 library, SD library and a bunch of calculations, this is to much for one nano.

The data will always change as every rfid has different data stored on it with different lengths.
Also the data is saved to a SD card with ',' to later import that to a excel file CSV.

I can break up my data into smaller chunks with no problem ie: i can send my serial number as i know it the length will never be more that 15 characters. the same with a bunch more data.

MY PROBLEM IS:
when i send my first bit of data and then end the transmission, i cannot send the other data. It seems to no want to recieve any more data once i call the Wire.endTransmission

beginTransmission() tells the library to write whatever you provide into a buffer.
endTransmission() is when the buffer content is actually sent over.
so if you want to send something else again, you need to rinse and repeat: call beginTransmission(), write the bytes, call endTransmission()

On the receiving end you'll need to know what's coming so that you can build the original content back. That means some sort of protocol needs to be implemented (number of packets you'll send, start frame, end frame, ....)

The Arduino Nano has buffers for I2C of 32 bytes. The maximum length for the I2C data is therefor 32 bytes.
I prefer to split the data into chunks of a fixed length, such as the example by J-M-L. However, a lot more code is needed to be sure that all the chunks of data are received and below to each other.

@mr_tropica can you tell which library is used for the RFID ? I think that most information is available as binary data.

Can i give you an example of my problem?

On my SLAVE my code looks like this:

void setup()
{
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
if (!SD.begin(2)) {
Serial.println("initialization failed!");
while (1);
}
Wire.begin(SLAVE_ADDR);
Wire.onReceive(receiveEvent);

}

void receiveEvent(int howMany)
{
while( 1 < Wire.available())
{
char c = Wire.read();
//all += c;
Serial.print(c);
}
}

Now on my MASTER :

void SendData()
{
String g = "DATA CHUNK 1";
Wire.beginTransmission(SLAVE_ADDR);
byte data[g.length()];
for(byte i = 0; i < g.length(); i++)
{
data[i] = (byte)g.charAt(i);
}
Wire.write(data, sizeof(data));
Wire.endTransmission();
delay(500);
SendNextData();
}

void SendNextData()
{
String g = "DATA CHUNK 2"
Wire.beginTransmission(SLAVE_ADDR);
byte data[g.length()];
for(byte i = 0; i < g.length(); i++)
{
data[i] = (byte)g.charAt(i);
}
Wire.write(data, sizeof(data));
Wire.endTransmission();
delay(500);
}

This doesn't work, I ONLY receieve DATA CHUNK 1 on my slave.
Even if i call Wire.onReceive(receiveEvent); in the loop function of my slave i ONLY receiev DATA CHUNK 1

I have found the solution, apparently in the SLAVE you need this piece of code

void receiveEvent(int howMany) {
  while( 1 < Wire.available())  {
    char c = Wire.read();
    all += c;
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(all); 
}

I don't think this is the solution to the problem you exposed but if you are happy with it...

what this does is to get all the data but the last byte in the (I suppose) String instance all and then skip the last byte (why would you do that depends on what's sent)

So data will accumulate into the all String but the question is when do you reset it? (when do you know that the full original data set is complete)?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.