Go Down

### Topic: adding decimal points and zero padding for display. (Read 7820 times)previous topic - next topic

#### moutonnoir

##### Jan 31, 2011, 09:37 am
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?
Code: [Select]
`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);} `

#### PaulS

#1
##### Jan 31, 2011, 11:37 am
The sprintf function will convert the long to a string, with leading 0 padding:

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

Then, copy the data into another array:
Code: [Select]
`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"

#### moutonnoir

#2
##### Jan 31, 2011, 06:31 pm
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..

#### tdc218

#3
##### Jan 31, 2011, 07:10 pmLast Edit: Jan 31, 2011, 07:11 pm by tdc218 Reason: 1
Looks like the terminating null isn't there.  You could work around that with
Code: [Select]
`withDot[6] = '\0';`

#### moutonnoir

#4
##### Jan 31, 2011, 07:16 pm
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:
Code: [Select]
`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 NULLSerial.println(withDot);`

#### moutonnoir

#5
##### Jan 31, 2011, 07:23 pm
Here is an example of the output. Notice the first value is unique, then it oscillates around at some other odd numbers..

Code: [Select]
`89.24795.99789.29295.99789.29295.99789.29295.99789.29295.99789.29295.99789.29295.99789.29295.997`

#### tdc218

#6
##### Jan 31, 2011, 07:25 pm
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".

#### Daanii

#7
##### Jan 31, 2011, 07:49 pm

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:
Code: [Select]
`- 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`

#### moutonnoir

#8
##### Jan 31, 2011, 07:55 pm
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..

Code: [Select]
`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 NULLSerial.println(testNumber);Serial.println(withDot);}`

#### Daanii

#9
##### Jan 31, 2011, 08:11 pm
Sounds like you may be bumping into the upper limit for an unsigned integer, which is 65,535.

Quote
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).

#### moutonnoir

#10
##### Jan 31, 2011, 08:48 pm
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.

Code: [Select]
`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 NULLSerial.println(testNumber);Serial.println(withDot);}`

#### PaulS

#11
##### Jan 31, 2011, 08:50 pm
Code: [Select]
`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.

#### moutonnoir

#12
##### Jan 31, 2011, 08:54 pm
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:

Code: [Select]
`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 NULLSerial.println(testNumber);Serial.println(withDot);}void loop(){}`

#### atelae

#13
##### Jan 31, 2011, 09:03 pm
Hi Guys,

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

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]
}

#### atelae

#14
##### Jan 31, 2011, 09:11 pm
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]
}

Go Up