Anfänger:string zusammensetzen und wieder zerlegen

Hallo Leute!

Erstmal ich bin absoluter Anfänger, hab jetzt seit 3 Wochen zwei Arduinos. Hardware ist für mich kein Problem nur beim programmieren happert es total... nun steh vor nem sicher für Euch banalen Problem:

Am ersten Arduino sind 4 analge Sensoren und 8 digitale. Er ist als I2C Slave konfiguriert. Er erfasst Messdaten rechnet ein bisschen drann rum.

Der 2. Arduino ist I2C Master und hohlt die Daten ab und macht weiter

Die Messdaten Erfassung und die generelle I2C Kommunikation hab ich hinbekommen nun zu meinem Problem:

Ich möchte am 1 Arduino die 12 Variablen zu einem String zusammenfügen das ist mit den digitalen Daten kein problem da es nur 1stellige Werte sind nur die analogen machen mir Probleme da sie von 0-1023 gehen somit bekomme ich einen String unterschiedlicher länge was mir dann am 2.arduino beim abfragen per i2c Probleme bereitet. jetzt stell ich mir halt vor das bei den Analogwerten einfach Nullen vorne eingefügt werden solange bis die Aariable 4 Stellen hat somit komme ich auf einen String der dann immer 24Byte lang ist (4x4bytes für die analogen Werte plus 8 byte für die digitalen)

Auch das Zerlegen des empfangenen Strings macht mir Probleme da ich keinen Ansatzpunkt habe... wie gesagt ich bin programmier DAU.

Ist überhaupt mein Gedankengang richtig oder gibts ne bessere Variante die Daten vom Master aus abzufragen?

danke schon mal im voraus

lg Joe

Hallo Leute!

Ich habs jetzt mal hinbekommen das es das tut was es soll. Was haltet Ihr von der Lösung?

#include <Wire.h>

// ADC Pin's deklarieren
int ADC0=0;
int ADC1=1;
int ADC2=2;
int ADC3=3;

//Kanäle deklarieren
int Kanal_1;
int Kanal_2;
int Kanal_3;
int Kanal_4;

//div deklarationen
int laenge1=0;
int laenge2=0;
int laenge3=0;
int laenge4=0;
String Geber_1 = "";
String Geber_2 = "";
String Geber_3 = "";
String Geber_4 = "";
String Geber_sum = "";


void setup ()
{
  Serial.begin(57600);
  Wire.begin(1);                                // Starte i2c bus als Slave mit addresse #1
  Wire.onRequest(i2c_request);                  // I2C interrupt Routine i2c request
}

void loop()
{
  //Kanäle einlesen
  Kanal_1=analogRead(ADC0);
  Kanal_2=analogRead(ADC1);
  Kanal_3=analogRead(ADC2);
  Kanal_4=analogRead(ADC3);
 

  //hier kommen noch einige berechnungen zu den analogwerten rein

  Geber_1 = String(Kanal_1, DEC);
  Geber_2 = String(Kanal_2, DEC);
  Geber_3 = String(Kanal_3, DEC);
  Geber_4 = String(Kanal_4, DEC);
  laenge1 = Geber_1.length();
  laenge2 = Geber_2.length();
  laenge3 = Geber_3.length();
  laenge4 = Geber_4.length();
    switch (laenge1)
  {
  case 1:
    Geber_1 = String("000" + Geber_1);
    break;
  case 2:
    Geber_1 = String("00" + Geber_1);
    break;
  case 3:
    Geber_1 = String("0" + Geber_1);
    break;
  case 4:
    break;
  }

    switch (laenge2)
  {
  case 1:
    Geber_2 = String("000" + Geber_2);
    break;
  case 2:
    Geber_2 = String("00" + Geber_2);
    break;
  case 3:
    Geber_2 = String("0" + Geber_2);
    break;
  case 4:
    break;
  }
    switch (laenge3)
  {
  case 1:
    Geber_3 = String("000" + Geber_3);
    break;
  case 2:
    Geber_3 = String("00" + Geber_3);
    break;
  case 3:
    Geber_3 = String("0" + Geber_3);
    break;
  case 4:
    break;
  }
    switch (laenge4)
  {
  case 1:
    Geber_4 = String("000" + Geber_4);
    break;
  case 2:
    Geber_4 = String("00" + Geber_4);
    break;
  case 3:
    Geber_4 = String("0" + Geber_4);
    break;
  case 4:
    break;
  }


  Geber_sum = String(Geber_1 + Geber_2 + Geber_3 + Geber_4);
  
  // Werte Seriell ausgeben
  Serial.println(Geber_sum);
  

}

void i2c_request()                                      //daten per i2c senden
{
  char buffer[32];
  Geber_sum.toCharArray(buffer, 32);
  Wire.send(buffer);
}

irgendwelche tips um den Code zu verbessern?

LG Joe

Hi,
ich habs mir jetzt nicht genau angesehen, aber gerade für dein Längenproblem bin ich der Meinung das du das (sorry) ungeschickt gelöst hast. Dafür gibt nämlich eine Funktion. Versucht mal folgendes

char buffer[90]; // hier den Wert auf was sinnvolles stellen
sprintf(buffer,"%3i",wert_zwischen_0_und_999);

oder für deine nullen

sprintf(buffer,"%03i",wert_zwischen_0_und_999);

also aus

switch (laenge1)
  {
  case 1:
    Geber_1 = String("000" + Geber_1);
    break;
  case 2:
    Geber_1 = String("00" + Geber_1);
    break;
  case 3:
    Geber_1 = String("0" + Geber_1);
    break;
  case 4:
    break;
  }

machste

  sprintf(Geber_1,"%04i",int(Geber_1));

Gruß JKW

hi danke erstmal für deinen tip. nur komm ich nicht ganz klar damit:

als ausgangspunkt gibts den "int Kanal_1" der die werte per analogread zwischen 0-1023 bekommt.

anschliessend (im mir geposteten code nicht ersichtlich) werden noch bestimmte faktoren mit dem Kanal_1 zusammen gerechnet. wir sind noch immer bei nem int der jetzt nen wertebereich von -500 bis +1000 hat.

nach den berechnungen wird der int Kanal_1 in den string Geber_1 umgewandelt. in dem switch wird dann die führenden nullen ergänzt um immer 4 stellig zu sein

danach werden die strings Geber_1 bis Geber_4 aneinandergehängt und können vom i2c master dann abgefragt werden.

wenn ich jetzt deinem beispiel folgend Geber_1 als char definiere bringe ich die integer werte nicht mehr rein , bekomme immer diesen fehler:

sticks_1_4:43: error: incompatible types in assignment of 'char' to 'char [4]'

hier nochmal der gesamte code mit deiner modifikation:

// Sticks 1-4

#include <Wire.h>

// ADC deklarieren
int ADC0=0;
int ADC1=1;
int ADC2=2;
int ADC3=3;

//Kanäle deklarieren
int Kanal_1;
int Kanal_2;
int Kanal_3;
int Kanal_4;

//div deklarationen
int laenge1=0;
int laenge2=0;
int laenge3=0;
int laenge4=0;
char Geber_1[4];
String Geber_2 = "";
String Geber_3 = "";
String Geber_4 = "";
String Geber_sum = "";


void setup ()
{
  Serial.begin(57600);
  Wire.begin(1);                                // Starte i2c bus als Slave mit addresse #1
  Wire.onRequest(i2c_request);                  // I2C interrupt Routine i2c request
}

