|
|
View previous topic :: View next topic |
Author |
Message |
VanHauser
Joined: 03 Oct 2005 Posts: 88 Location: Ploiesti, Romania
|
The same old float printf problem |
Posted: Wed Jan 31, 2007 3:52 pm |
|
|
I do the following with PCWH 4.023 :
Code: |
float f1 = -3.141500;
float f2 = -30.41500;
float f3 = -301.1500;
float f4 = -3014.500;
printf(lcd_putc, "%9f", f1); // this shows -3.141500 Correct
printf(lcd_putc, "%9f", f2); // this shows -30.415000 Why 10 chars?
printf(lcd_putc, "%9f", f3); // this shows -301.150016 Now 11 chars?
printf(lcd_putc, "%9f", f4); // this shows 1280.467200 ??!?
|
I know CCS has big issues in this matter. I need to display floats with decimal point's position not being always the same. I could really use some help... I get the same results with 3.249 too. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 31, 2007 4:41 pm |
|
|
I think CCS must have only tested "%f" with very limited number of
width and precision values. The code below works. It displays this:
Quote: |
-3.14150
-30.41500
-301.15000
-3014.50016
|
I did a few experiments and I think these might be the rules:
The "%f" format string is followed by "width.precision".
1. The width should be a maximum of 7.
2. The precision should always be at least 1 less than the width,
but no greater than 5.
For example "%f7.5" works. Also "%f4.3" works. Etc.
These rules are tentative. I didn't do a lot of testing on it.
I tested this with PCH vs. 4.023 (your version) in the MPLAB
simulator, with output going to UART1 (which is displayed in
the MPLAB output window).
Code: |
#include <18F452.h>
#fuses XT, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
//====================================
void main()
{
float f1 = -3.141500;
float f2 = -30.41500;
float f3 = -301.1500;
float f4 = -3014.500;
printf("%7.5f \n", f1);
printf("%7.5f \n", f2);
printf("%7.5f \n", f3);
printf("%7.5f \n", f4);
while(1);
} |
|
|
|
VanHauser
Joined: 03 Oct 2005 Posts: 88 Location: Ploiesti, Romania
|
|
Posted: Wed Jan 31, 2007 5:39 pm |
|
|
PCM, thank you for your prompt reply, but there's another bug. When trying to print -30141.0 with "%7.5f" it shows 12808.67072
Honestly I don't know what try anymore. I just need to print a float made of at least 7 digits, let's say 9 chars together with the sign and decimal point. The bad news is that I can't predict where the decimal point will be, so the format must be a general one. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 31, 2007 7:24 pm |
|
|
Here is a possible alternate solution. Once, a long time ago, I was trying
to investigate the problems with the CCS floating point code. I studied
the .LST file and tried to understand the ASM code. I made some
progress but it was just too time-consuming and I gave up. I don't
even use floating point anyway.
During that time, I looked for other solutions and I found that a previous
forum member, Trampas Stern, had posted code on the MPLAB forum
that he said he found on the net. He had converted it to C18. I took that
code and converted it to CCS. It works. Using your test values,
posted earlier in this thread, here is the output of the program, which
shows the values displayed by the ftoa() routine, compared to the CCS
library code. In the first four tests, CCS is correct, but after that they
fail.
Code: |
ftoa: -3.14150
ccs: -3.14150
ftoa: -30.41500
ccs: -30.41500
ftoa: -301.15001
ccs: -301.15000
ftoa: -3014.50042
ccs: -3014.50016
ftoa: -30141.50238
ccs: 12808.17152
ftoa: -301415.02380
ccs: -767.30372
ftoa: -3014150.23803
ccs: -7672.95533
ftoa: -30141502.38037
ccs: 9169.79254
|
Because the output of the ftoa() routine is placed in a string buffer,
you could take however many digits of it that you want, such as the
first nine digits as you said. You might have to write a little algorithm
to do this because if the number is negative, then the first character
will be the minus sign, etc., but it could be done.
The ftoa() routine is a little costly in terms of ROM usage. It takes
about 2300 bytes of ROM, when compiled with PCH vs. 4.023 for
an 18F452.
Here is the test program:
Code: |
#include <18F452.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#include <stdlib.h>
#include <ftoa_ts.c>
//============================
void main()
{
float f;
char buffer[30];
char prec;
char format;
float f1 = -3.141500;
float f2 = -30.41500;
float f3 = -301.1500;
float f4 = -3014.500;
float f5 = -30141.50;
float f6 = -301415.0;
float f7 = -3014150.0;
float f8 = -30141500.0;
prec = 5;
format = 'f';
ftoa(f1, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f1);
printf("\n\r");
ftoa(f2, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f2);
printf("\n\r");
ftoa(f3, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f3);
printf("\n\r");
ftoa(f4, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f4);
printf("\n\r");
ftoa(f5, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f5);
printf("\n\r");
ftoa(f6, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f6);
printf("\n\r");
ftoa(f7, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f7);
printf("\n\r");
ftoa(f8, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f8);
printf("\n\r");
while(1);
} |
Here is the Trampas Stern code, converted to CCS:
Code: |
// FUNCTION: ftoa
// AUTHOR = TRAMPAS STERN
// FILE = strio.c
// DATE = 2/6/2003 4:27:14 PM
//
// PARAMETERS: long,*str, int count
//
// DESCRIPTION: Convets an float to string
// format 'f', 'E', or 'e'
//
// RETURNS:
//
// NOTE this code was found on the web and modified
// to actually work.
//-----------------------------------------------------------
int ftoa(float x, CHAR *str, char prec, char format)
{
int k, fstyle;
signed int8 ie, i, ndig;
//double y;
//float y;
CHAR *start;
start = str;
// Based on precision, set the number of digits.
ndig = prec + 1;
// if(prec < 0)
// ndig = 7;
if(prec > 22)
ndig = 23;
fstyle = 0; // Exponent 'e'
if(format == 'f' || format == 'F')
fstyle = 1; // Normal 'f' style
if(format == 'g' || format == 'G')
fstyle=2;
ie = 0;
// If x is negative, write minus sign and reverse.
if(x < 0)
{
*str++ = '-';
x = -x;
}
// If (x < 0.0) then increment by 10 until between 1.0 and 10.0.
if(x != 0.0)
{
while (x < 1.0)
{
x =x* 10.0;
ie--;
}
}
// If x > 10 then let's shift it down.
while(x >= 10.0)
{
x = x * (1.0/10.0);
ie++;
}
/*
if(ABS(ie) > MAX_MANTISA)
{
if(fstyle==1)
{
fstyle=0;
format='e';
// ie=2;
}
}
*/
// In f format, the number of digits is related to size.
if(fstyle)
ndig = ndig + ie;
if(prec == 0 && (ie > ndig) && fstyle)
{
ndig=ie;
}
// Round. x is between 1 and 10 and ndig will be printed to
// the right of the decimal point so rounding is...
/*
y = 1;
for(i = 1; i < ndig; i++) // Find least significant digit
y = y * (1.0/10.0); // Multiplying by 1/10 is faster
// than dividing
x = x + y * (1.0/2.0); // Add rounding
// Repair rounding disasters.
if(x >= 10.0)
{
x = 1.0;
ie++;
ndig++;
}
*/
// Check and see if the number is less than 1.0
if(fstyle && ie<0)
{
*str++ = '0';
if(prec!=0)
*str++ = '.';
if(ndig < 0)
ie = ie-ndig; // Limit zeros if underflow
for(i = -1; i > ie; i--)
*str++ = '0';
}
// For each digit.
for(i=0; i < ndig; i++)
{
float b;
k = x; // k = most significant digit
*str++ = k + '0'; // Output the char representation
if(((!fstyle && i==0) || (fstyle && i==ie)) && prec!=0)
*str++ = '.'; // Output a decimal point
b = (float)k;
// Multiply by 10 before subtraction to remove
// errors from limited number of bits in float.
b = b*10.0;
x = x*10.0;
x = x - b; // Subtract k from x
// b=x+b;
// x =x* 10.0; // Get next digit
}
// Now, in e style, put out the exponent if not zero.
if(!fstyle && (ie != 0))
{
*str++ = format;
if(ie < 0) // If number has a negative exponent
{
ie = -ie;
*str++ = '-';
}
// Now we need to convert the exponent to a string.
for(k = 1000; k > ie; k = k/10); // Find the decade of exponent
for( ; k > 0; k = k/10)
{
char t;
t = DIV(ie, k);
*str++ = t + '0';
ie = ie -(t * k);
}
}
*str++ = '\0';
return (str - start); // Return string length
} |
|
|
|
VanHauser
Joined: 03 Oct 2005 Posts: 88 Location: Ploiesti, Romania
|
|
Posted: Thu Feb 01, 2007 6:03 am |
|
|
Thank you, PCM. Before seeing your post, I've came up with a simpler solution to my problem:
Code: | // Convert float to text, with max. 5 digits precision
// str should be at least 18 chars long
void float_to_text(float x, char *str) {
int1 sign = 0;
int32 whole;
int32 frac;
if (x<0) {
sign = 1;
x = -x;
}
whole = (int32)x;
x = x - whole;
x += 0.000001; // eliminate precision problems
x *= 100000; // max. 5 decimal digits
frac = (int32)x;
if (sign) str[0] = '-';
else str[0] = ' ';
sprintf(&str[1], "%lu.%05lu", whole, frac);
}
|
I use this to display my floats in 8 char strings. It also gets rid of precision trouble. It takes 5...6 ms to execute @32Mhz. If I have some time, I'll test which is faster, my solution or yours. It's good to have it for future reference though. |
|
|
VanHauser
Joined: 03 Oct 2005 Posts: 88 Location: Ploiesti, Romania
|
|
Posted: Fri Feb 02, 2007 9:51 am |
|
|
PCM, I have just tested the function you gave me, it works great and it is very fast, about 700 us execution time in my case. I will stick with it, thank you very much. |
|
|
hadeelqasaimeh
Joined: 05 Jan 2006 Posts: 105
|
|
Posted: Tue Mar 27, 2007 7:08 am |
|
|
hi pcm programmer
i try your code
it ok ,uptil some larg number,,it become wrong
here is my sample code:
Code: |
#include <16f877a.h>
#fuses XT, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
#include "lcd_kbd1.c"
#include <stdlib.h>
#include <ftoa_ts.c>
//============================
void main()
{
float f;
char buffer[30];
char prec;
char format;
float f1 = 0;
prec = 0;
format = 'f';
LCD_Init ( );
LCD_PutCmd ( CLEAR_DISP );
while (TRUE)
{
ftoa(f1, buffer, prec, format);
LCD_SetPosition ( LINE_16_1);//80-8f
printf(LCD_PutChar,"%s\n\r",buffer);
delay_ms(100);
f1=f1 +1111;
}
}
|
i dont know why!! |
|
|
hadeelqasaimeh
Joined: 05 Jan 2006 Posts: 105
|
|
Posted: Tue Mar 27, 2007 7:11 am |
|
|
i wonder what do you mean by format ?? and which to choose!!
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 27, 2007 12:21 pm |
|
|
I tested it with compiler vs. 3.249 and it worked OK. However, I didn't
use an LCD. I displayed it with the MPLAB simulator with 'UART1'.
Here is the results, displayed in the Output window:
Quote: |
0
1111
2222
3333
4444
5555
6666
7777
8888
9999
11110
12221
13332
14443
15554
16665
17776
18887
19998
21109
22220
23331
24442
etc.
|
So I think the ftoa() routine works OK. |
|
|
hadeelqasaimeh
Joined: 05 Jan 2006 Posts: 105
|
|
Posted: Tue Mar 27, 2007 4:29 pm |
|
|
hi pcm
i try to larger number,,my application suppose numbers of highr order
i will post them next;;
now if i i gnor this i try this code:
Code: |
value= READ_FLOAT_INT_EEPROM(address) ;
ftoa(value, buffer, prec, format);
strcat(S1,buffer);
strcat(S1,S2);
printf("%s",S1);
//send msg to server
|
the value is incremented by a fixed step in an external routine,,but code suspend on it!!!and dont send any thing to RS232.
help plz |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 27, 2007 4:41 pm |
|
|
You didn't show any code. My guess is the S1 and S2 are not
initialized as strings. You probably left them as empty arrays.
Read my comments in this thread about "what is a string":
http://www.ccsinfo.com/forum/viewtopic.php?t=27630 |
|
|
hadeelqasaimeh
Joined: 05 Jan 2006 Posts: 105
|
|
Posted: Tue Mar 27, 2007 5:45 pm |
|
|
thank for your fast reply
Code: |
#include <16f877a.h>
#include <string.h>
#fuses xt,NOWDT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#byte tris_d =0x00
#define address 10 // Location in EEPROM
#include <stdlib.h>
#include <ftoa_ts.c>
void WRITE_FLOAT_INT_EEPROM(long int , float );
float READ_FLOAT_INT_EEPROM(int ) ;
|
Code: |
#int_ext
void ext_isr() {
value= READ_FLOAT_INT_EEPROM(address) ;
value = value + 0.0003;
WRITE_FLOAT_INT_EEPROM( address , value );
ftoa(value, buffer, prec, format);
output_high(PIN_A1);
delay_ms(50);
output_low(PIN_A1);
}
|
Code: |
float value;
int cntr , cmd;
char buffer[30] ,S1[10],S2[10];
char prec;
char format;
|
Code: |
prec = 0;
format = 'f';
strcpy(S1,"*1$&");
strcpy(S2,"#"); |
Code: | value= READ_FLOAT_INT_EEPROM(address) ;
ftoa(value, buffer, prec, format);
strcat(S1,buffer);
strcat(S1,S2);
printf("%s",S1);
//send msg to server
}// read
|
Code: |
///////subroutine////////
void WRITE_FLOAT_INT_EEPROM(long int n, float data) {
int i;
for (i = 0; i < 4; i++)
write_eeprom(i + n, *((int8*)&data + i) ) ;
}
//////////////////////////////////////////
float READ_FLOAT_INT_EEPROM(int n) {
int i;
float data;
for (i = 0; i < 4; i++)
*((int8*)&data + i) = read_eeprom(i + n);
return(data);
}
//////////////////////////////////////
|
thank you again |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 27, 2007 5:47 pm |
|
|
What exact line does it lock-up on ? |
|
|
hadeelqasaimeh
Joined: 05 Jan 2006 Posts: 105
|
|
Posted: Tue Mar 27, 2007 5:51 pm |
|
|
Code: | value= READ_FLOAT_INT_EEPROM(address) ;
ftoa(value, buffer, prec, format);
strcat(S1,buffer);
strcat(S1,S2);
printf("%s",S1); |
this phrase |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 27, 2007 5:58 pm |
|
|
Add some putc() statements to determine which line it locks up on.
Run the program and watch the output in the terminal window on your PC.
Then post the results. This will tell us which line is causing the lockup.
Code: |
putc('A');
value= READ_FLOAT_INT_EEPROM(address) ;
putc('B');
ftoa(value, buffer, prec, format);
putc('C');
strcat(S1,buffer);
putc('D');
strcat(S1,S2);
putc('E');
printf("%s",S1);
putc('F');
|
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|