8

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.

1
  • use dtostrf() function
    – Juraj
    Jun 19, 2018 at 9:03

3 Answers 3

4

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';
}
3

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.

2
  • it is not ideal for right aligned float numbers on LCD
    – Juraj
    Jun 19, 2018 at 8:53
  • 1
    @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. Jun 19, 2018 at 9:59
0

One can use the String() type initialization to convert any number, including float to String. For example to convert 3.14159 simply type ⤵︎

float num = 3.14159
String str1 = String(num, 1) // 3.1
String str2 = String(num, 2) // 3.14
String str3 = String(num, 3) // 3.141

To the right of the comma is the number of decimal places one wants the string result to have. It has a lot of functionality but that's one of the overloads. You can see them all here!

To see this code working on a .ino sketch check out this GitHub repo https://github.com/aeonSolutions/aeonlabs-ESP32-C-Base-Firmware-Libraries

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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