I2C Datenübertragung

Moin, ich habe ein kleines Problem mit der I2C Datenübertragung von zwischen 2 Ardunio.

Ich möchte mehrer float Werte vom einen zum anderen übertragen (der eine soll später die Daten erfassen und der andere diese auf ein TFT Display ausgeben)

Das klappt im Prinzip auch allerdings nur bis zum 4. Wert danach kommt am anderen Arduino nichts mehr an. Ich habe schon verschiedene Pull-Up Widerstände ausprobiert aber das hat nichts gebracht und für den test habe ich auch nur 2 Jumper-Kabel verwendet.

Vielleicht hat ja jemand eine Idee wie man das besser lösen könnte.

Master

#include <Wire.h>

void setup() {

  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {
  Wire.requestFrom(4, 60);    // request 20 bytes from slave device #2
  String string, Temp1, Temp2, Temp3, Temp4, Temp5, Temp6,Temp7, Temp8,Temp9, Temp10;
  do   // slave may send less than requested
  {
    char c = Wire.read(); // receive a byte as character

    string = string + c; //Keep saving whatever is comming

    Temp1 = string.substring(0,6); //slpit String from 0 to 8
    Temp2 = string.substring(6,12);
     Temp3 = string.substring(12,18); //slpit String from 0 to 8
    Temp4 = string.substring(18,24);
     Temp5 = string.substring(24,30); //slpit String from 0 to 8
    Temp6 = string.substring(30,36);
     Temp7 = string.substring(36,42); //slpit String from 0 to 8
    Temp8 = string.substring(42,48);
     Temp9 = string.substring(48,54); //slpit String from 0 to 8
    Temp10 = string.substring(54,60);// Split from 9 to the End of String


  } while (Wire.available());

    Serial.println();
  Serial.print("Temperatur 1: " );
  Serial.print(Temp1);
  Serial.println();
    Serial.print("Temperatur 2: " );
  Serial.print(Temp2);
  Serial.println();
    Serial.print("Temperatur 3: " );
  Serial.print(Temp3);
  Serial.println();
    Serial.print("Temperatur 4: " );
  Serial.print(Temp4);
  Serial.println();
    Serial.print("Temperatur 5: " );
  Serial.print(Temp6);
  Serial.println();
    Serial.print("Temperatur 7: " );
  Serial.print(Temp7);
  Serial.println();
    Serial.print("Temperatur 8: " );
  Serial.print(Temp8);
  Serial.println();
    Serial.print("Temperatur 9: " );
  Serial.print(Temp9);
  Serial.println();
    Serial.print("Temperatur 10: " );
  Serial.print(Temp10);
  Serial.println();

 delay(1000);

}

Slave

#include<Wire.h>



float Temp1 = 902.5 ;
float Temp2 = 1852.6 ;
float Temp3 = 1024.6;
float Temp4 = 304.5;
float Temp5 = 587.5;
float Temp6 = 1026.6;
float Temp7 = 1054.6;
float Temp8 = 1046.3;
float Temp9 = 220.4 ;
float Temp10 = 30.5;



char t1[6];
char t2[6];
char t3[6];
char t4[6];
char t5[6];
char t6[6];
char t7[6];
char t8[6];
char t9[6];
char t10[6];


void setup() {
  Wire.begin(4);
  Wire.onRequest(Request);
 Serial.begin(500);
}

void loop() {
}


void Request()
{
//Converting float value to char
//The format (float, bytes, numbers of numbers after the decimal, char variable)
    dtostrf(Temp1, 6, 1, t1); 
    Wire.write(t1);
    dtostrf(Temp2, 6, 1, t2); 
    Wire.write(t2);
      dtostrf(Temp3, 6, 1, t3); 
    Wire.write(t3);
     dtostrf(Temp4, 6, 1, t4); 
    Wire.write(t4);
    delay(500);
     dtostrf(Temp5, 6, 1, t5); 
    Wire.write(t5);
     dtostrf(Temp6, 6, 1, t6); 
    Wire.write(t6);
     dtostrf(Temp7, 6, 1, t7); 
    Wire.write(t7);
     dtostrf(Temp8, 6, 1, t8); 
    Wire.write(t8);
     dtostrf(Temp9, 6, 1, t9); 
    Wire.write(t9);
     dtostrf(Temp10, 6, 1, t10); 
    Wire.write(t10);   
 delay(1000);

}

Eigentlich dürfte es dann garnicht funktionieren.
2 Kabel sind zu wenig.
Du brauchst 3 Kabel, das dritte für GND.

GND ist/war natürlich auch verbunden.

Hi

Da Du großzügig mit Strings um Dich wirfst - zeigt der Kompiler ggf. eine Warnung, daß Das die Lauffähigkeit beeinträchtigen kann?

Davon ab - was macht Dein Sketch Da überhaupt?
Die '6' könnten die Anzahl der Zeichen incl. Punkt der Float-Werte sein.
Dann würdest Du aber nur einen Zeichen-Haufen übertragen.
Würde aber zum Master passen, Der diese Zeichen wohl in einen String bapp't um daraus wieder einen float-Wert zu machen.

Was soll's unterm Strich werden?
Die Strings werden zur Laufzeit erst 'erstellt', wenn Du Diese dann 'zusammen klebst', wird ein neuer String mit größerer Länge erstellt - dabei kann Dir schnell der Speicher ausgehen (nicht, daß Du Nichts mehr frei hättest, Du hast aber kein Platz für die Boing, nur für Smarts - davon aber Mehrfach).

MfG

Das ist nicht wirklich durchdacht. Sieht nach wild drauflosprogrammieren aus

Auf dem Slave hast du ewige Delays drin. Aber auf dem Master soll alles auf einmal in einer einzigen Schleife gelesen werden. Das kann nicht gehen. Die Übertragungspuffer haben außerdem nur ca. 30 Bytes.
Und wo fangen die Delays an? Nach dem 4. Wert! Deine while-Schleife bricht einfach ab weil nichts mehr kommt.

Vernünftiger macht man das wenn du erst mal den gewünschten Index des Werts an den Slave sendest und danach nur einen Wert anforderst und überträgst (statt alles auf einmal). Dazu am besten die Werte auf dem Slave in einem Array halten und nicht in zig Variablen. Das ist vielleicht nicht unbedingt nötig, aber es zerlegt die Daten in kleinere Häppchen.

Die String Klasse sollte so oder so rausfliegen. Einfach weil sie unnötig sind. Ein Float hat nur 4 Bytes. Die kann man ganz einfach direkt übertragen.
Nehme auf beiden Seiten eine Union aus einem float und einem Byte Array:

union FloatData
{
   float f;
   byte b[sizeof(float)];
};

FloatData temp[10];

Wenn du dann einen Wert in temp[index].f schreibst kannst du direkt das Array aus Bytes mit Wire.write() übertragen:

Wire.write(temp[index].b, sizeof(FloatData));

Und umgekehrt. Mit Wire.read() 4 Bytes in das Array einlesen. Und du hast den Wert auch als Float.

Was hast du mit den String Objekten im Master vor?
Im welchen Zusammenhang steht das Kommentar in dieser Zeile?

Wire.requestFrom(4, 60);    // request 20 bytes from slave device #2

ich habe diese Tage ein I2C Master / Slave gebastelt, zwar momentan nur mit 16bit Integers die dann vice versa auf zwei byte geschiftet werden, aber so in der Art sollte eigentlich auch ein float übertragen werden können.
[* wobei natürlich die Variante von Serenifly viel besser aussieht - aber das muss ich selber erst mal verdauen]

Wenn du daran weiterarbeiten möchtest, kann ich es gern reinstellen. Wenn es zu sehr verwirrt - lass ich es lieber.

Danke schonmal für die extrem schnellen und ausführlichen Antworten, ich setzte mich morgen nochmal hin, die Vorlage kommt von einem Engländer der das genau so gemacht hat aber wenn man mal genauer drüber nachdenkt ist das schon sehr umständlich.

Nicht alles, was man im Netz findet, ist sinnvoll. Oft ist noch selbst nachdenken gefragt.

Gruß Tommy

Serenifly:

Wire.write(temp[index], sizeof(FloatData));

Müßte es nicht temp[index].b heißen?

Vielleicht :stuck_out_tongue:

Ich muss ehrlich zugeben das ich die union Funktion nicht wirklich verstanden habe und auch im Internet nicht wirklich was dazu gefunden habe.

Ich habe das jetzt erstmal in sämtlichen Variationen versucht und erstmal auch nur mit einem Wert aber komme nicht wirklich zu einem Ergebnis

#include <Wire.h>


union FloatData
{
   float f = 123.45;
   byte b[sizeof(float)];
};

FloatData temp[10];


void setup() {
  Wire.begin(); // join i2c bus (address optional for master)
}

void loop() {

  Wire.beginTransmission(8); // transmit to device #8
Wire.write(temp[10].b, sizeof(FloatData));
  Wire.endTransmission();    // stop transmitting
}

kann mir da vielleicht nochmal einer einen Gedankenanstoß geben ?

union heißt nur, dass man auf den gleichen Speicher mit verschiedenen “Variablentypen” zugreifen kann.

In Deinem Beispiel ist ein float 4 Byte groß.

Durch die 2. Möglichkeit kann man auf die 4 einzelnen Bytes zugreifen oder auf alle zusammen als als Array von Bytes.
Es wird aber nur 1 Mal der Platz für einen float-Wert belegt.

Gruß Tommy

und auch im Internet nicht wirklich was dazu gefunden habe.

Dann hast du nicht richtig gesucht. Im low level C Bereicht ist das nicht ungewöhnlich. Schon Wikipedia liefert da ein paar Infos:

Das wichtigste ist schon der erste Satz:

Bei sog. Unions beginnen alle Komponenten an der gleichen Speicheradresse

Master:

#include <Wire.h>

const byte SLAVE_ADR = 1;

union FloatData
{
  float f;
  byte b[sizeof(float)];
};

FloatData temp[4];


void setup()
{
  Serial.begin(9600);
  Wire.begin();
}

void loop()
{
  for (byte i = 0; i < sizeof(temp) / sizeof(temp[0]); i++)
  {
    getTemp(i);
    Serial.println(temp[i].f);
  }   
  Serial.println();

  delay(2000);
}

void getTemp(byte index)
{
  Wire.beginTransmission(SLAVE_ADR);
  Wire.write(index);
  Wire.endTransmission();

  Wire.requestFrom(SLAVE_ADR, sizeof(FloatData));
  if (Wire.available())
  {
    for (byte i = 0; i < sizeof(FloatData); i++)
      temp[index].b[i] = Wire.read();
  }
}

Slave:

#include <Wire.h>

const byte SLAVE_ADR = 1;
byte index;

union FloatData
{
  float f;
  byte b[sizeof(float)];
};

FloatData temp[4];


void setup()
{
  Wire.begin(SLAVE_ADR);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);


  temp[0].f = 10.0;
  temp[1].f = 123.5;
  temp[2].f = -30.8;
  temp[3].f = 4.99;
}

void loop()
{
}

void receiveEvent(int numBytes)
{
  index = Wire.read();
}

void requestEvent()
{
  Wire.write(temp[index].b, sizeof(FloatData));
}

Serenifly:

const byte SLAVE_ADR = 1;

Die kleinen I2C-Adressen sind reserviert, die freien beginnen bei 8.

Funktioniert super, jetzt auch mit allen 10 Werten vielen Dank :slight_smile: