Float Values in Arduino

Status
Not open for further replies.

imranahmed

Advanced Member level 3
Joined
Dec 4, 2011
Messages
822
Helped
3
Reputation
6
Reaction score
3
Trophy points
1,298
Location
Karachi,Pakistan
Visit site
Activity points
6,533
Please let me know that I wrote Arduino code for displaying float values

and using MAX7219 for 3 digit 7-segment display.All readings are display well

but when I tend to write 0.05 it cannot display but displays 0.49 , 0.10 is 0.99 and other

values are shown well.


What is happening can any one interested to tell me?
 

but when I tend to write 0.05 it cannot display but displays 0.49 , 0.10 is 0.99 and other

values are shown well.


What is happening can any one interested to tell me?

You are storing the value in some declared variable as float so it read something like this for example if you have 5 as reading then your variable is having value 4.9999.. if you debug the code then you will see this.This is happening to you.

http://www.arduino.cc/en/Serial/Print
http://arduino.cc/en/Reference/Float
**broken link removed**
 
hello,
but when I tend to write 0.05 it cannot display but displays 0.49 , 0.10 is 0.99 and other

a mistake here ?
0.10 is 0.099 !
0.05 is 0.049 !

with PIC18F & MikroC , i don't get this behavior
if initialise a float value with 5.00 ,
or convert ascii "5.00" to float ,
i get 5.00 !

show your particular case ..(code)

don't forget than Floating point round value somewhere .. because use approximations
you can improuve some displaying result by mutipling the original value
by 100.0 and then use ceil or round or fix math function .
 
Dear paulfjujo,


Please see the attached code I have 3 digit 7-segment display interface with Arduino,MAX7219 as
display driver.

when program runs it displays 0.00 when I rotate Encoder it gives 0.01 , 0.02 , 0.03 , 0.04 but
next value should be 0.05 but it displays 0.04 (I checked with num = temp * 1000; ) multiply by 1000 it displays 0.049 means it cannot round off to 0.05 and same
event occur when value reaches 0.09 next value should be 0.10 but it displays 0.099(when * by 1000)
Code:
float f_Temp=0.0,temp=0;           // Global Variable
unsigned int num=0, RTE_VAL=0;  // Global Variable  

void loop()
{
RTE_VAL=getRotary.Encoder();  //Get Rotary Encoder Values 0,1,2,3....n

temp = RTE_VAL * 0.01;    // Make Rotary Encoder Values to decimal.


if(temp>=0.0 && temp<=9.9)  // for printing decimal values
{
num = temp * 100;
one=num%10;
ten=(num/10)%10;
hundred=(num/100)%10;
lc.setdigit(0,2,(byte)one,0);  //lc.setdigit(addr , digits , value , dp);
lc.setdigit(0,1,(byte)ten,0);
lc.setdigit(0,0,(byte)hundred,1);
}
else if(temp>=10.0 && temp<=99.9)  // for printing decimal values
{
num = temp * 10;
one=num%10;
ten=(num/10)%10;
hundred=(num/100)%10;
lc.setdigit(0,2,(byte)one,0);
lc.setdigit(0,1,(byte)ten,1);
lc.setdigit(0,0,(byte)hundred,0);
}
else if(temp>=100 && temp<=999)  // for printing decimal values
{
num = temp * 1;
one=num%10;
ten=(num/10)%10;
hundred=(num/100)%10;
lc.setdigit(0,2,(byte)one,1);
lc.setdigit(0,1,(byte)ten,0);
lc.setdigit(0,0,(byte)hundred,0);
}

}

- - - Updated - - -

Dear ud23,

There is no any problem occur when using LCD.

I am using 3 digit 7-segment display and I post Code on POST#4

Please see and comment your valuable remarks.
 
Last edited:

Code:
  int x;
   int y;
   float z;

   x = 1;
   y = x / 2;            // y now contains 0, ints can't hold fractions
   z = (float)x / 2.0;   // z now contains .5

same thing you are doing in your code too try this
Code:
temp = (float)RTE_VAL * 0.01;
 
hello,


Even using float casting; it doesn't solve the probleme..
I don't work with Arduino, but with PIC , and C keep C langage !
I allaready was facing to some problem when using or convert float to ascii and i fund a soluce..

Here you can apply same ..
Integer are alwways rounded value (no decimal of course).. but floating point are not finished number
so by adding a little offset 0,00001 you can pass over..