void loop()
{
  //Kanäle einlesen
  Kanal_1=analogRead(ADC0);
  Kanal_2=analogRead(ADC1);
  Kanal_3=analogRead(ADC2);
  Kanal_4=analogRead(ADC3);
 // Geber_1 = String(Kanal_1, DEC);
  Geber_1 = char(analogRead(ADC0));
  Geber_2 = String(Kanal_2, DEC);
  Geber_3 = String(Kanal_3, DEC);
  Geber_4 = String(Kanal_4, DEC);
  //laenge1 = Geber_1.length();
  laenge2 = Geber_2.length();
  laenge3 = Geber_3.length();
  laenge4 = Geber_4.length();
  //switch (laenge1)
  //{
  //case 1:
  //  Geber_1 = String("000" + Geber_1);
  //  break;
  //case 2:
  //  Geber_1 = String("00" + Geber_1);
  //  break;
  //case 3:
  //  Geber_1 = String("0" + Geber_1);
  //  break;
  //case 4:
  //  break;
  //}
  sprintf(Geber_1,"%04i",int(Geber_1));

    switch (laenge2)
  {
  case 1:
    Geber_2 = String("000" + Geber_2);
    break;
  case 2:
    Geber_2 = String("00" + Geber_2);
    break;
  case 3:
    Geber_2 = String("0" + Geber_2);
    break;
  case 4:
    break;
  }
    switch (laenge3)
  {
  case 1:
    Geber_3 = String("000" + Geber_3);
    break;
  case 2:
    Geber_3 = String("00" + Geber_3);
    break;
  case 3:
    Geber_3 = String("0" + Geber_3);
    break;
  case 4:
    break;
  }
    switch (laenge4)
  {
  case 1:
    Geber_4 = String("000" + Geber_4);
    break;
  case 2:
    Geber_4 = String("00" + Geber_4);
    break;
  case 3:
    Geber_4 = String("0" + Geber_4);
    break;
  case 4:
    break;
  }


  Geber_sum = String(Geber_1 + Geber_2 + Geber_3 + Geber_4);
  
  // Werte Seriell ausgeben
  Serial.println(Geber_sum);
  

}

void i2c_request()                                      //daten per i2c senden
{
  char buffer[32];
  Geber_sum.toCharArray(buffer, 32);
  Wire.send(buffer);
}

wo mach ich den hier den fehler?

lg joe

edit: ausserdem ist mir gerade aufgefallen das durch sprintf das compilierte programm um ca 800byte länger ist....

Moin, hmmm versuchs mal so

// Sticks 1-4

#include <Wire.h>

// ADC deklarieren
int ADC0=0;
int ADC1=1;
int ADC2=2;
int ADC3=3;

//Kanäle deklarieren
int Kanal_1;
int Kanal_2;
int Kanal_3;
int Kanal_4;

//div deklarationen
int laenge1=0;
int laenge2=0;
int laenge3=0;
int laenge4=0;
char Geber_1[4];
String Geber_2 = "";
String Geber_3 = "";
String Geber_4 = "";
String Geber_sum = "";


void setup ()
{
  Serial.begin(57600);
  Wire.begin(1);                                // Starte i2c bus als Slave mit addresse #1
  Wire.onRequest(i2c_request);                  // I2C interrupt Routine i2c request
}

