Pic XC8:  ftoa() another dummy question. - Page 1
Forum section: electronics / general

author: DTJ
author_rank: Super Contributor
timestamp: January 03, 2017, 09:53:05 am
content: I'm a novice trying to convert a float variable to an ascii string and it's not going too well.I'm using MPLABx + XC8 lite + P18LF14k22I've got a temperature value as a float that I want to convert to an ASCII string.Attached below is a grab of the output from the code I'm trying out.The conversion is only doing the first character. In the example its the '-' sign.I'm sure this is because I'm not specifying the length of the output char array.However if I try to declare the array with say 8 elements as below:unsigned char buf; //temp ascii string........the compiler balks at the ftoa() line.How should I be implementing this?ThanksMy code:Code:char * buf; // <<<< I don't think this is declared correctlyfloat input = -14.25685; //test value 1//float input = 52.54821; //test value 2int status;buf = ftoa(input, &status);This is from the XC8 Compiler User Manual:Quote

author: newbrain
author_rank: Super Contributor
timestamp: January 03, 2017, 10:25:56 am
content: Given the (very incomplete: what is status, how long is the buffer, etc...) description of the ftoa() function, your code is correct.The return value is the address of the buffer (which is probably statically allocated).The compiler is right in rejecting the assignment to buf, when declared as an array: in C, array variables cannot be used as lvalues (in simple words: as targets of an assignment).You are seeing just the first character of the converted number ('-') because buf is a char pointer, and the IDE/debugger gives you...just the char pointed to!Try examining the memory at the address pointed by buf, or actually print it out using printf()/puts(), and I'm quite sure your ASCII representation of the floating point number will be there.

author: nctnico
author_rank: Super Contributor
timestamp: January 03, 2017, 10:37:28 am
content: declare buf as:char bufwhere 20 must be big enough to contain all characters and a terminating zero (google C strings).

author: matseng
author_rank: Frequent Contributor
timestamp: January 03, 2017, 10:38:50 am
content: Looks fine to me. The ftoa returns a pointer to a char, so the "char *buf" declaration is ok.Since the returned value really is a pointer to an array of chars you have to iterate over the characters until you encounter a 0-value.Code:char ch;char *p; // make a copy of the buf pointerp=buf;while (*p!=0) { // not reached the end?ch=*p; // fetch next character/* do something with ch here */p=p+1; // jump to next character}

author: newbrain
author_rank: Super Contributor
timestamp: January 03, 2017, 10:42:20 am
content: Quote from: nctnico on January 03, 2017, 10:37:28 amNot with ftoa() declared as it is, unless he strcpy the returned buffer into buf.

author: DTJ
author_rank: Super Contributor
timestamp: January 03, 2017, 10:54:22 am
content: Quote from: nctnico on January 03, 2017, 10:37:28 amntnico - thanks - I tried that and it wont compile - fails at the ltoa()Quote from: newbrain on January 03, 2017, 10:25:56 amnewbrain - Yes - on your suggestion I checked the data memory and I can see the correct values in there. See attached screen grab.Quote from: matseng on January 03, 2017, 10:38:50 ammatseng - ok so I think I'm almost understanding what is happening. The output array is dynamically created and I either need to use it directly (breaking out when the null 0x00 is reached) or to keep it simple for me to understand I need to read it into a buffer where I can see it & work forward from there?Hmmmm. I spotted something interesting, there is a difference between the input test value and the output string in memory:float input = -14.25685; //test value 1data in memory = -14.256836Many thanks for your suggestions guys. I'd be stuffed without your kind help.I'll go and play around and see if I can get it working.

author: newbrain
author_rank: Super Contributor
timestamp: January 03, 2017, 11:02:58 am
content: Quote from: DTJ on January 03, 2017, 10:54:22 amUnless you can see the ftoa() source it's difficult to say whether the ftoa() buffer is statically or dynamically allocated.I suspect it's static, with a reasonable size, and hence overwritten every time you call ftoa().This is easy to check: does ftoa() return always the same vale for buf (i.e. the memory address you examined) on subsequent calls?Yes: static allocationNo: dynamic allocation (but this would be a memory leak, as no instructions are given to release the buffer).In the first case, you might need to copy/process it before calling ftoa() again.

