Converting float to string

Go To Last Post
22 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello again ,

I'm practicing math functions on my Atmega32 and I want to be able to print them on my LCD .

I need to be able to convert floats to strings.
With integers I used itoa and it works fine.
How do I do it with floats?
I cannot find a decent answer for embedded systems.
Some suggestions were to use 'ftoa' but it's not included in the stdlib .

Any advice?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I were to do this, I might strip the decimal point from the floating point string, remembering the position of the point in the string.

Then use atoi to convert the string to an integer. Next, assign the integer to a floating point variable and then divide by the appropriate power of 10.

There are probably better ways, but that should work.

If we are not supposed to eat animals, why are they made out of meat?

Last Edited: Thu. Aug 15, 2013 - 12:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AndyG wrote:
If I were to do this, I might strip the decimal point from the floating point string, remembering the position of the point in the string.

Then use itoa to convert the string to an integer. Next, assign the integer to a floating point variable and then divide by the appropriate power of 10.

There are probably better ways, but that should work.

Hmm i don't really understand how assigning the integer to a floating point variable and then dividing by the appropriate power would work , but i'm sure it's just my lack of knowledge .
Also I don't know how I would strip the decimal point.

Thanks alot for the suggestion but I think i'm going to wait for a more efficient one.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Akternatively, this might be useful...

/*			- ATOF.C -

   The ANSI "atof" function.
	   
$Name: V3_33D $	   
	   
*/

#include "ctype.h"
#include "stdlib.h"

double atof (const char *s)
  {
#ifdef _INTRINSIC
    return (atof(s));
#else
    double val, power;
    int sign, exp;

    while (isspace (*s))
      {
	 s++;
      }

    if (*s == '-')
      {
	s++;
	sign = -1;
      }
    else
      {
        sign = 1;
	if (*s == '+')
	  {
	    s++;
	  }
      }

    val = 0;
    while (isdigit (*s))
      {
	val = val * 10 + (*s++ - '0');
      }

    power = 1;

    if (*s == '.')
      {
        while (isdigit(*++s))
	  {
	    val = val * 10 + (*s - '0');
	    power = power * 10;
	  }
      }

    if (tolower(*s) == 'e')
      {
	exp = atoi (++s);
	while (exp < 0)
	  {
	    val /= 10;
	    exp++;
	  }
	while (exp > 0)
  	  {
            val *= 10;
	    exp--;
	  }
      }

    return (sign * val / power);
#endif
  }

If we are not supposed to eat animals, why are they made out of meat?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My original suggestion would first convert the modified string to an integer, which was a number of powers of ten too big.

If you simply divided the integer to the appropriate power of ten, then because this was integer division, you would lose the part of the number to the right of the decimal point.

Converting to a floating point before the division would result in the division being a floating point one; the part of the number to the right of the decimal point would thus be preserved.

If we are not supposed to eat animals, why are they made out of meat?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not proficient in C coding some of your syntax is unfamiliar to me .
So how would I input a string to that?
Would I call the function with my string as a passed variable?
I'd appreciate some help on that.

Also , I found some other method on youtube .
It works with integers and chars but it doesn't work with floats which is what I need.
My lcd displays a '?' when I use it



lcd_init(LCD_DISP_ON);
	lcd_clrscr();
	
		 

	char Lcd_result[6];
	sprintf(Lcd_result, "%.2f", 12.34 );
		  
		  
		 
	lcd_puts(Lcd_result);

	
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AndyG wrote:
My original suggestion would first convert the modified string to an integer, which was a number of powers of ten too big.

If you simply divided the integer to the appropriate power of ten, then because this was integer division, you would lose the part of the number to the right of the decimal point.

Converting to a floating point before the division would result in the division being a floating point one; the part of the number to the right of the decimal point would thus be preserved.

EDIT:

I partially understand .I could store 12.52 in an int which would round it off and give me 12. Then I would subtract the float fromthe int to get 0,52 .
Then I could display 12 , then a 'dot'character and then 0.52 multiplied by the 2 orders of power

What do you think ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
double atof (const char *s)

The idea is that you pass the (address of the) string to atof and it returns a (double) float.

If we are not supposed to eat animals, why are they made out of meat?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How about printf/sprintf ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have a lot of flash , sprintf might work ... and is flexible enough.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As for why your sprintf is not working, maybe the library you are using does not support floats?

My general approach to using "floating point" numbers on embedded microcontrollers is to use integers internally and convert to a "floating point" format manually.

If we are not supposed to eat animals, why are they made out of meat?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
The idea is that you pass the (address of the) string to atof and it returns a (double) float.

Ok thanks I'll try it out.

Quote:
How about printf/sprintf ?

Quote:
If you have a lot of flash , sprintf might work ... and is flexible enough.

Yeah I tried using sprintf as I meantioned above, but it does not work.

lcd_init(LCD_DISP_ON); 
   lcd_clrscr(); 
    
       

   char Lcd_result[6]; 
   sprintf(Lcd_result, "%.2f", 12.34 ); 
        
        
       
   lcd_puts(Lcd_result); 

