2

I'm using a Mega2560 and a generic SSD1306 OLED display with the Adafruit_SSD1306 (and by extension, Adafruit_gfx) library.

I need to print a bunch of float values (ranging between 30.0 and 99.9) to the display with exactly one decimal place of precision. The catch is, the Adafruit library doesn't have a printf() method, only one that takes a single ready-to-print string.

Here's an (obviously non-Arduino) Java-like example of what I'm trying to accomplish:

String foo = String.format("%.1f, %.1f\%", temp1, hum1);
// "display" is my instance of Adafruit_SSD1306
display.print(foo);

So... how can I do something similar in Arduino-compatible C(++)?

Note: for this specific program, I have (relatively speaking) RAM to burn, so I really don't care if whatever library I use to generate formatted Strings is particularly efficient (as long as it isn't leaking). If it wants to use 4k of RAM and 80k of flash to format a 20-character String, so be it.

  • use dtostrf() function – Juraj Jun 19 '18 at 9:03
2

The Adafruit_GFX class has two methods named print() and println(). These behave exactly like Serial.print() and Serial.println(). Specifically, when printing a float, you can provide a second argument telling it the number of decimal places you want after the decimal point:

display.print(temp1, 1);  // 1 digit after the decimal point
display.print(", ");
display.print(hum1, 1);  // ditto
display.print("%");

Background: the reason these methods behave like the ones of Serial is that both Adafruit_GFX and HardwareSerial inherit them from the Print virtual class.

  • it is not ideal for right aligned float numbers on LCD – Juraj Jun 19 '18 at 8:53
  • @Juraj: That's right. However, the format used by the OP in his question ("%.1f, %.1f\%") doesn't do any kind of alignment. Thus I assumed that alignment is not a requirement. – Edgar Bonet Jun 19 '18 at 9:59
1

Normally for formatting strings I'd suggest the venerable snprintf and similar functions. However, on an 8-bit Arduino when you're using floats that's not an option: the function that does all the formatting for this family if functions has had floating point support surgically removed from it. This is to make the function a fraction of the size so it's not as bloaty in small microcontrollers.

I believe there is a float-capable version somewhere on the internet that could be somehow installed, though I have never looked into doing that.

Instead you need to do the formatting of floats manually. Everything else can be done with snprintf, but the floats need to be done separately.

Fortunately there's a function specifically for formatting a float into a character array (C-string), called dtostrf and is used thus:

float myVal = 23.49173783;
char *buffer[10]; // Enough room for the digits you want and more to be safe
dtostrf(myVal, 9, 1, buffer);

The first number in the parameter list is how many characters you want to have in your output, including the . and any leading -. Any extra characters are padded with space. The second number is how many decimal places. If the first number is negative the value is left-aligned. If it's positive it's right-aligned. So the code above would give you:

〿〿〿〿〿23.5␀

(Note: I am using to denote a space character.) If you used -9 you'd get:

23.5〿〿〿〿〿␀

You can, of course, feed that created string into another string using snprintf and the %s placeholder.

char buf2[32];
snprintf(buf2, 32, "The temperature is: %s\r\n", buffer);

buf2 ⇒ "The temperature is: 23.5〿〿〿〿〿"

If you want to trim the string down to just contain the number portion and lose the spaces it's best to left-align it with a negative width, then change the first space to a :

char *space = strchr(buffer, ' ');
if (space != NULL) {
    *space = '\0';
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.