Printing a float to string with leading zeros

Hi,

I'm having some trouble trying to correctly convert a float to a string so I could write it with a serial.print. Whenever I try to convert a float like 0.01 I always end up with a 0.1 string. I even tried the dtostrf function without success. Here is one of my test with this function which doesn't seem to work. Am I doing something wrong?

Regards,

char x [6];

void setup(){
  Serial.begin(9600);
}

void loop(){
  dtostrf(0.01, 5, 4, x);
  Serial.println(x);
  //print_float(0.01, 3);
}

How many digits do you want after the decimal sign ?
This is for two:

char buffer[20];

float f = 0.01;

void setup()
{
  Serial.begin(9600);
  while(!Serial);                   // For Leonard/Micro
  Serial.println("Started");

  dtostrf( f, -5, 2, buffer);       // float, width, precision, buffer
  Serial.println( buffer);
  
  Serial.println( f, 2);
}

void loop()
{
}

It is not possible to send "0.01" and that is received as "0.1", unless a few characters got lost along the way. So maybe there is something else causing it. For example SoftwareSerial, wrong baudrates, bad sketch, and so on.

CoraMatt:
I'm having some trouble trying to correctly convert a float to a string so I could write it with a serial.print.

Why don't you just print the float?

All of those options work for me:

char buffer[20];
float f = 0.01;

void setup() {
  Serial.begin(9600);
  while (!Serial);                  // For Leonard/Micro
  Serial.println("Started");

  Serial.println( f, 2);

  dtostrf(f,  5, 4, buffer);
  Serial.println(buffer);

  dtostrf( f, -5, 2, buffer);       // float, width, precision, buffer
  Serial.println( buffer);
}

void loop() {
}

Output on Serial Monitor:

Started
0.01
0.0100
0.01

If I change 'f' to 123.456 I get the expected results:

Started
123.46
123.4560
123.46

Thank you guys for the feedback! I tried the code john gave but I get these outputs instead of what you posted:

Started
0.01
0.99
0.99
Started
123.46
123.
123.

I just can't make sense of what is going on there...
I'm actually trying to send a bunch of variables (float & bool mainly) to a LabVIEW program via USB from my Arduino so the computer can make use of them. The following code is how I'm doing this at the moment but I'm getting the conversion from float to string with this concatenation. In particular with the flow data which is some water flow in the system. This method suppress the leading zeros when the flow is of the form 0.0x so that I end up with something like 0.x which is not really the same flow... Is there a better way to do this or is converting all my floats to strings with dtostrf prior to concatenation a good method?

void sendData(){
   
  Serial.println(messageSent+"Start;"+photodiodeVoltage+";"+gain+";"+powerDetected+";"+emissionStatus+";"
                +conditionEmissionStatus+";"+conditionFlow+";"+conditionCableInterlock+";"
                +conditionRelays+";"+conditionRoomInterlock+";"+conditionStartButton+";"+flow+";"+brokenRelay+";"
                +modeGainStable+";"+flowThreshold+";"+";End");
}

Thank you again!

The Arduino does not change 0.01 into 0.99, unless there is a memory problem. And I think with code as you show, it could be indeed a memory problem. Or else something is wrong in LabView.

Try to break up the Serial.println, and don't use the String object.

  ...
  Serial.print(F( "Start;"));
  Serial.print( photodiodeVoltage);
  Serial.print(F( ";"));
  Serial.print( gain);
  Serial.print(F( ";"));
  Serial.print( powerDetected);
  ...

Do you see the 'F()' macro ? That keeps the text in flash rom memory. Normally such a text is copied to sram during startup, but the 'F()' macro uses the text directly from the flash memory.

Can you show the whole sketch ?

You only use the String object when sending that message. I think the source code will get bigger, but the compiled code will be smaller.
Which Arduino board do you use ?
The basic Arduino boards, for example the Arduino Uno, can have mememory problems with String objects : Solving Memory Problems | Memories of an Arduino | Adafruit Learning System

I don't think it will help, perhaps LabView is doing something weird. But if do have an Arduino Uno, it is always good to get rid of the String object.

Did you know that the sketch waits when the Serial output buffer is full.
I think the buffer inside the Serial library is 64 bytes. With 9600 baud, the characters are slowly transferred to the computer.
If the buffer of 64 bytes are full, the Serial.println() waits until a character is transmitted to add a new character to the buffer.

Can you increase the 9600 baud ? To for example 115200 ?

