Go Down

Topic: How to sprintf a float? (Read 29 times) previous topic - next topic

landon

I've been trying to sprintf a float value and the resulting string always contains "?".

I can sprintf integers fine.  What do I need to do to the arduino IDE/environment to deal with floating point numbers in strings?  What are some other alternatives to converting floats to string text except sprintf (I don't see an ftoa, for example.)

CrashingDutchman

#1
Dec 01, 2006, 10:45 am Last Edit: Dec 01, 2006, 10:46 am by jds Reason: 1
I have not found a real solution to this, but what I do is multiply the float by 100 or 1000 and convert it to an int. After that you can do do  with it what you want...

mellis

Sadly, linking Arduino against the version of sprintf that supports floats makes your sketches much bigger (they probably won't fit on the board), so for the moment, you'll need to do something like jds's suggestion.  sprintf() for floats is something we could consider supporting with the ATmega168 for example.

landon

That would be good.  I'm using the Arduino Mini, so I would like to think there was enough space in it.  It would be very useful.

Thanks for the replies.

caprica_cylon

I've been having a similar problem. I have a setup of 4 ds18s20's and found a code that finds them and pulls their value and helps display it to an lcd. However right now all I have are readings with 5 significant figures after the decimal place. I was using the sprintf command with a buffer but sprint(buffer,%0d%d,temp1a) works. I cannot find any other variable in the middle that will work. I just want two sig figures after and its not working. Can anyone help me out??

mem

There is code in this thread that formats floating point as a string. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207226548/11#11

But I you just need to display floats to two decimal places on an LCD (or serial port) you can use the LiquidCrystal library in Arduino release 0013

skumlerud

#6
Feb 25, 2009, 12:16 pm Last Edit: Feb 25, 2009, 12:17 pm by skumlerud Reason: 1
If you're already using itoa you can write a simple ftoa that will use very little additional space. The following code will convert an int to a string with up to nine decimals.

Code: [Select]
char *ftoa(char *a, double f, int precision)
{
 long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
 
 char *ret = a;
 long heiltal = (long)f;
 itoa(heiltal, a, 10);
 while (*a != '\0') a++;
 *a++ = '.';
 long desimal = abs((long)((f - heiltal) * p[precision]));
 itoa(desimal, a, 10);
 return ret;
}


This code first converts the integer part by casting the double to a long and convert it using itoa. Then it appends a '.' to the string, and finally it converts the decimals by multipying them by a factor of 10^precision, cast this to a long and convert it using itoa.

If you're not using itoa anywhere else in your code, the code that mem refers to might be more efficient.

caprica_cylon

Okay I am totally clueless about this arduino code I just started about 3 weeks ago. I have never do any programming. I found this code because I basically have 4 ds18s20's that I want their temperature to show up on an lcd screen. And I also want it to save to the data to a 1 gb microsd card.
I found this code and it was setup for a serial display. i added a fourbit library because I didn't know the codes to do scrolling with the standard lcd library. If anyone knows those I will be happy to change that immediately. Below is my code if anyone wants to take a peek.


Code: [Select]
//-----DS18S20 Temperature Setup-------
// Sketch to run two DS18s20's on an arduino, outputing to
// a serial enabled 20x4 LCD in Fahrenheit
//
//
// Resources
//   http://www.arduino.cc/playground/Code/PrintFloats
//   http://www.arduino.cc/playground/Learning/OneWire
//   http://216.38.50.214/cgi-bin/yabb2/YaBB.pl?num=1218768628/2
//   http://forums.fungizmos.com/viewtopic.php?f=6&t=2&st=0&sk=t&sd=a&sid=4b4e4942df2d3402308d2bf58902cd75
//   Datasheets
//     DS18s20 - http://pdfserv.maxim-ic.com/en/ds/DS18S20.pdf
//     SerLCDv2.5 - http://www.sparkfun.com/datasheets/LCD/SerLCD_V2_5.pdf
//-------------------------------------

#include <OneWire.h> //1-wire library
#undef int
#include <stdio.h>

#include <LCD4Bit.h>
LCD4Bit lcd = LCD4Bit(2);
OneWire  ds(5);  // on ardunio pin 5
#define BADTEMP -999

// Define unique sensor ID
// DS18S20 inside the house
byte alpha1[8]  = {0x10, 0xD6, 0xC4, 0x71, 0x01, 0x08, 0x00, 0x4A};
byte alpha2[8] = {0x10, 0xFE, 0xA2, 0x71, 0x01, 0x08, 0x00, 0xD0};
byte alpha3[8] = {0x10, 0x4A, 0xB3, 0x71, 0x01, 0x08, 0x00, 0xBA};
byte alpha4[8] = {0x10, 0xB5, 0xD7, 0x71, 0x01, 0x08, 0x00, 0xE2};

//----------Initialize------------------
// start serial port
void setup(void) {
 Serial.begin(9600);
 pinMode(13,OUTPUT);
 
 lcd.init();
 lcd.clear();
 
 lcd.cursorTo(1,2);
 lcd.printIn("Green Dot Tech");
 lcd.cursorTo(2,3);
  lcd.printIn("Sensor V.1");
 delay(1000);
 lcd.leftScroll(20,60);
 delay (3000);
 
 lcd.clear();
 lcd.cursorTo(1,2);
 lcd.printIn("Warming Up");
 lcd.cursorTo(2,2);
  lcd.printIn("Please Wait");
  delay (2000);
  lcd.leftScroll(20,60);

lcd.clear();
lcd.cursorTo(1,8);
lcd.printIn("A");

lcd.cursorTo(2,7);
lcd.printIn("B");
 
 
}

//---------Search_devices---------------
// Search for 1-wire devices
void search_devices() {
     byte addr[8];
     int i=0;
     
     if ( !ds.search(addr)) {
           Serial.print("No more addresses.\n");
           ds.reset_search();
           return;
           }
           Serial.print("R=");
           for( i = 0; i < 8; i++) {
                 Serial.print(addr[i], HEX);
                 Serial.print(" ");
     }
     if ( OneWire::crc8( addr, 7) != addr[7]) {
           Serial.print("CRC is not valid!\n");
           return;
     }
     
     if ( addr[0] != 0x10) {
           Serial.print("Device is not a DS18S20 family device.\n");
           return;
     }
}

//-----------GetTemp-------------------
float get_temp(byte* addr) {
 byte i;
 byte present = 0;
 byte data[12];
 int temp;
 float ftemp;

 ds.reset();
 ds.select(addr);
 ds.write(0x44,1);         // Start conversion, with parasite power on at the end
 delay(1000);    
     
 present = ds.reset();
 ds.select(addr);    
 ds.write(0xBE);         // Read Scratchpad

 for ( i = 0; i < 9; i++) {           // We need 9 bytes
   data[i] = ds.read();
 }
 
 // Get temp in something besides hex, and take the two bytes from
 // the response relating to temperature
 temp = (data[1]<<8)+data[0];

 // Get hi-rez data - see datasheet
 int cpc;
 int cr = data[6];
 cpc = data[7];      
 if (cpc == 0)
    return BADTEMP;
 temp = temp >> 1;  // Truncate by dropping bit zero for hi-rez forumua

 // Fahrenheit conversion
 temp = ((temp * 9) / 5.0) + 32; // Comment this line out to get celcius
 ftemp = temp - (float)0.25 + (cpc - cr)/(float)cpc; // Per datasheet
 return ftemp;
}

//------------PrintFloat---------------
void printFloat(float value, int places) {
// this is used to cast digits
int digit;
float tens = 0.1;
int tenscount = 0;
int i;
float tempfloat = value;

// if value is negative, set tempfloat to the abs value
// make sure we round properly. this could use pow from  
//<math.h>, but doesn't seem worth the import
// if this rounding step isn't here, the value  54.321 prints as  
//54.3209

// calculate rounding term d:   0.5/pow(10,places)
float d = 0.5;
if (value < 0)
     d *= -1.0;
// divide by ten for each decimal place
for (i = 0; i < places; i++)
     d/= 10.0;
// this small addition, combined with truncation will round our  
// values properly
tempfloat +=  d;

// first get value tens to be the large power of ten less than value
// tenscount isn't necessary but it would be useful if you wanted  
// to know after this how many chars the number will take

if (value < 0)
     tempfloat *= -1.0;
while ((tens * 10.0) <= tempfloat) {
     tens *= 10.0;
     tenscount += 1;
}

// write out the negative if needed
if (value < 0)
     Serial.print('-');

if (tenscount == 0)
     Serial.print(0, DEC);

for (i=0; i< tenscount; i++) {
     digit = (int) (tempfloat/tens);
     Serial.print(digit, DEC);
     tempfloat = tempfloat - ((float)digit * tens);
     tens /= 10.0;
}

// if no places after decimal, stop now and return
if (places <= 0)
     return;

// otherwise, write the point and continue on
Serial.print('.');

// now write out each decimal place by shifting digits one by one  
// into the ones place and writing the truncated value
for (i = 0; i < places; i++) {
     tempfloat *= 10.0;
     digit = (int) tempfloat;
     Serial.print(digit,DEC);
     // once written, subtract off that digit
     tempfloat = tempfloat - (float) digit;
}
}

//-------------Loop--------------------
void loop(void) {
//search_devices(); //Gets sensor device id. Comment out to disable

float temp1;
temp1 = get_temp(alpha1);
float temp2;
temp2 = get_temp(alpha2);
float temp3;
temp3= get_temp(alpha3);
float temp4;
temp4= get_temp(alpha4);

char buffer[2];
char baffer[3];
char beffer[4];
char biffer[5];

int temp1a = (((temp1)*100))/100;
int temp2a = ((temp2) - (int)temp2a)*1;
int temp3a = ((temp3) - (int)temp3a)*1;
int temp4a = ((temp4) - (int)temp4a)*1;

/*Serial.print(0xFE, BYTE);   // Command flag
Serial.print(130, BYTE);    // Position
Serial.print("Ambient Temp (F)");*/

Serial.print(0xFE, BYTE);  
Serial.print(192, BYTE);    
Serial.print("alpha1 = ");
//printFloat(temp,1);
lcd.cursorTo(1,0);
sprintf(buffer,"%d.%d",temp1a);
lcd.printIn(buffer);


Serial.print(0xFE, BYTE);  
Serial.print(148, BYTE);    
Serial.print("alpha2 = ");
printFloat(temp2,1);
lcd.cursorTo(2,0);
sprintf(baffer,"%d.%d",temp2a);
lcd.printIn(baffer);

Serial.print(0xFE, BYTE);  
Serial.print(148, BYTE);    
Serial.print("alpha3 = ");
printFloat(temp2,1);
lcd.cursorTo(2,9);
sprintf(beffer,"%d.%d",temp3a);
lcd.printIn(beffer);

Serial.print(0xFE, BYTE);  
Serial.print(148, BYTE);    
Serial.print("alpha4 = ");
printFloat(temp2,1);
lcd.cursorTo(1,9);
sprintf(biffer,"%d.%d",temp3a);
lcd.printIn(biffer);

Serial.print(0xFE, BYTE);   // Heartbeat to insure the it's working
Serial.print(231, BYTE);    
//Serial.print("-");
delay(1000*1);  //1 sec loop
Serial.print(0xFE, BYTE);  
Serial.print(231, BYTE);    
Serial.print("+");

}

Vambo

skumlerud

Thanks for the ftoa function. Just came across it. Very useful, especially
as a substitute for sprintf for floats.

quine

#9
Jul 10, 2010, 02:30 pm Last Edit: Jul 10, 2010, 02:32 pm by quinezhu Reason: 1
skumlerud

Thx.  it works on my Arduino Duemilanove.  and it would be better if ftoa has the function of rounding off.

VIKI

In case you would be using a more binary connection to the arduino you can also send a float in binary form to the receiving aparatus assuming the receiver uses the same float format (which it probably does):

 // arduino:
 float f=123.456; // some float
 float *f_ptr=&f;
 char *c=(char *)f_ptr;
 char buf[4];
 for (int a=0;a<4;a++) buf[a]=c[a];
 // then send buf (as buffer not as string)

 // on the receiving end when data was received (in buf):
 float o;
 float *o_ptr=&o;
 char *d=(char *)o_ptr;
 for (int a=0;a<4;a++) d[a]=buf[a];
 // and here float o holds the float output from the arduino

//-

Go Up