Sprintf () wird nicht ausgegeben

Hallo zusammen.
Ich habe folgendes Problem: ich möchte auf einem Arduino Uno via Serial bzw. LCD-Display testweise einen Wert anzeigen lassen.

Ist der Wert kleiner als 10, soll vor der Ziffer eine 0 erscheinen, dass immer 2 Ziffern dastehen.

Das habe ich mittels sprintf(%02d...) realisiert.

Jedoch scheint das Programm hier rumzuzicken, denn wenn ich den Code ausführe, erscheint garnichts auf dem seriellen Monitor bzw dem Display.
Hier der relevante Code:

char zeit1[5];
byte stunde1 = 0;

void setup() {

Serial.begin(9600);

 sprintf(zeit1, "%02d:00", stunde1);
 Serial.println(zeit1);

}

void loop() {

}

Wenn ich beim gleichen Code jedoch vor dem Befehl Serial.print(zeit1) zusätzlich noch Serial.println(stunde1) anführe, funktioniert der Code wie gewollt und Ich erhalte als Ausgabe 0 und 00:00

Woran liegt das denn?

"12:44" benötigt Platz für 6 Symbole.

1 Like

sprintf() ist speicherintensiv.
Sie könnten in kleinen Schritten tun, was Sie wollen

void setup() {
  Serial.begin(115200);
  for (byte stunde = 0; stunde < 24; stunde++) {
    if (stunde < 10) Serial.write('0');
    Serial.print(stunde);
    Serial.println(F(":00"));
  }
}

void loop() {}

alternativ könnte man auch einfach auf Buffer und Zwischenvariablen verzichten und die 0 ausgeben wenn notwendig.

if (stunde1 < 10) Serial.print('0');

Nein, es ist nicht der gleiche Code :slight_smile: Damit verschieben sich Adressen auf die zugegriffen wird, wenn es zu einer Bereichsüberschreitung kommt.

Das lässt sich aber verhindern, wenn an Stelle von sprintf() snprintf() genutzt wird.
Der Funktion wird übergeben, wie groß der Buffer ist, in den das Ergebins passen soll. Ist das Ergebnis größer, wird abgeschnitten:

char zeit1[5];
byte stunde1 = 5;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  snprintf(zeit1, 5, "%02d:00", stunde1);
  Serial.println(zeit1);
}

void loop()
{
}

liefert:

20:54:16.490 -> Start...
20:54:16.490 -> 05:0

Um sicher zu gehen, das nicht durch magische Zahlen doch eine Bereichüberschreitung eintritt, kann die - immer richtige - Größe errechnet werden:

const byte charLength =  sizeof(zeit1)/sizeof(zeit1[0]);

Das geht natürlich auch "on the fly"

  snprintf(zeit1, sizeof(zeit1)/sizeof(zeit1[0]), "%02d:00", stunde1);

birgt aber den nachteil, das bei exzessiver Anwendung mehr Rechenleistung aufgebracht werden muss. Daher mit einer Konstanten arbeiten.

Die Berechnung erfolgt in diesem Fall anhand der Länge des Buffers geteilt durch die Größe des ersten Elementes, was zur Folge hat, das Du die Anzahl der Elemente bekommst, egal welche Größe ein Element hat.

Bei einer byte-var ist 1 Element 1 byte groß.
Bei einer (u)int16_t wären es schon 2 byte und ein einfaches sizeof(wert) würde Dir ein verfälschtes Ergebnis liefern.

Ansonsten: Es ist ja bereits geschrieben worden, das es zu aufwändig ist, in dieser Form 1 (EINE) Vornull ausgeben zu lassen.

Ich geb die Zahl an eine Funktion:

void vornull(const byte zahl)
{
  if (zahl<10) Serial.print(0);
  Serial.print(zahl);
}

Was?

Wird zur Kompilezeit ausgewertet!
Ist also kostenlos!
Und doch Unsinn!


constexpr size_t buffSize {6};

char zeit1[buffSize];


snprintf(zeit1, buffSize, "%02d:00", stunde1);

So!

für ungebrauchten Speicher gibts kein Geld zurück!

sehr richtig.
Ich habe dies nur für den Fall erwähnt, dass der verfügbare Flash-Speicher im realen Projekt mit dem Display knapp wird.

char zeit[] = "xx:00";
void setup() {
   Serial.begin(115200);
   for (byte h=0;h<24;h++) {
      zeit[0] = '0' + h / 10;
      zeit[1] = '0' + h % 10;
      Serial.println(zeit);
   }
}
void loop () {}
1 Like

Das funktioniert auch – Modulo und Division sind allerdings kostspielig.

Und du glaubst, dass deine variante Sparsamer ist?

Welch ein Irrtum!

stunde ist ein Byte!
Also ein unsigned char.

Es wird aufgerufen:
size_t Print::print(unsigned char b, int base)
Die Daten werden aufgeweitet zu: unsigned long

Dann dieses aufgrufen:
size_t Print::print(unsigned long n, int base)

Welches dann zu guter Letzt dieses aufruft:

size_t Print::printNumber(unsigned long n, uint8_t base)
{
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    char c = n % base;
    n /= base;

    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while(n);

  return write(str);
}

Und was sehe ich da?
% und /

Von einer Ersparnis ist da nicht viel zu sehen!

1 Like

gutes Argument

Daher werden z.B. in RTC IC die Daten BCD-codiert gespeichert.Dann kann jede Ziffer durch shift- und masken- Operationen "verarbeitet" werden

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.