Sprintf funktioniert nicht mit floats

Hallo,

Ich habe eigentlich wie hier beschrieben: How to Fix Arduino sprintf Float Not Formatting: Convert Float to Char String Correctly — tutorialpedia.org sprintf() aktiviert. Habe die entsprechende Datei angehängt und beim Compilen meine ich auch in der Ausgabe zu erkennen, dass er das aktiviert hat:

/home/david/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-gcc -Wall -Wextra -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections,-u,vfprintf -lprintf_flt -lm -mmcu=atmega328p -o /home/david/.var/app/cc.arduino.IDE2/cache/arduino/sketches/35FC6558740892C1AA7BFC9AEB9C1639/sketch_mar19a.ino.elf /home/david/.var/app/cc.arduino.IDE2/cache/arduino/sketches/35FC6558740892C1AA7BFC9AEB9C1639/sketch/sketch_mar19a.ino.cpp.o /home/david/.var/app/cc.arduino.IDE2/cache/arduino/sketches/35FC6558740892C1AA7BFC9AEB9C1639/../../cores/arduino_avr_uno_2c6520e3c8cd3fd575384f133191054e/core.a -L/home/david/.var/app/cc.arduino.IDE2/cache/arduino/sketches/35FC6558740892C1AA7BFC9AEB9C1639 -lm

platform.txt (8,4 KB)

Trotzdem tut es nicht, ich habe zum Testen diesen Code:

float lat = 48.3456789, lon = 9.9876543;
double altitude = 320.739;
int satellites = 7;
int hour = 13;
int minute = 42;
int sec = 7;
long unsigned int age = 95;  // 4294967295

float BackupVoltage = 3.514777, MainVoltage = 3.60;

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

  char PingSMS[500];
  snprintf(PingSMS, sizeof(PingSMS), "omaps.app/map?v=1&ll=%.5f,%.5f&n=%02d:%02d:%02d_Al%.5f_S%d_Ag%d_BV%.2fblablablabla", BackupVoltage, lon, hour, minute, sec, altitude, satellites, age, BackupVoltage);
  
  char test[20];
  snprintf(test, sizeof(test), "%.2f", 5.412);

  float humidity = 67.89;
  char buffer[20];

  Serial.print(F("test: "));
  Serial.println(test);

  Serial.print(F("PingSMS: "));
  Serial.println(PingSMS);

  sprintf(buffer, "Humidity: %.1f%%", humidity);
  Serial.println(buffer);
}

void loop() {
}

Aber der gibt mir nur das aus:

test: 5.41
PingSMS: omaps.app/map?v=1&ll=3.51478,9.98765&n=13:42:07_Al320.73901_S7_Ag95_BV-3070091300000000000000000000000.00blablablabla
Humidity: 67.9%

Es liegt wohl nicht an der Variable, denn die erste Ausgabe funktioniert ja – die zweite aber nicht. Warum? Ich habe wirklich viel Verschiedenes ausprobiert, aber komme beim besten Willen nicht darauf. Danke im Voraus für eure Hilfe!

PS: Ich verwende einen Arduino Nano (Old Bootloader), habe auch einen Arduino Uno probiert – gleiches Ergebnis.
PPS: ich habe gerade festgestellt, das ich direkt nach dem Upload des Codes eine andere Ausgabe bekomme:

test: 5.41
PingSMS: omaps.app/map?v=1&ll=3.98765&n=13:42:07_Al320.73901_S7_Ag95_BV-3070091300000000000000000000000.00blablablabla
Humidity: 67.9%
test: 5.41
PingSMS: omaps.app/map?v=1&ll=3.51478,9.98765&n=13:42:07_Al320.73901_S7_Ag95_BV-3070091300000000000000000000000.00blablablabla
Humidity: 67.9%
test: 5.41
PingSMS: omaps.app/map?v=1&ll=3.51478,9.98765&n=13:42:07_Al320.73901_S7_Ag95_BV-3070091300000000000000000000000.00blablablabla
Humidity: 67.9%

Danach sind beim erneuten Reset drücken/Neustart durch Öffnen des seriellen Monitors die Ausgaben immer gleich. Keine Ahnung, vielleicht hilft das ja :slight_smile:

Verwenden Sie dtostrf, um einen C-String für die Gleitkommazahl zu erstellen.

Dann muss ich aber einen String verwenden und das will ich möglichste vermeiden, weil das nach langer Zeit gerne durch RAM/Heap crasht. Wenn es an den anderen Stellen tut, muss es doch auch an der Stelle tun? Meine Frage war nicht nach alternativen Lösungen, sondern wie man das zum Laufen bekommt.

Na ja, dan musst damit leben oder auf eine 32 Bit MCU wechseln.
Die float unterstütztung wurde bei AVR extra begrenzt und zB. für printf() ganz gestriechen.
Manche Sachen kann man im AVR GCC freischalten nur da must du die AMTEL Doku studieren.

Nein, es handelt sich um einen C-string, nicht um einen String (mit großem S).

Der Grund, warum sprintf auf AVR-basierten Boards keine Unterstützung für Gleitkommazahlen bietet, ist deren Rechenaufwand. Die bevorzugte Methode ist die Verwendung von dtrostrf. Es scheint jedoch möglich zu sein, die Unterstützung für Gleitkommazahlen auf AVR zu aktivieren; siehe den Beitrag von oqibidipo (21. Juli 2016) auf sprintf for floats on Arduino Mega? · Issue #293 · arduino/ArduinoCore-avr · GitHub; ich habe es selbst noch nicht ausprobiert.

Anstelle von dtostr können Sie oft die normalen print-Funktionen verwenden (z. B. Serial.print/println oder file.print/println (für SD)) und in wenigen Anweisungen print verwenden.

Musst Du nicht. Schau Dir mal dtostrf an.

Gruß Tommy

Ich habs:
”age” ist ein long unsinged int, daher muss man ihn mit %lu und nicht %d wie int aufrufen… Danke für die anderen Vorschläge, aber jetzt tut es!

Kann hour und die andere negativ werden?

Nein, du meinst, das ich die dann auch als unsigned initialisiere?

Genau, am besten als
constexpr uint8_t