String mit Variable füllen

Hallo, kurze und ganz peinliche Frage, aber googel liefert mir da keine Antwort drauf. Ich möchte Daten in einem String per UDP verschicken, was ja leider nur als char möglich ist. Die Daten habe ich vorher als int Variable ausgelesen und möchte sie später auch wieder am Empfänger auslesen. Ich bin jedoch zu doof das ganze umzusetzen.

Hier das ganze in reduzierter Form:

int bewegung_X = 1;



char befehl[4] = {bewegung_X, '0', '8', '0'};

udp.begin(eingangs_port);
  udp.beginPacket(sende_ip, ausgangs_port);
     udp.write(befehl);
        udp.endPacket();

Als Ausgabe bekomme ich ich dann: X080? Ich würde aber gerne 1080 erhalten.

Heimdall:
Hier das ganze in reduzierter Form:

...

int bewegung_X = 1;
char befehl[4] = {bewegung_X, '0', '8', '0'};
...

Du speicherst ein int in einem Array von chars. Das muss schiefgehen.

Guck, dass Du aus dem Wert 1 ein Zeichen "1" machst – zum Beispiel mit itoa(). itoa() ist allerdings eine nicht standardkonforme Funktion, d. h., dass Dein Code dadurch schlecht oder gar nicht portierbar wird (was Dir vermutlich ziemlich egal sein dürfte).

Gruß

Gregor

Dein Array zu klein! C Strings sind NULL-terminiert! Ein String mit 4 Zeichen hat die Länge 5 mit NULL, 0 oder '\0' an der letzten Stelle.

Wieso 080 dahinter?

1 als ASCII Zeichen ist 1 + '0' (also 49)

Also um einer Ziffer auf das ASCII Zeichen zu kommen addiert man '0' oder 48 oder 0x30. Umgekehrt subtrahiert man

char befehl[] = {bewegung_X + '0', '0', '8', '0', NULL};

Um richtige Integer (mit mehreren Ziffern) in C Strings zu konvertieren gibt es itoa():
http://www.cplusplus.com/reference/cstdlib/itoa/
Kann die Zahl mal mehrere Ziffern haben?

sprintf() wäre noch eine Alternative um die Konvertierung mit "080" danach in einem Schritt zu machen. Auch da auf die Array Länge achten:

char buffer[10];
sprintf(buffer, "%d080", Bewegung_X);

Ist für ein Zeichen ist das sehr brachial (weil printf() viel Speicher braucht), aber praktisch wenn die Integer mit mehreren Ziffern hast

Aber wie gesagt, hat die Variable wirklich immer nur eine Ziffer? Wenn nein, geht die erste Variante nicht! Was soll das mit dem "080"?

Die 080 sind nur platzhalter bzw. dienen als Beispiel. Ich wollte das Beispiel hier so einfach wie möglich halten. Dort werden ebenfalls Zahlen übergeben. Die Zahlen können von -8 bis +8 sein.

Sowas solltest du gleich sagen. Statt dessen hat es nur verwirrt :slight_smile:
"Ich will Zahlen von -8 und +8 in einen String konvertieren". Da weiß man sofort was gemeint ist

Dann verwende itoa(). Damit hast du auch das Vorzeichen behandelt

char befehl[5];
itoa(Bewegung_X, befehl,  10);

Okay Danke. Funktioniert so weit. Wie kann ich die Werte beim Empfänger jetzt wieder zu int. machen?

Heimdall:
Okay Danke. Funktioniert so weit. Wie kann ich die Werte beim Empfänger jetzt wieder zu int. machen?

Siehe atoi() :slight_smile:

Gruß

Gregor

itoa = integer to ascii
atoi = ascii to integer

Die ganzen Konvertierungs-Funktionen sind hier:
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html

Ein paar davon sind nicht teil des eigentlichen C Standards (z.B. itoa() oder ltoa()), aber trotzdem weitreichend dokumentiert. D.h. du bekommst weitere Erklärungen wenn du mit Google suchst. Vor allem auf cplusplus.com. Die Ausnahme ist dtostrf(). Das ist eine AVR-spezifische Funktion für Float -> C String. Aber auch auf der Seite ist unten eine kurze Erklärung der Parameter.