Test
Arduino IDE 1.6.10 in linux, Arduino Uno board selected.
Original sketch : 9202 bytes code, 269 bytes sram.
With the code below : 6356 bytes code, 255 bytes rsram.

Remove the line

String messageSent = "";

And this is the new sendData:

// Fonction qui envoie les données nécessaires par USB au programme LabVIEW
void sendData(){
  Serial.print(F( "Start;"));
  Serial.print( photodiodeVoltage);
  Serial.print(F( ";"));
  Serial.print( gain);
  Serial.print(F( ";"));
  Serial.print( powerDetected);
  Serial.print(F( ";"));
  Serial.print( emissionStatus);
  Serial.print(F( ";"));
  Serial.print( conditionEmissionStatus);
  Serial.print(F( ";"));
  Serial.print( conditionFlow);
  Serial.print(F( ";"));
  Serial.print( conditionCableInterlock);
  Serial.print(F( ";"));
  Serial.print( conditionRelays);
  Serial.print(F( ";"));
  Serial.print( conditionRoomInterlock);
  Serial.print(F( ";"));
  Serial.print( conditionStartButton);
  Serial.print(F( ";"));
  Serial.print( flow);
  Serial.print(F( ";"));
  Serial.print( brokenRelay);
  Serial.print(F( ";"));
  Serial.print( modeGainStable);
  Serial.print(F( ";"));
  Serial.print( flowThreshold);
  Serial.print(F( ";"));
  Serial.print(F( ";End"));
  Serial.println();
}

Do you try to send the data every 10ms ? I don't understand the delay of 10ms in the loop.

This function is somewhat clumsy, perhaps, but it should do the job.

void showPaddedFloat (float num, int cells, int places=1) {
  if (places<0) places=0; // because lower values are not supported
  if (places>6) places=6; // because higher values are not supported
  boolean neg = false;
  long adj = (long)((num * pow(10.0, places)) + ((num>0.0)?0.5:(-0.5)));
  if (adj<0) {
    neg = true;   
    adj = -adj;
    cells--; // to leave room for the minus sign
  }
  if (places>0) {
    cells -= (places + 1);
  }
  long divisor = 1;
  for (int i=1; i<=places; i++) {
    divisor *= 10;
  }
  long frac = adj % divisor;
  adj /= divisor;
  if ((cells>9) && (adj<=999999999L)) serial.print(" ");
  if ((cells>8) && (adj<=99999999L)) serial.print(" ");
  if ((cells>7) && (adj<=9999999L)) serial.print(" ");
  if ((cells>6) && (adj<=999999L)) serial.print(" ");
  if ((cells>5) && (adj<=99999L)) serial.print(" ");
  if ((cells>4) && (adj<=9999L)) serial.print(" ");
  if ((cells>3) && (adj<=999L)) serial.print(" ");
  if ((cells>2) && (adj<=99L)) serial.print(" ");
  if ((cells>1) && (adj<=9L)) serial.print(" ");
  if (neg) serial.print("-");
  serial.print(adj);
  if (places>0) {
    serial.print(".");
    if ((places>5) && (frac<=99999L)) serial.print("0");
    if ((places>4) && (frac<=9999L)) serial.print("0");
    if ((places>3) && (frac<=999L)) serial.print("0");
    if ((places>2) && (frac<=99L)) serial.print("0");
    if ((places>1) && (frac<=9L)) serial.print("0");
    serial.print(frac);
  }
}

Usage: showPaddedFloat(x, 0, 2); where x is the floating-point number you want to show.

Well it seems to be working with this new sendData() function! I'm actually using a chipkit Uno32 as my board. I'm not very familiar with the baud rate, so would there be any undesirable side effects with an increased rate? I can change it pretty easily in both my sketch and my Labview without problem but I can't test it at this moment.

Do you try to send the data every 10ms ? I don't understand the delay of 10ms in the loop.

I use relays to provide interlock contacts for a laser module so it knows the environment is safe or not for an emission. The 10ms wait is used to provide some time for the relays to actually switch without skipping an iteration of the program, which could cause some safety issues.

Just try the higher baudrate.
If you would have said that you are using a 'pic' microcontroller, then I would not even have answered your questions :smiling_imp: It is only a little compatible with Arduino. You could enter into more trouble with that board.
Next time you buy something, look at the Cortex M0+ processors. They are on the MKR1000 board and Adafruit uses them in a number of boards.

Well it was kind of imposed on the poor intern to use this board ... aka me. Anyway I'll make sure to have a look at those for my next projects!

Thanks for your help!