adding decimal points and zero padding for display.

I am creating a motion control project. It needs to display a number that can be upto 99.999 - this number, however, does not need to be a real float - it will not be used for any floating point anything, it just represents inches in thousandths.

So the number would typically be values such as "00.012" or 00.150" or "01.625" or even "32.699". I can see that I can hold this number in a Long type.

I need help parsing this beast and adding the decimal place. I currently have some messy messy code..

I have seen the various posts about similar topics concerning creating a string from a float, but I am not sure the requirements are the same.

Does anyone have any advice? An idea for a function that takes the raw integer and simply puts it, properly formatted, into a string?

decimate(string containing integer, number of decimal places)

void decimate(char test[],int dec) {
 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);
}

The sprintf function will convert the long to a string, with leading 0 padding:

int val = 1238;
char buff[6];
sprintf(buff, "%.5ld", val); // buff will be "01238"

Then, copy the data into another array:

char withDot[7];
withDot[0] = buff[0];
withDot[1] = buff[1];
withDot[2] = '.'; // Add the "decimal point"
withDot[3] = buff[2];
withDot[4] = buff[3];
withDot[5] = buff[4];
withDot[6] = buff[5]; // The terminating NULL

withDot will now contain "01.238"

Pauly,

Hey - thanks! That does seem close to operational. Unfortunately it is displaying really weird numbers, such as: "87.608Â
" or 84.597Â" - always with a "Â" at the end.

I have this in a loop, and the numbers change each time..

Looks like the terminating null isn't there. You could work around that with

withDot[6] = '\0';

tdc,

I tried that.. It had the exact same effect as the original code. I have been looking at sprintf syntax. It looks like the problem is possibly that the print command is trying to display the ascii values for the 1238 number, not just the 'ascii'.. if that makes any sense... This is starting to get frustrating!

here is my current test code:

int testNumber = 1238;
char buff[6];
sprintf(buff, "%.5li", testNumber); // buff will be "01238"
char withDot[7];
withDot[0] = buff[0];
withDot[1] = buff[1];
withDot[2] = '.'; // Add the "decimal point"
withDot[3] = buff[2];
withDot[4] = buff[3];
withDot[5] = buff[4];
withDot[6] = '\0'; // The terminating NULL
Serial.println(withDot);

Here is an example of the output. Notice the first value is unique, then it oscillates around at some other odd numbers..

89.247
95.997
89.292
95.997
89.292
95.997
89.292
95.997
89.292
95.997
89.292
95.997
89.292
95.997
89.292
95.997

Hmm. That's odd. I have a meeting to run to in a couple of minutes or I'd code it up and see what was going on.

The sprintf conversion syntax is odd, the source number is an int and you've got "%.5li". Try "%.5d" or just "%5d".

MoutonNoir:
Here is an example of the output. Notice the first value is unique, then it oscillates around at some other odd numbers..

Where is that output from? The problem seems to be with your Serial.println(withDot); statement. I ran the other code and it generates exactly what you want it to. That is, you get a character array withDot that has the following in it:

-		withDot	0x001ff7d0 "01.238"	char [7]
		[0]	48 '0'	char
		[1]	49 '1'	char
		[2]	46 '.'	char
		[3]	50 '2'	char
		[4]	51 '3'	char
		[5]	56 '8'	char
		[6]	0	char

Oh. I just got it working with advice from above, but it wont work with numbers greater than around 50,000... I am using a long type..

testNumber = 98000;
void setup()
{
  Serial.begin(57600);
}

void loop()
{

char buff[6];
sprintf(buff, "%.5u", testNumber); // buff will be "01238"
char withDot[7];
withDot[0] = buff[0];
withDot[1] = buff[1];
withDot[2] = '.'; // Add the "decimal point"
withDot[3] = buff[2];
withDot[4] = buff[3];
withDot[5] = buff[4];
withDot[6] = '\0'; // The terminating NULL
Serial.println(testNumber);
Serial.println(withDot);
}

Sounds like you may be bumping into the upper limit for an unsigned integer, which is 65,535.

Unsigned ints (unsigned integers) are the same as ints in that they store a 2 byte value. Instead of storing negative numbers however they only store positive values, yielding a useful range of 0 to 65,535 (2^16) - 1).

oh.. yeah. i am trying to use longs though..

"long testNumber = 98000;"

this is outputting "32.464"

with 68000, for instance, it is outputting "02.464"

with 38120 it outputs "38.120" - correctly! (yay) Maybe I will just limit that motion to +/- the value allowed in an int.. It should be fine.. I did want to let users select units though = so this xx.xxx could be millimeters, for instance.. A larger range than +/1 65,000 would be nice.

long testNumber = 68000;
void setup()
{
  Serial.begin(57600);
}

void loop()
{
char buff[6];
sprintf(buff, "%.5u", testNumber); // buff will be "01238"
char withDot[7];
withDot[0] = buff[0];
withDot[1] = buff[1];
withDot[2] = '.'; // Add the "decimal point"
withDot[3] = buff[2];
withDot[4] = buff[3];
withDot[5] = buff[4];
withDot[6] = '\0'; // The terminating NULL
Serial.println(testNumber);
Serial.println(withDot);
}
sprintf(buff, "%.5u", testNumber); // buff will be "01238"

Where did the l (long) go? You are trying to output testNumber as though it is unsigned int, not unsigned long. Try "%.5ld" like I first suggested.

Paul,

Thank you very much!- I eventually got it working. I do not know what I was doing wrong the first time, but here is what has ended up working:

long testNumber = 99999;
void setup()
{
  Serial.begin(57600);  
char buff[6];
sprintf(buff, "%.5ld", testNumber); // buff will be "01238"
char withDot[7];
withDot[0] = buff[0];
withDot[1] = buff[1];
withDot[2] = '.'; // Add the "decimal point"
withDot[3] = buff[2];
withDot[4] = buff[3];
withDot[5] = buff[4];
withDot[6] = '\0'; // The terminating NULL
Serial.println(testNumber);
Serial.println(withDot);
}

void loop(){
}

Hi Guys,

Could you do something like (may need converting to arduino c :blush:)

void decimate(char *result, int value, int dec)
{
sprintf(result, "%.*f", dec, (float) value);
}

int main(void)
{
char result[10];

decimate(result, 1.2, 3);

printf("[%s]\n", result); // output [1.200]
}

sorry you also mentioned zero padding:

void decimate(char result, int value, int length, int dec)
{
sprintf(result, "%0
.*f", length, dec, (float) value);
}

int main(void)
{
char result[10];

decimate(result, 1.2, 6, 3);

printf("[%s]\n", result); // output [01.200]
}