I don't have 3x7seg + point, so i tested with a table CRam1 with 4 position and get result on RS232 terminal..
but you juste have to adapt the display output..
and my opinion : it is better to use Float2Ascii function .. because a strange remaining value when i=990
see results ..

nota: with unsigned int maxi value is 65535 so 99999 not possible, or use long int.



coded with MikroC

Code:
unsigned char CRam1[32];
unsigned int num;
unsigned int one,ten,hundred;
float temp;


void Float2Ascii (float x, unsigned char *str,char precision)
{
 /* converts a floating point number to an ascii string */
 /* x is stored into str, which should be at least 30 chars long */
// unsigned char *adpt;
int ie, i, k, ndig;
 double y;
 //adpt=str;
 ndig = ( precision<=0) ? 7 : (precision > 22 ? 23 : precision+1);
 ie = 0;
 /* if x negative, write minus and reverse */
 if ( x < 0)
 {
   *str++ = '-';
   x = -x;
 }
 /* put x in range 1 <= x < 10 */
 if (x > 0.0) while (x < 1.0)
 {
   x *= 10.0;                // a la place de =*
   ie--;
 }
 while (x >= 10.0)
 {
   x = x/10.0;
   ie++;
 }
 // in f format, number of digits is related to size
 ndig += ie;                                // a la place de =+
 //round. x is between 1 and 10 and ndig will be printed to
 // right of decimal point so rounding is ...
 for (y = i = 1; i < ndig; i++)
 y = y/10.;
 x += y/2.;
 if (x >= 10.0) {x = 1.0; ie++;}
 if (ie<0)
 {
   *str++ = '0'; *str++ = '.';
   if (ndig < 0) ie = ie-ndig;
   for (i = -1; i > ie; i--)  *str++ = '0';
 }
 for (i=0; i < ndig; i++)
 {
   k = x;
   *str++ = k + '0';
   if (i ==  ie ) *str++ = '.';
   x -= (y=k);
   x *= 10.0;
  }
 *str = '\0';
//return (adpt);
}