void loop()
{
  //Kanäle einlesen
  Kanal_1=analogRead(ADC0);
  Kanal_2=analogRead(ADC1);
  Kanal_3=analogRead(ADC2);
  Kanal_4=analogRead(ADC3);
 // Geber_1 = char(analogRead(ADC0));
  Geber_2 = String(Kanal_2, DEC);
  Geber_3 = String(Kanal_3, DEC);
  Geber_4 = String(Kanal_4, DEC);
  //laenge1 = Geber_1.length();
  laenge2 = Geber_2.length();
  laenge3 = Geber_3.length();
  laenge4 = Geber_4.length();
  //switch (laenge1)
  //{
  //case 1:
  //  Geber_1 = String("000" + Geber_1);
  //  break;
  //case 2:
  //  Geber_1 = String("00" + Geber_1);
  //  break;
  //case 3:
  //  Geber_1 = String("0" + Geber_1);
  //  break;
  //case 4:
  //  break;
  //}
  sprintf(Geber_1,"%04i",Kanal_1);

    switch (laenge2)
  {
  case 1:
    Geber_2 = String("000" + Geber_2);
    break;
  case 2:
    Geber_2 = String("00" + Geber_2);
    break;
  case 3:
    Geber_2 = String("0" + Geber_2);
    break;
  case 4:
    break;
  }
    switch (laenge3)
  {
  case 1:
    Geber_3 = String("000" + Geber_3);
    break;
  case 2:
    Geber_3 = String("00" + Geber_3);
    break;
  case 3:
    Geber_3 = String("0" + Geber_3);
    break;
  case 4:
    break;
  }
    switch (laenge4)
  {
  case 1:
    Geber_4 = String("000" + Geber_4);
    break;
  case 2:
    Geber_4 = String("00" + Geber_4);
    break;
  case 3:
    Geber_4 = String("0" + Geber_4);
    break;
  case 4:
    break;
  }


  Geber_sum = String(Geber_1 + Geber_2 + Geber_3 + Geber_4);
  
  // Werte Seriell ausgeben
  Serial.println(Geber_sum);
  

}

void i2c_request()                                      //daten per i2c senden
{
  char buffer[32];
  Geber_sum.toCharArray(buffer, 32);
  Wire.send(buffer);
}

das mit dem Code "zuwachs" liegt glaube ich daran das weitere libs includet werden müssen. wenns bei dir auf den speicherplatz ankommt dann kannste sprintf tatsächlich nicht benutzten. Also das hat schon seine Richtigkeit... machts halt einfacher zu schreiben :wink:

hi jkw

dank deines tips habe ich jetzt mal folgenden code gebastelt

// Sticks 1-4

#include <Wire.h>

// ADC PINS deklarieren
int ADC0=0;
int ADC1=1;
int ADC2=2;
int ADC3=3;

//Kanäle deklarieren
int Kanal_1;
int Kanal_2;
int Kanal_3;
int Kanal_4;

//div deklarationen

char Geber_1[4];
char Geber_2[4];
char Geber_3[4];
char Geber_4[4];

void setup ()
{
  Serial.begin(57600);
  Wire.begin(1);                                // Starte i2c bus als Slave mit addresse #1
  Wire.onRequest(i2c_request);                  // I2C interrupt Routine i2c request
}

void loop()
{
  //Kanäle einlesen
  Kanal_1=analogRead(ADC0);
  Kanal_2=analogRead(ADC1);
  Kanal_3=analogRead(ADC2);
  Kanal_4=analogRead(ADC3);
 
  //Kanäle Rechnen
  
  
  // ausgabe vorbereiten
  
  sprintf(Geber_1,"%04i",Kanal_1);
  sprintf(Geber_2,"%04i",Kanal_2);
  sprintf(Geber_3,"%04i",Kanal_3);
  sprintf(Geber_4,"%04i",Kanal_4);

  // Werte Seriell ausgeben
  Serial.print(Geber_1);
  Serial.print(" - ");
  Serial.print(Geber_2);
  Serial.print(" - ");
  Serial.print(Geber_3);
  Serial.print(" - ");
  Serial.println(Geber_4);
  

}

void i2c_request()                                      //daten per i2c senden
{
//  char buffer[32];
//  Geber_sum.toCharArray(buffer, 32);
  Wire.send(Geber_1);
}

nur is mir da noch was unklar: warum auch immer hab ich jetzt folgende ausgabe per seriell:

