Formatierung bei sprintf()

Ich bin mir unsicher, ob die Arduino-IDE das überhaupt kann. Finden unter Arduino kann ich zu den Punkt sprintf() nichts. Das soll nicht heißen, dass es nichts gibt.

Folgender Code funtioniert:

void setup()
{
Serial.begin(9600);
char logString[130];
 int totalDay =2; 
 int totalMonth=2;
 int totalYear=2013;
 int totalHour=8;
 int totalMinute=5;
  
 sprintf(logString,"%02d.%02d.%4d,%02d:%02d,",totalDay,totalMonth,totalYear,totalHour,totalMinute);
 Serial.println(logString);
}
void loop(){}

Dieser hier wirft aber nur ein Müll heraus, obwohl er nach den Konventionen von sprintf() aufgebaut wurde:

void setup()
{
Serial.begin(9600);
char logString[130];
float temp1 = 15.3;
float hum1= 41.5;
float dew1 = -5.1;
Serial.println(logString);
  
sprintf(logString,"%5f,%4.1f,%#g5.1f",temp1,hum1,dew1);
 Serial.println(logString);
}
void loop(){}

Wo liegt der Fehler?

Gruß Eberhard

sprintf kann kein float Format (Edit: jedenfalls Arduino's avrgcc Version )

Abhilfe : dtostrf

eberduino:
Wo liegt der Fehler?

Die in Arduino verlinkte Version von printf hat keine Unterstützung für Gleitkommazahlen.

Warum sparst Du in Deinem Programm nicht RAM-Speicher und verwendest intern nur int für Temperaturen?
Temperaturen in hundertstel Grad ==> int
Luftfeuchte in zehntel Prozent ==> byte
Taupunkt in hundertstel Grad ==> int

Und dann formatierst Du nur zur menschlichen Ausgabe die Werte "wie eine Dezimalzahl" mit printf mit der entsprechenden Anzahl Vor- und Nachkommastellen:

void setup()
{
  Serial.begin(9600);
  char logString[130];
  int hum1= 415;
  int dew1 = -51;

 for (int temp1=-9900;temp1<=9900;temp1+=11)
  {
    sprintf(logString,"%3d.%02d, %2d.%01d, %2d.%01d",temp1/100,abs(temp1%100),hum1/10,abs(hum1%10),dew1/10,abs(dew1%10));
    Serial.println(logString);
  }   
}

void loop(){}

@michael_x: Ich habe es mir schon gedacht.
@jurs: eine gute Idee, da ich mit der LCD-Anzeige ähnlich verfahren. Fine ich nur schade, da ich hoffte auf solch elegante Art und Weise einen vernünftigen inhalt zu bekommen.
Ich habe nur Verständnisschwierigkeiten mit der Zeile:

for (int temp1=-9900;temp1<=9900;temp1+=11)

Warum muss ich hier durch eine Schleife, wenn ich als gemessenen Wert 45.7 (Grad C) *100= 4570 übergebe und temp1 = 4570 ist?

Gruß Eberhard

eberduino:
Warum muss ich hier durch eine Schleife, wenn ich als gemessenen Wert 45.7 (Grad C) *100= 4570 übergebe und temp1 = 4570 ist?

Das mußt Du natürlich in dem Fall nicht.

Die Schleife für diverse verschiedene positive und negative Temperaturen im geposteten Sketch habe ich nur zum Testen gemacht, um mich zu vergewissern, dass nicht nur positive Temperaturen, sondern auch negative Temperaturen korrekt ausgegeben werden, mit einer Null in der ersten und mit einer Null in der zweiten Nachkommastelle.

Nicht dass im Logfile nachher Temperaturen wie "-12.-30" statt "-12.30" geloggt stehen, oder vielleicht "12.3" wo es eigentlich "12.03" heißen sollte, weil da was mit der Arithmetik beim Basteln einer "Sieht-nach-Gleitkommazahl-aus" durcheinander gegangen ist.

Wenn ich hier im Forum ein paar Codezeilen poste, dann ist es eigentlich mein Anspruch, dass die dann auch soweit in Ordnung sind, dass sich sie guten Gewissens anderen empfehlen kann, weil ich sie auch selber so verwenden würde.

Hallo jurs,
jetzt verstehe ich warum. Meinen besten Dank!
Eberhard

ich habe noch eine Zusatzfrage (oder neuer thread?):

Mein logString ist 130 Zeichen lang. Stelle 1-34 ist befüllt, der NULL-Terminator an Stelle 130. Wenn ich nun ab der 35.Stelle einen char[20] einfügen möchte, wie könnte ich das am einfachsten machen? Alle mem*-Befehle beginnen (für mich :wink: ) immer an der 1.Stelle. Ich bekomme das nicht gebacken.

Gruß Eberhard

eberduino:
Mein logString ist 130 Zeichen lang. Stelle 1-34 ist befüllt, der NULL-Terminator an Stelle 130.

Und was ist an den Stellen 35 bis 129?

Normalerweise bekommst Du keine Probleme, wenn Du damit anfängst, vor dem Zusammenbasteln der Log-Zeile den String einmal komplett mit Nullzeichen auszunullen:
memset(buffer, 0, sizeof(buffer));

Und dann kannst Du von vorne weg ein Nullzeichen nach dem anderen Nullzeichen durch irgendwas anderes ersetzen.

eberduino:
Wenn ich nun ab der 35.Stelle einen char[20] einfügen möchte, wie könnte ich das am einfachsten machen? Alle mem*-Befehle beginnen (für mich :wink: ) immer an der 1.Stelle. Ich bekomme das nicht gebacken.

Einfach mit strcpy den neuen String an der Adresse im String hintendrankopieren.

Der &-Operator steht in C auch für "Adresse von", d.h. "&buffer[34]" ist "Adresse von Zeichen mit Index 34 im buffer", und da kannst Du natürlich was mit den pointerbasierten C-Stringfunktionen hinkopieren. Codebeispiel:

  memset(buffer,0,sizeof(buffer)); // buffer ausnullen
  for (int i=0;i<34;i++) // erste 34 Zeichen setzen
    buffer[i]=i+'0';
  strcpy (&buffer[34]," erfolgreich drankopiert!");
  Serial.println(buffer);

Übrigens: Mit sprintf und dem Formatierungsplatzhalter %s können auch Strings mit sprintf formatiert werden.

Das ist genau das was ich wollte!! Klasse.

Und was ist an den Stellen 35 bis 129?

Zuerst ein TimeStamp, und danach die Messwerte von n Messfühlern.

Danke!

Gruß Eberhard

eberduino:
Das ist genau das was ich wollte!! Klasse.

Na prima!

Noch eine kleine Warnung vor der "sprintf"-Funktion: Wenn Deine in Strings umzuwandelnden Parameter bei der Formatierung einen längeren Strng ergeben als geplant und als es Deiner Puffergröße entspricht (z.B. durch Programmfehler oder wegen durchgedrehter Sensoren), dann schreibt sprintf() gnadenlos über das Pufferende hinaus und überschreibt dann ggf. essentielle andere Datenbereiche.

Im Zweifelsfall also die "sichere" Version der Funktion namens "snprintf" verwenden. Die snprintf()-Funktion bekommt als zweiten Parameter die Größe des Puffers übergeben, erzeugt einen String mit maximaler Länge von Puffergröße minus 1, und arbeitet ansonsten exakt so wie sprintf auch.

Noch ein (kleines??) Problem mit der Formatierung:

sprintf(logString,"%3d.%02d, %2d.%01d, %2d.%01d",temp1/100,abs(temp1%100));

Versuch es mal mit folgenden Werten:

temp1 = -50;
temp1 = 50;

Für beide wird 0.5 angezeigt.
Klar: -50/100 = 0

Fällt jemand eine elegante Lösung ein???

Hier eine Idee:

char sign_temp1;
if (temp1 < 0) {sign_temp1 = '-';} else {sign_temp1 = '+';}
sprintf(logString,"%c%3d.%02d",sign_temp1,abs(temp1/100),abs(temp1%100));