author: DTJ
author_rank: Super Contributor
timestamp: January 03, 2017, 11:16:25 am
content: Quote from: newbrain on January 03, 2017, 11:02:58 amThanks newbrain.I'll run it a few times and see if it stays in the same location.I copied the array as suggested and it seems to work well with the converted value saved in the TempStr[] array.My code is below - it needs a clean up.Many thanks!Code:// convert float Temp_C to an ASCII string in unsigned char TempStr[]Temp_C = -14.25685; //test value 1Temp_C = 52.54821; //test value 2char TempStr;//temperature ascii stringchar * buf;// char buffloat input = -14.25685; //test value 1//float input = 52.54821; //test value 2int status;int gCount = 0;buf = ftoa(input, &status); // output string is not in this dynamically created buffer.// data can be used directly from there or copied to another static buffer.//copy to a static bufferchar ch;char *p; // make a copy of the buf pointerp=buf;gCount = 0;while (*p!=0) { // not reached the end?ch=*p; // fetch next characterTempStr = *p; //copy from buf to TempStr[]p=p+1; // jump to next charactergCount = gCount + 1;}

author: newbrain
author_rank: Super Contributor
timestamp: January 03, 2017, 11:31:37 am
content: Quote from: DTJ on January 03, 2017, 11:16:25 amYou're welcome!And yes, your code needs some improvements, which I'll leave to you to implement.The TmpStr array is of insufficient size: even looking at your memory dump, you can see that more than 8 characters are needed, and don't forget the terminating 0. Nctnico suggestion of 20 chars should be enough.The copy loop is not correct, you miss the terminating 0......and it's definitely not "idiomatic" C (not a faultper se, but common idioms are easier to understand when reading someone else's code, and in this case the idiiomatic version would be shorter and without the off-by-one error!)

author: Ian.M
author_rank: Super Contributor
timestamp: January 03, 2017, 11:41:08 am
content: Quote from: newbrain on January 03, 2017, 11:02:58 amIts static. See sources\common\ftoa.c (from XC8 folder)Code:#include<stdlib.h>#include<stdio.h>// quick and dirty ftoa for legacy codechar *ftoa(float f, int * status){static charbuf;char *cp = buf;unsigned longl, rem;if(f < 0) {*cp++ = '-';f = -f;}l = (unsigned long)f;f -= (float)l;rem = (unsigned long)(f * 1e6);sprintf(cp, "%lu.%6.6lu", l, rem);return buf;}Its also fugly and calls sprintf(), so you might as well simply sprintf() to your own buffer or even implement putch() four output device and printf() directly to it!

author: nctnico
author_rank: Super Contributor
timestamp: January 03, 2017, 12:17:39 pm
content: Quote from: newbrain on January 03, 2017, 10:42:20 amSigh... too much C++

author: DTJ
author_rank: Super Contributor
timestamp: January 06, 2017, 07:14:14 am
content: Quote from: newbrain on January 03, 2017, 11:31:37 amThanks newbrain - I fixed the bugs you pointed out.Thanks Ian - I'll think leave the sprintf() implementation until next year when I understand a little more! I'm just glad it seems to be working.nctnico.

author: ericmichael
author_rank: Newbie
timestamp: January 10, 2017, 09:47:29 am
content: Quote from: Ian.M on January 03, 2017, 11:41:08 amI you compareCode:char * buff;float input = 12.34;int status;buff = ftoa(input, &status);withCode:char buff;float input = 12.34;sprintf(buff,"%f",input);the sprintf version uses 4554 more bytes of flash, than that used by the ftoa version.Cheers,

author: Ian.M
author_rank: Super Contributor
timestamp: January 10, 2017, 10:18:43 am
content: Yes. That's because you've just compiled in support for the '%f' format specifier which previously wasn't used as the sprintf() in XC8 ftoa() uses the '%l' specifier. It may be worth the extra FLASH, if the more flexible formatting helps you and if you have several floating point variables that need printing.If you want to do much better you will need to search for an algorithm that can convert IEEE-754 32 bit binary floats (or Microchip's proprietary 24 bit modification of that format) direct to decimal ASCII. Caution: many IEEE-754 ftoa() implementations need 64 bit integers which XC8 doesn't support.

author: Euphyllia
author_rank: Newbie
timestamp: January 14, 2017, 07:33:41 pm
content: Is this a learning exercise or an actual project you're working on? With an 8-bit PIC the first problem with this code in the real world is the fact the word "float" appears anywhereIf it's just learning or practice then please ignore.