Decimals on TFT

Hi,

For a scale project I need to display float numbers on a TFT touch screen. The float number has 2 figures behind the decimal point (219.15 for example). I only get the numbers before the decimal point on the screen. The figure is the calibration factor off the scale.
I’m using the ‘itoa’ function to convert the float to a char.

itoa(calibration_factor_LA, LaCal, 10);

How can I display the figures behind the decimal point?

Ben

Please say which TFT and which TFT library you are using.

Most Arduino libraries support the regular Stream methods. e.g.

Serial.println("David");
lcd.print("Prentice");
tft.println(1234.5678);      //defaults to 2 decimal places
tft.println(1234.5678, 4);   //4 decimal places
tft.println("Calibration is " + String(calibration_factor_LA));
tft.println(calibration_factor_LA, 5);   //5 decimal places

David.

itoa means integer to ascii, that might explain that the float is truncated.

you can do the whole part first and the decimal part thereafter

int w = f ;
int d = round((f - w)* 100);
print w
print .
print d

Rob,

Look @ the dutch version I think I found a solution. Het Nederlandstalig Arduino forum - Bekijk onderwerp - Decimale waardes op TFT

robtillaart:
itoa means integer to ascii, that might explain that the float is truncated.

you can do the whole part first and the decimal part thereafter

int w = f ;
int d = round((f - w)* 100);
print w
print .
print d

You forgot something.

int w = f ;
int d = round((f - w)* 100);
print w
print .
if (d < 10) print 0
print d

you are 100% right ... :slight_smile:

This dec_str function appears to work, rounds the value up/down and handles negative numbers...
of course the float number has integer maximum number limits.

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

void loop() {
  
  float test = -1234.5678;
  Serial.println( dec_str( test ) );
  while(1);
}

char* dec_str(float value)
{
   char str[33];
   itoa(value,str,10);
   strcat(str,".");
   int dec = 0.5 + 100 * abs(value - (int)value);
   if(dec<10) strcat(str,"0");
   itoa(dec,&str[strlen(str)],10);
   return str;
}

Edit: Ah came back to fix the x.999 rounding case and I see it has already been spotted! It also does not cope with negative numbers less than 1.

rowboteer:
This dec_str function appears to work, rounds the value up/down and handles negative numbers...

Nope. For example, try it on 0.998 .

If God gave you everything that you need in the println() method, why not use it?

For example, you can specify the number of decimal places displayed. And it should cope with the rounding properly.

Of course, the OP has never said which TFT library he is using. Most inherit the regular Print class methods. Perhaps his library does not.

David.

Hi,

I’m using the Adafruit TFTLCD library.
In the original sketch I used from JOS menu, there was a piece of code that helped with decimals.

void decimate(char test[],int dec) {  // creates decimal function  decimate(string containing integer, number of decimal places)

 int i=0;  
 int length=strlen(test);
 char msg[10]="";

 strcpy(msg,test);

 if (length <= dec) {
   for(i=dec;i>(dec-length);i--)  msg[i] = msg[i-(dec-length+1)];
   for(i=0;i<(dec+1-length);i++)  msg[i]='0';
   length = strlen(msg);
 }
 for (i=length;i>(length-dec);i--)  msg[i]=msg[i-1];
 msg[length-dec]='.';

 strcpy(test,msg);
}

I then multiplied the int value by 100 and then wrote the following.

itoa((calibration_factor_LA*100),LaCal, 10);
  decimate(LaCal, 2);

I then get a value with 2 figures after the decimal point without affecting the code.

Ben

david_prentice:
If God gave you everything that you need in the println() method, why not use it?

Or dtostrf() if you are not using a DUE.

Sadly sprintf() does not work on floats in the Arduino IDE.

Usually functions like this are needed to find the length of a string for formatting the text on a display.

My point was: Print method()s will work on ANY Arduino and on any compatible library. e.g. Serial, lcd, Adafruit_TFTLCD, ...

I am guessing that Ben has an integer variable that he wants to display as a decimal.
e.g. you calculate in integer cents but want to display in dollars.
e.g. you calculate in millimetres but want to display in centimetres or metres.

tft.println(1234.5678);      //defaults to 2 decimal places
tft.println(1234.5678, 4);   //4 decimal places
tft.println(0.01 * cents);    //dollars.  defaults to 2 decimal places
tft.println(0.001 * length_in_mm, 3);   //metres to 3 decimal places
tft.println(0.01 * integer_caliibration_hundreds);    //decimal.  defaults to 2 decimal places
tft.println(0.01 * integer_caliibration_hundreds, 2);    //decimal to 2 decimal places

David.

I came to this thread hoping I would find some code to use as I need a function like Ben, but in my case to reduce a sketch size, display right justified parameters on a TFT and build strings for JSON messages. The TFT does support the print() methods but at a cost of code size.

print() also has an annoying habit of putting a - sign in front of a rounded up small negative number e.g -0.00 which looks "untidy" to me. This function does not do that deliberatlely.

This is the final solution I am using, as it was written whilst consuming some homemade mead the usual caveats apply!

/*  Function to convert a float (or double) type to a string array
 *  The value will be printed to 2 decimal places
 */
