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() functionJuraj– Juraj ♦2018年06月19日 09:03:43 +00:00Commented Jun 19, 2018 at 9:03
3 Answers 3
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円';
}
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.
-
1it is not ideal for right aligned float numbers on LCD2018年06月19日 08:53:37 +00:00Commented 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.Edgar Bonet– Edgar Bonet2018年06月19日 09:59:53 +00:00Commented Jun 19, 2018 at 9:59
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