Ich schaue auch bei C von A bis Z gerne nach, auch wenn es nicht speziell avr-libc ist.

Okay. Also ich muss sagen das geht mir alles etwas zu weit, bzw. ist mir zu hoch mit den Datentypen. Als ich mir vor 10 Jahren PHP beigebracht habe war das deutlich einfacher :smiley: Oder ich war einfach nur jünger oder das BWL Studium hat alles aufgesaugt :wink: Aber danke für die Links. Ich habe auch nen altes C++ Buch gefunden, das ich mir mal durchlesen werde. Datentypen sind echt nicht meine Stärke. Die Dokumentationen helfen mir ehrlich gesagt auch nur bedingt. Trotzdem Danke.

Ich habe es geschafft, dass ich die Daten übergeben bekomme. Das geht alles ohne Probleme. Allerdings sende ich ja mit dem Befehl, den du mir genannt hast nur bewegung_X. Wie gebe ich jetzt auch noch bewegung_Z, bewegung_Y und bewegung_GEAR dazu? Bzw. wie bestimme ich an welchen Container im String ich die Variable positioniere?

Wie lese ich das ganze jetzt korrekt aus?

int atoi(char *text);

bewegung_X = text[0];
bewegung_Y = text[1];
bewegung_Z = text[2];
bewegung_GEAR = text[3];

Kannst du mal mehr Informationen geben als immer nur ein paar vage Häppchen? Jetzt ist es schon wieder was ganz anderes. Sag doch gleich was du tun willst.

Am einfachsten ist das:

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

  int bewegung_X = 100;
  int bewegung_Y = -2000;
  int bewegung_Z = -5;
  int bewegung_GEAR = 30;

  char buffer[20];
  snprintf(buffer, sizeof(buffer), "%d,%d,%d,%d", bewegung_X, bewegung_Y, bewegung_Z, bewegung_GEAR);
  Serial.println(buffer);

  int value1 = atoi(strtok(buffer, ","));
  int value2 = atoi(strtok(NULL, ","));
  int value3 = atoi(strtok(NULL, ","));
  int value4 = atoi(strtok(NULL, ","));
  Serial.println(value1);
  Serial.println(value2);
  Serial.println(value3);  
  Serial.println(value4);
}

void loop() 
{
}

Schreibt erst alle Daten in einen String und zerpflückt ihn dann wieder. strtok() liefert dabei jedesmal einen Zeiger auf den nächsten Teil-String

Den Puffer dabei so groß machen dass auch wirklich alles reinpasst.

Man kann per UDP aber auch sehr einfach direkt Bytes schicken und sich den String Kram vollkommen sparen. Einfach die Daten in eine union aus einem struct und einem Byte Array packen. Und schon hat man alles direkt in Variablen ohne irgendwas zu konvertieren:

union Data
{
  byte asArray[sizeof(int) * 4];

  struct
  {
    int bewegung_X;
    int bewegung_Y;
    int bewegung_Z;
    int bewegung_GEAR;
  };
};

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

  Data data;
  data.bewegung_X = 100;
  data.bewegung_Y = -2000;
  data.bewegung_Z = -5;
  data.bewegung_GEAR = 30;

  //nur als Test alle Bytes des Arrays ausgeben
  for (unsigned int i = 0; i < sizeof(data); i++)
    Serial.println(data.asArray[i]);

}

void loop() 
{
}

Du schreibst die Daten in das struct. Durch die union belegen sie dann den gleichen Speicherplatz wie das Array. Das Array kannst du dann so versenden:

udp.write(data.asArray, sizeof(data));

Lesen geht anders herum. Du liest in das Array ein und hast direkt die Daten in den Variablen

Das ist eigentlich der übliche Weg in diesem Fall. Braucht keinen zusätzlichen Speicher für die Konvertierungsfunktionen

Dankeschön. Das eingeben mit Buffer etc. hatte ich mir schon selber gebastelt nur am aufteilen in einzelne Variablen hat es gehakt. Wirklichen vielen Dank für die Hilfe. Nächstes mal gebe ich mehr Informationen, dachte nur ich limitiere das ganze auf das meiner Meinung nach Elementare.

Jetzt kann ich die Motoren ohne Probleme ansteuern. Super!