0565048504910529 - 048504910529 - 04910529 - 0529
0564048504920529 - 048504920529 - 04920529 - 0529
0565048504910530 - 048504910530 - 04910530 - 0530
0565048504910529 - 048504910529 - 04910529 - 0529
0565048504910529 - 048504910529 - 04910529 - 0529
0565048504910529 - 048504910529 - 04910529 - 0529
0565048504910530 - 048504910530 - 04910530 - 0530
0565048504920529 - 048504920529 - 04920529 - 0529
0565048504910530 - 048504910530 - 04910530 - 0530
0565048504910530 - 048504910530 - 04910530 - 0530
0565048404910529 - 048404910529 - 04910529 - 0529
0565048504920530 - 048504920530 - 04920530 - 0530
0565048504910529 - 048504910529 - 04910529 - 0529
0565048504910529 - 048504910529 - 04910529 - 0529
0565048504910529 - 048504910529 - 04910529 - 0529

die ersten 16 zeichen sind in "Geber_1" gespeichert und enthält aus mir unerfindlichen gründen alle kanäle von 1-4
die 2.te sequenz (Geber_2)mit 12 zeichen enthält die kanäle 2-4
die 3.te sequenz (Geber_3)mit 8 zeichen enthält die Kanäle 3,4
und einzig die 4.te sequenz(Geber_4) mit 4 Zeichen ist eigentlich korrekt und enthält nur den 4. Kanal

ich erkenne zwar das muster das dahintersteckt nur hab ich momentan keinen plan ... hab mir zar die englische referenz zu sprintf reingezogen nur blick ich die nicht ganz...

so wie ich das verstehe interagiert die erste sprintf anweisung mit allen nachfolgenden....

kommt mir vor wie bei ner seriellen ausgabe wo alles aneinander gereiht wird bis das Serial.println kommt

liege ich da richtig?

übrigens danke für deine hilfe.....

lg joe

edit: nachdem ich jetzt den code von den switch schleifen und unnötigen variablen befreit habe... ist der code sogar um einiges kleiner geworden :smiley:

ist doch super ( das mit dem kleiner )
jetzt würde ich folgendes vorschlagen:

statt 4 buffer variablen und 4 sprintf's machste:

// Sticks 1-4

#include <Wire.h>

// ADC PINS deklarieren
int ADC0=0;
int ADC1=1;
int ADC2=2;
int ADC3=3;

//Kanäle deklarieren
int Kanal_1;
int Kanal_2;
int Kanal_3;
int Kanal_4;

//div deklarationen

char Buffer[20];

void setup ()
{
  Serial.begin(57600);
  Wire.begin(1);                                // Starte i2c bus als Slave mit addresse #1
  Wire.onRequest(i2c_request);                  // I2C interrupt Routine i2c request
}

void loop()
{
  //Kanäle einlesen
  Kanal_1=analogRead(ADC0);
  Kanal_2=analogRead(ADC1);
  Kanal_3=analogRead(ADC2);
  Kanal_4=analogRead(ADC3);

  //Kanäle Rechnen
  
  
  // ausgabe vorbereiten
  
  sprintf(Buffer,"%04i - %04i - %04i - %04i",Kanal_1,Kanal_2,Kanal_3,Kanal_4);

  // Werte Seriell ausgeben
  Serial.println(Buffer);
  

}

void i2c_request()                                      //daten per i2c senden
{
//  char buffer[32];
//  Geber_sum.toCharArray(buffer, 32);
  Wire.send(Geber_1);
}

alles in einem. ... dann sollte dieses merkwürdige, mir unerklärlich verhalten aufhören :wink:

Gruß JKW

hi

hey super ja jetzt tut es... genial... ich danke dir recht herzlich das du mich an der hand genommen hast... :slight_smile:

mich würd es jetzt zwar doch brennend interessieren warum das mit den 4 sprintf so komisch tat aber ok

lg Joe

Und mich erst, normalerweise gibt's nur erstaunlich Ergebnisse wenn man z.b. Sowas macht
unsigned Long Test=123;
Char Buffer[10];
sprintf(Buffer,"%i",Test);

wobei das ja nun definitiv ein programmierfehler ist hab ich mich schon öfters über sowas gewundert :wink:

Freut mich das es läuft.
Gruß JKW

mach mich schlau... wo liegt da der programmier fehler? da fehlt was bei "%i" oder?