char* dec2str(float value)
{
  char str[24]; // Increase if the "units" string is lengthened
  
  int ptr = 0;  // Array member pointer
  
  if (value < -0.005) { str[ptr] = '-'; ptr++; } // Check sign and append
  
  // else {str[ptr]='+'; ptr++;} // Optionally add + sign at beginning
  // str[ptr]='

For my needs I add the parameter "units" to the end of the string, it would also be easy to add $ or + at the start, see commented out lines.

Attached is a test sketch that checks some "corner/boundary/break it" cases of the functions and compares them to the print() output.

Also attached are a few test sketches to compare compiled code sizes of a minimalist sketch.

In summary the code sizes were:

Program size

2081 bytes: print an "int"
3646 bytes: print a "float"
3280 bytes: use dtostrf() and print a character array

1996 bytes: use dec2str() function above and print a character array

So it is seems like quite a code efficient solution

For compelteness I have added an example using the String class, ouch! Minimalist sketch size is now 4750 bytes. Of course we are including a lot of hidden functionality in the sketch but if it is not wanted then it is a waste of precious space.

See post #14 regarding a bug in this code.

print_float.ino (301 Bytes)

dtostrf.ino (344 Bytes)

String_test.ino (374 Bytes)

dec2str_test.ino (4.4 KB); ptr++;        // Optionally add £ or $ etc for monetary values

value = abs(value);            // Remove the sign
  value += 0.005;                // Add to round number up
  value -= 0.0000000005;        // Fudge factor, otherwise x.0049999999 is rounded up (value of 0 not affected)

ltoa(value, str + ptr, 10);
  strcat(str, ".");

int dec = 100 * (value - (unsigned long)value);
  if (dec < 10) strcat(str, "0");
  ltoa(dec, &str[strlen(str)], 10);

// Could add units string passed as a parameter to function
  // strcat(str," mV"); // Optionally add "units" to end of string
 
  return str;
}


For my needs I add the parameter "units" to the end of the string, it would also be easy to add $ or + at the start, see commented out lines.

Attached is a test sketch that checks some "corner/boundary/break it" cases of the functions and compares them to the print() output.

Also attached are a few test sketches to compare compiled code sizes of a minimalist sketch.

In summary the code sizes were:

Program size
============

2081 bytes: print an "int"
3646 bytes: print a "float"
3280 bytes: use dtostrf() and print a character array

1996 bytes: use dec2str() function above and print a character array

So it is seems like quite a code efficient solution

For compelteness I have added an example using the String class, ouch! Minimalist sketch size is now 4750 bytes. Of course we are including a lot of hidden functionality in the sketch but if it is not wanted then it is a waste of precious space.

See post #14 regarding a bug in this code.

[print_float.ino|attachment](upload://f3LmQzQpyiXs0RO4EnvXpLVQa3x.ino) (301 Bytes)

[dtostrf.ino|attachment](upload://n96o4G54JodvDeXcsf8xc4KnpIw.ino) (344 Bytes)

[String_test.ino|attachment](upload://8YIewa0BGlusbxKesA6YxlyKghd.ino) (374 Bytes)

[dec2str_test.ino|attachment](upload://u8dLwGNuaX7AdhgaLaGiDzIXhvq.ino) (4.4 KB)

Post #12 has been updated to correct a bug where two lines of code were in the wrong order!

The mead was stronger than I thought :slight_smile:

For future convenience the latest version can be pulled from GitHub here.

Now I have come to use the dec2str() function (and the fog from mead drinking has cleared) I realise I have done something rather naughty. viz the array exists only in the function so as soon as the function exits it can get corrupted.

There are a couple of solutions, an array buffer can be declared as global for use by functions throughout the code, or the array needs to be created before calling the function and a pointer passed to it.

The GitHub repository will be updated.

I fully understand the increase in program size when you use Print or String methods.

However, once you have used them one time, there is no cost penalty in using them repeatedly.
And of course they are proven method()s that have already been debugged.

The beauty of the Arduino system is that you can add Libraries and inherit classes and methods(). e.g. Serial.print(float), lcd.print(float), tft.print(float), ... all work the same way.

The average UNO will have enough Flash to contain most sketches.
Yes, if you are trying to squeeze into a Tiny25, you have to be very careful.

David.

Absolutely agree with David, if an existing function fits your needs then use it.

There are plenty of examples here how to use the print class to print float variables etc.

I thought I would investigate why the print() method apparently prints garbage number when this is run in the test sketch I used to check the dec2str() function:

float test = -2300000000;
Serial.println( test );

It is a perfectly acceptable floating point number but the print function incorrectly outputs:

1994967296.00

I expected a duff result from my dec2str() function (which uses signed long types for the conversion), but not from the proven :wink: print method.

So what's the problem?

Many will know that the the sketch is converted in a multistage process to executable code. So, is the problem with the compiler or print() function? One simple way to find out is try the following:

test = -23000000;
test *= 100;
Serial.println( test );

Now the correct value is printed (-2300000000), so there must be a problem with the interpreter/compiler chain...

A defensive software aficionado will cite "garbage in = garbage out" and that the compiler has issued warnings in file xyzzy.w*f, and that no-one in their right mind puts numbers like that in their code, and that this violates coding style guidelines, and that this problem is well known... and that the line should be written like this:

test = -23e+8;
Serial.println( test );

Which prints correctly :slight_smile:

Another coding "Gotcha" for the unwary!

It is fairly simple rules of the language.

float test = 2300000000;    //signed long integer is default.  (int32_t)
Serial.println( test );

test = 2300000000uL;        //unsigned should give you the result that you wanted (uint32_t)
Serial.println( test );

test = -23e+8;              //double constant
Serial.println( test );


test = -2300000000;         //signed long long integer constant  (int64_t)
Serial.println( test );

Look in your K&R for the rules of C. Or Stroustroup for C++. There will be websites too.

A number constant is always treated as an int unless you tell it otherwise. Or it evaluates to a "bigger" integer.

David.

What's K&R, is that the same as R&R?

(Only joking!)