But the lcd outputs a '?' character. Is there something wrong with the code?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AndyG wrote:
As for why your sprintf is not working, maybe the library you are using does not support floats?

My general approach to using "floating point" numbers on embedded microcontrollers is to use integers internally and convert to a "floating point" format manually.

Yeah I guessed that It might be something to do with the library .
As for doing it manually , I just wrote up the following code:


void printfloat(float a)
{
	lcd_clrscr();
	int roundoff = a;   // getting rounded integer
	float remainder = 0; 
	int whole_remainder = 0; // declaring remainder variable
	remainder = a - roundoff; // calculating remainder
	
	char whole[6];
	itoa(roundoff,whole,10);
	
	lcd_puts(whole);
	lcd_puts(".");
	
	whole_remainder = remainder*100;
	
	char decimals[6];
	itoa(whole_remainder,decimals,10);
	
	lcd_puts(decimals);
	
	
}

It seems to be working. I can also give it a dynamic precision input which I'm going to write up now.

Thanks for the suggestion AndyG!

Still if someone has another concrete suggestion of doing this an easier way then I'll be happy to hear it !:)
Or maybe how I can make the sprintf work.

Last Edited: Thu. Aug 15, 2013 - 01:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are most welcome :)

If we are not supposed to eat animals, why are they made out of meat?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The easy way is to read the "Standard C Library" and the provisions of printf().

Then tick one or two boxes in AS6 Properties. This will link your program with the full f-p printf() library.

Yes, you can go hand-crafting an ftoa() or even use the dstrtof() provided by your avr-gcc library.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is the final version with an input to vary the amount of decimal numbers after the point (precision)
Works perfectly


void printfloat(float a , int precision)
{
	lcd_clrscr();
	int roundoff = a;   // getting rounded integer
	float remainder = 0; 
	int whole_remainder = 0; // declaring remainder variable
	remainder = a - roundoff; // calculating remainder
	
	char whole[6]; // Numbers before the decimal point
	itoa(roundoff,whole,10); 
	
	lcd_puts(whole); // writing whole numbers to lcd
	lcd_puts("."); // writing a dot to lcd
	
	whole_remainder = remainder*(pow(10,precision));   // multiplying decimals to get a whole number . 
	
	char decimals[6];
	itoa(whole_remainder,decimals,10);
	
	lcd_puts(decimals); // writing the decimals
	
	
}

Takes about 2.8k of flash together with a math function library and the LCD library and the itoa and all that crap.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
The easy way is to read the "Standard C Library" and the provisions of printf().

Then tick one or two boxes in AS6 Properties. This will link your program with the full f-p printf() library.

Yes, you can go hand-crafting an ftoa() or even use the dstrtof() provided by your avr-gcc library.

David.

Ok thanks for the info , will check it out.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But the lcd outputs a '?' character. Is there something wrong with the code?

In your AS6 project look at Solution Explorer. For the project you are working on there is a line that says "Libraries". Right click it then "Add library". Hopefully you will find libm already ticked. Now make sure there's a tick against libprintf_flt as well. Now visit the Properties for the project and under Toolchain-AVR/GNU Linker-General make sure the bottom entry "Use vprintf library" is ticked. Now rebuild and try again. Your ? should now show a floating point number.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Works (no warnings, executes OK once adapted) on a PC.
Have you included ?
Is floating point formatting activated (adds some Ks to your avr executable?)
Edited : redundant with Clawsons.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

But the lcd outputs a '?' character. Is there something wrong with the code?

In your AS6 project look at Solution Explorer. For the project you are working on there is a line that says "Libraries". Right click it then "Add library". Hopefully you will find libm already ticked. Now make sure there's a tick against libprintf_flt as well. Now visit the Properties for the project and under Toolchain-AVR/GNU Linker-General make sure the bottom entry "Use vprintf library" is ticked. Now rebuild and try again. Your ? should now show a floating point number.

Thank you sir , It works now :)

But it takes 800bytes more memory than my custom solution . Nevertheless , i'm Using an atmega32 so plenty left.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Nevertheless , i'm Using an atmega32 so plenty left.

Exactly so why bother - by the way did you confirm that libm was ticked? If it isn't that can "cost" a considerable amount of flash space.

The thing with floating point is that you only pay the cost once. For arithmetic functions it costs 700 bytes and for full printf() float support it is about 2-2.5K. ut once those costs are paid you can use the functionality as often as often as you like. It's true that in a 2-4K AVR it's a heavy cost to pay. In anything from 16K onwards it is likely a drop in the ocean.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

Nevertheless , i'm Using an atmega32 so plenty left.

Exactly so why bother - by the way did you confirm that libm was ticked? If it isn't that can "cost" a considerable amount of flash space.

The thing with floating point is that you only pay the cost once. For arithmetic functions it costs 700 bytes and for full printf() float support it is about 2-2.5K. ut once those costs are paid you can use the functionality as often as often as you like. It's true that in a 2-4K AVR it's a heavy cost to pay. In anything from 16K onwards it is likely a drop in the ocean.

Yes libm was ticked and i ticked everything else that you said.

Thanks for the info clawson!