void Affiche (unsigned int i)
 {
   temp = (float) i * 0.01 + 0.00001;  //  <-OK  and best writing !
   // temp = (float) i * 0.01;    // <-- BAD
   // temp =  i * 0.01 + 0.00001;    // <--- OK  even without float casting
   CRam1[4]=0;
      if(temp>=0.0 && temp<=9.9)  // for printing decimal values
      {
       num =(unsigned int) (temp * 100.0);
       one=num%10;
       ten=(num/10)%10;
       hundred=(num/100)%10;
       CRam1[3]=48+one;            //  lc.setdigit(addr , digits , value , dp);
       CRam1[2]=48+ten;            [COLOR=#0000FF][B] // add 48 to get an ascii value[/B][/COLOR]
       CRam1[1]='.';
       CRam1[0]=48+hundred;

       }
      else if(temp>=10.0 && temp<=99.99)  // for printing decimal values
       {
         num =(unsigned int) ( temp * 10.0);
         one=num%10;
         ten=(num/10)%10;
         hundred=(num/100)%10;
         CRam1[3]=48+one;  //lc.setdigit(addr , digits , value , dp);
         CRam1[2]='.';
         CRam1[1]=48+ten;
         CRam1[0]=48+hundred;
       }
         else  if(temp>=100.0 && temp<=999.999)  // for printing decimal values
        {
             num =(unsigned int)  temp;
             one=num%10;
             ten=(num/10)%10;
             hundred=(num/100)%10;
             CRam1[3]='.';
             CRam1[2]=48+one;  //lc.setdigit(addr , digits , value , dp);
             CRam1[1]=48+ten;
             CRam1[0]=48+hundred;
        }
       WordToStr(i,txt);
       UART1_Write_CText("I=");   UART1_Write_Text(txt);
       UART1_Write_CText("  Value=");   UART1_Write_Text(CRam1);
       Float2Ascii (temp,CRam1,2);
       k=strlen(CRam1) ;
       // rajoute eventuel 0 non significatif
       while (k<4)
       {
       CRam1[k]='0';CRam1[k+1]=0;
       k=strlen(CRam1) ;
       }
       CRam1[4]=0; // limite long à 4
       UART1_Write(TAB);
       UART1_Write_CText("float2ascii temp=");   UART1_Write_Text(CRam1);
       CRLF();
  }


// in  main program
  Affiche (0);
      Affiche (1);
      Affiche (49);
      Affiche (50);
      Affiche (99);
      Affiche (100);
      Affiche (101);
      Affiche (990);
      Affiche (999);
      Affiche(1000);
      Affiche (1001);
      Affiche (1010);
      Affiche (9999);
      Affiche (10000);
      Affiche (10001);
      Affiche (10010);
      Affiche (10100);
      Affiche (65535);
      Delay_ms(5000);
 
...but when I tend to write 0.05 it cannot display but displays 0.49 , 0.10 is 0.99 and other

values are shown well.


What is happening can any one interested to tell me?

You should keep in mind as with all floating point standards, including the IEEE754 and others, there is inherently an inability to represent with 100% accuracy many common used values such as 0.10. The root of the issue stems from the inability to represent an infinite number of values over a range using a floating point standard which can only represent a finite number of values over the same range, an inherent limitation when converting from a base ten decimal to a base two (binary) decimal system with limit digits of precision, these limitations result in a rounding error inherent in the use of any floating point standards.

Case in point:

The value 0.10 can only be represented approximately using the IEEE754 single precision floating point standard, 0.10 is approximated as:

0.099999994 => 00111101110011001100110011001101

These rounding errors inherent with floating point standards can certainly be an issue and should be carefully considered before utilizing a floating point standard where accuracy is foremost.

IEEE-754 Floating-Point Conversion


The main point to keep in mind is a rational value requiring a limited number of digits to be represented accurately using one system maybe a rational requiring an infinite number of digits to be represented accurately using another system and vice versa, this issue along with the finite number of values which can be represented, the precision of the system, can produce rounding errors and other associated issues.
 
Dear All members,

I want that initially display 0.00 when I rotate Encoder(KY-040) the display looks like 0.01,0.02....0.09,0.10.....0.99..

..1.00 , 1.01.....1.99 , 2.00.............................9.90 , 9.91.....9.99..10.0.........99.0.......99.9.....100,101,102.....999.

then roll over.

I programmed it but some values missed during rotating like 9.99 when I reached 9.97 and rotate once the value

should be 9.98 then 9.99 but it but when I rotate at 9.97 there is no increase in value and second rotate no increase

third rotate no increase fourth rotate the value display 10.0.

Means the value 9.98 and 9.99 are missed during rotate and same occuring with other values.

How to do this?
 

hello,


so, your problem is in encoder managment (treatment)...
and maybe parasites values.

show your code ..
Code:
getRotary.Encoder();
.

did you try to also display your raw RTE_VAL on LCD ?
did you fix your floating point display problem ?
 

From your description, one possible option is simply to use an integer type to count the the encoder clicks, incrementing and decrementing the count based on the direction of the turn. The current count can then be passed to a routine which converts the count to a string and formats it, i.e., inserts a decimal point in the proper position, adds leading zeros if needed, sign if needed, etc, which can accomplished using C's standard routines and then the resulting string is passed to your display routine.

Keep in mind, the use of integer types are a good method when counting an event, while floating types are typically used to increase the possible range of a value while maintaining a level of precision, number of significant digits.
 
Working MAX7219 mikroC PRO PIC code which displays floating point values. I have used float2ascii.h by paulfjujo.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include "float2ascii.h"
 
sbit Data7219 at LATD0_bit;
sbit Load7219 at LATD1_bit ;
sbit Clk7219 at LATD2_bit;
 
sbit Data7219_Direction at LATD0_bit;
sbit Load7219_Direction at LATD1_bit;
sbit Clk7219_Direction at LATD2_bit;
 
const unsigned char Font_B[16] = {0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,
                                  0x7f,0x7b,0x77,0x1f,0x4e,0x3d,0x4f,0x47
};
 
void Send7219 (char,char);
void Send7219byte(char);
void MAX7219init();
void Display(float);
 
double adcVal = 0.0, prevVal = 0.0;
 
void MAX7219init() {
    Data7219_Direction = 0;
    Load7219_Direction = 0;
    Clk7219_Direction = 0;
    Data7219 = 0;
    Load7219 = 0;
    Clk7219 = 0;
    Send7219(0x09, 0x00); //Decode Mode
    Send7219(0x0A, 0x05); //Brightness
    Send7219(0x0B, 0x07); //Scan limit
    Send7219(0x0C, 0x01);
    Send7219(0x0F, 0x00);
}
 
void Send7219(char Digit,char Data) {
    Send7219byte(Digit);
    Send7219byte(Data);
    Data7219 = 0;
    Load7219 = 1;
    Delay_us(20);
    Load7219 = 0;
}
 
void Send7219byte(char byte) {
 
    unsigned char i;
 
    for(i = 0; i < 8; i++)
    {
        if(byte & 0x80)
                Data7219 = 1;
        else
                Data7219 = 0;
 
        Clk7219 = 1;
        Delay_us(20);
        Clk7219 = 0;
 
        byte <<= 1;
    }
}
 
void Display(double fpNum) {
 
        unsigned char dispskip;         // add 1 if "." found within string
        unsigned char i, dp, str[30];
 
        Float2Ascii(fpNum, str, 2);     //Convert float value to string
        Ltrim(str);                     //remove spaces padded to left of string
        LCD_Out(1,1,str);
        dispskip = strlen(str) - 1;
 
        if(dispskip >= 8)dispskip = 7;
 
        i = 0;
        dp = 0;
        while(i <= dispskip) {
 
                if((str[dispskip-i] >= 0x30) && (str[dispskip - i] <= 0x39) && (dp == 0)) {
                      Send7219(i+1, (Font_B[str[dispskip-i] - 0x30]));//0-9
                }
                
                if((str[dispskip-i] >= 0x30) && (str[dispskip - i] <= 0x39) && (dp)) {
                      Send7219(i, (Font_B[str[dispskip-i] - 0x30]));//0-9
                }
 
                if(str[dispskip-i] == '.') {
                       Send7219(i+1, (Font_B[str[dispskip-(i+1)] - 0x30]) | 0x80);//
                       i++;
                       dp = 1;
                }
                
                i++;
        }
        
        while(i <= 8) {
              Send7219(i, 0);
              i++;
        }
}
 
void main() {
 
        TRISA = 0xFF;
        TRISB = 0x00;
        PORTB = 0x00;
        LATB = 0x00;
        TRISD = 0x00;
        PORTD = 0x00;
        LATD = 0x00;
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
 
        MAX7219init();
 
        while(1) {
        
              unsigned char i = 0;
              for(i = 0; i < 20; i++) {
                    adcVal += ADC_Read(0);
                    Delay_ms(20);
              }
              adcVal /= 20;
 
              if(prevVal != adcVal) {
              
                      Display(adcVal);
                      
                      prevVal = adcVal;
              }
        }
}

 
Dear paulfjujo,

did you try to also display your raw RTE_VAL on LCD ?
I am using 3 digit 7-seg display and tried.

did you fix your floating point display problem ?

I tried dtostrf() function but some floating values are not rounding, i.e 3.45 , 3.459 but should br next value 3.46.
Some values between 0.00 to 9.99 are not fully round.



Please refer POST#4 for code I will send complete code soon.
 

Replace


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while(i <= dispskip) {
 
                if((str[dispskip-i] >= 0x30) && (str[dispskip - i] <= 0x39) && (dp == 0)) {
                      Send7219(i+1, (Font_B[str[dispskip-i] - 0x30]));//0-9
                }
                
                if((str[dispskip-i] >= 0x30) && (str[dispskip - i] <= 0x39) && (dp)) {
                      Send7219(i, (Font_B[str[dispskip-i] - 0x30]));//0-9
                }
 
                if(str[dispskip-i] == '.') {
                       Send7219(i+1, (Font_B[str[dispskip-(i+1)] - 0x30]) | 0x80);//
                       i++;
                       dp = 1;
                }
                
                i++;
        }



with


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
while(i <= dispskip) {
 
                if((str[dispskip-i] >= 0x30) && (str[dispskip - i] <= 0x39)) {
            if(!dp)Send7219(i+1, (Font_B[str[dispskip-i] - 0x30]));//0-9
            elseif(dp)Send7219(i, (Font_B[str[dispskip-i] - 0x30]));//0-9
                      
                }
                
                if(str[dispskip-i] == '.') {
                       Send7219(i+1, (Font_B[str[dispskip-(i+1)] - 0x30]) | 0x80);//
                       i++;
                       dp = 1;
                }
                
                i++;
        }

 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…