lg joe

nö, test ist vom typ long, und %i heisst "interpretiere als integer" da kommt dann irgendwas wie 4234234234 raus...
"%lu" wäre richtig ... kannst ja mal testen

ahhh ok.... sag mal hast du ne gute evtl deutsche beschreibung zu sprintf ? scheint mir sehr mächtig zu sein?

lg Joe

"mit großer Macht geht große Verantwortung einher,Luke" 8) also ja, ist schon extrem praktisch, aber ich hab schön öfters ein restart damit verursacht :wink:

und leider: nein, hab ich nicht. ist alles nur ungesundes halbwissen meinerseits. ich verwende:

%abc
wobei a entweder 0 oder ein paar andere sachen sein kann und dann für sowas steht wie "fülle mit nullen auf" oder + steht glaube für "mach ein pluszeichen davor wenns positiv ist" sowas ..

dann b anzahl an stellen ... also %08i kennst du ja schon 8 stelliger interer wert (häh?) ... vom prinzip her 8)

und dann c kann i,lu,s sein ( bestimmt noch mehr, aber die benutze ich hauptsächlich ) int,unsigned long,char array

Gruß JKW

PS: Sag Bescheid wenn du eine findest :wink:

edit1: Ich weiß das ist unvollständig und das man da noch mehr machen kann, sowas wie genauigkeit etc, das sollte nur zum Ausdruck bringen wofür ICH das hauptsächlich benutze und keine Anleitung sein :wink: ... nicht hauen

hi

so bin jetzt ganz gut mit menem projekt unterwegs.

nun möchte ich aber etwas zur sicherheit ber der daten übermittlung am I2C machen da ich hinundwieder I2C fehler habe (manchmal kommt ein undefiniertes zeichen)

jetzt hab ich 2 dinge im kopf

1.) möchte ich die zu übermittelnde zeichenfolge verkürzen/komprimieren
2.) ne prüfsumme generieren um am master den empfangenen string auf richtigkeit zu überprüfen

was gibts denn da für möglichkeiten?

lg joe

Nabend, ich denke mal es wäre am besten ein neues Thema dafür zu eröffnen, da es ja denkbar wenig mit der Überschrift zutun hat.
Mein Rat wäre lediglich nicht gegen die Symptome sondern gegen die Ursache anzu gehen. Vor jedem senden den String auf senderseite per serielle Verbindung ausgeben und sobald ein Fehler auftritt kpntrollieren ob das was du senden wolltest korrekt war.
Wenn wirklich Fehler auftreten die aber durch Induktion oder ähnliches verursacht wurden und sich nicht durch den i2c Master, dann vielleicht die Kabel verdrillen.
Checksumme könntest du sonst z.b. Aus der Summe aller zahlen modulo "beliebiger wert" errechnen und anhängen. Oder zahlen nach hex wandeln vor der übertragung. Oder oder oder :wink:
gruß JKW

ich wollte diesen thread nochmal kurz aus der Versenkung holen da ich mit genau dieser Thematik den ganzen Abend verbracht hab.
Sprintf ist mehr als gefährlich,
ich hab heute ewig gesucht und dann genau dort den Fehler gefunden
char char_buffer[20] stand irgendwo, unglaublich weit oben im Quelltext, war früher mal 100 Felder groß. Vor ner Woche hab ich mal zum optimieren das Feld auf 20 Reduziert und heute gingen immer meine Variablen flöten ... das lag letztlich daran das die Anweisung:

    sprintf(char_buffer,"%06lu,%06lu,%09lu,%09lu,%03i,%05i,%05lu,%i,%i,%i",gps_time[a],gps_date[a],gps_lati[a],gps_long[a],gps_speed_arr[a],gps_course[a],gps_alt[a],gps_sats[a],gps_fix[a],gps_special[a]);

sich schlicht "etwas mehr" speicher genommen hat. Da warnt einen keiner!

Also, wachsam bleiben!
Gruß JKW