I've done my share of hardware design and software programming in the past, but I'm fairly new to Arduino and I'm still learning the do's and don'ts of this platform. Here's a few don'ts and a do I learned recently.
For a project, I had to continuously (well, once per second) print two float values on an LCD. The float values had to be formatted to fit the limited space on the LCD. Basically, I have 4 characters for each float, including the decimal point. Example of how the LCD may look at some moment:
mirror: 32.4 RPM
eccent: 1.73 RPM
Simple task, right? Well, not so fast...
My first thought was to use sprintf() to format the float values, because that's what any programmer would think of first. It turns out, sprintf() provided by the Arduino libs won't accept float values. That was both surprising and unpleasant. Okay, let's look for other solutions.
Some older posts on this forum suggested using the dtostrf() function as a sprintf() replacement for floats. That seemed to work well, except once in a while it would trigger a subtle bug that allowed "10.00" to be printed exactly as-is, instead of truncating it to "10.0". Moreover, if I tried to feed "10.00" intentionally into the function, the bug would not trigger. It would only appear in some random combination of factors that I was unable to reproduce. That's not really confidence-inducing, so I abandoned this idea too.
I thought to write my own formatting functions. But most of the sane ideas I had all used the String library, or some sort of string objects, and that caused all manner of mysterious crashes and corruption. Plus, writing your own basic routines is not always fun. So that didn't work either. Looking for other solutions...
...enter PString:
http://arduiniana.org/libraries/pstring/
It doesn't crash, no matter how hard I try. That, right there, was a huge relief and a big change from everything else I tried before. It works well for simple formatting tasks, such as feeding it a float and asking "now return this float within N characters total". It's small. In fact, the code using PString generates a smaller binary than all the other options I've explored.
I highly recommend it for most simple usage scenarios when you would otherwise use the regular String lib. It's perhaps not a complete replacement, but it works well for the usual stuff.
Part of my trials and tribulations with String / sprintf / dtostrf are described here:
https://forums.adafruit.com/viewtopic.php?f=25&t=52883
Here's a sample of my test code (only the display part, the actual values are generated randomly, instead of being read from a sensor) that appears to work well with PString:
#include <Adafruit_CharacterOLED.h>
Adafruit_CharacterOLED lcd(OLED_V2, 6, 7, 8, 9, 10, 11, 12);
// http://arduiniana.org/libraries/pstring/
// This should cure the variety of problems formatting and printing
// floats on Arduino, without using the bug-ridden String library.
#include <PString.h>
// global variables for the simulated speeds that we display
float mir;
float ecc;
void setup()
{
// initialize display
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print("mirror: RPM");
lcd.setCursor(0, 1);
lcd.print("eccent: RPM");
// initialize simulated values
mir = random(0, 100);
ecc = random(0, 100);
}
void printspeed(float sp, int x, int y)
{
// properly format the displayed speed based on value
// then print it
// output print buffer
char buff[5];
// position the cursor
lcd.setCursor(x, y);
// format the number depending on its value
if (sp < 0) {
char buff[5] = " neg";
} else if (sp >= 0 && sp < 1000) {
PString(buff, sizeof(buff), sp);
} else {
char buff[5] = "high";
}
lcd.print(buff);
}
float gensp(float sp)
{
// generate new random value for speed
// max change at each step
float jit = 1.5;
// returned value
float ret;
int jitint = (int) 1000 * jit;
ret = sp + (float)random(-jitint, jitint)/1000;
if (ret < 0)
ret += jit;
if (ret >= 1000)
ret -= 100;
return ret;
}
void loop()
{
// refresh random value
mir = gensp(mir);
ecc = gensp(ecc);
// display
printspeed(mir, 8, 0);
printspeed(ecc, 8, 1);
delay(1000);
}