[SOLVED] Numbers with decimals without float

Status
Not open for further replies.

Veketti

Full Member level 3
Joined
Sep 14, 2014
Messages
164
Helped
0
Reputation
0
Reaction score
0
Trophy points
16
Activity points
1,700
Dear All,

I'm struggling to get numbers with decimals in MicroC pro without using floating point numbers. Eg. I have numbers from -500 to +500 and I need to get that shown in lcd display like "5.00". Naturally I'd do it like making it float, dividing by 100 and floattostr, but MicroC says, Aaaarrggggghhh, too complicated, I give up.:thumbsdown: "There's not enough rom space"

So I am thinking that probably it should be done so that get that number in string array and move all the numbers from right one slot left and add point there. eg. "500" -> "5 00" -> "5.00". But then it would need to work for numbers like 1 also. So it would have to add zeros like "1" -> "0.01". I don't know how to do this. There has to be some easier way which might be obvious and I'm not aware so please help me?
 

Zip and post the complete mikroC project files which is giving error.
 
Agreed - sprintf/printf is a wonderful function when there is lots of speed and memory but it isn't efficient or even possible sometimes in small processors.

Could your solution be to scale everything up by 100 times then reposition the decimal after the calculations?

Brian.
 
hello


what MCU are you using

With 16F , no chance or not easy to use MikroC sprintf library
consume too much memory and ressources..
Easy only with rescent PIC18F as 18Fx6K22


i used this for 16F;

Code:
char Texte[32];
char *txt;
float V1;




void fltToa (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 */
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++;
 }
 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';
}

// to test it
// with output txt to USART

 txt=&Texte[0];

V1=3.1415964;
fltToa(V1,txt,5);   // txt point to the result in ascii
k=PutStr_RS(txt);
CRLF();
V1=31450.159;
ltToa(V1,txt,1);
k=PutStr_RS(txt);
CRLF();
 
Probably the simplest is to use the modulo operator to get the digit then display it.

For example, if the variable is 1.234, multiply it first 1000 to remove the decimal.

You get the 1234 of course, then perform successive modulo operation to get each digit. Just put the '.' after the first digit, so you can display 1.234.
 
I'm using PIC16F819 so I wasn't even using sprintf as it's not supported with this chip. Even that floattostr was too much like I said on my first post. Anyway I tried paulfjujo's function and it still got out of rom. It seems whenever I introduce float, compiler refuses to co-operate. Here's the code:
Code:
#include "float2ascii.h"
// Lcd module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

#define CALIBRATED_0G_Z 368 //this is the analog value for the zero G point for Z
#define CALIBRATED_0G_X 349   //this is the analog value for the zero G point for X
#define CALIBRATED_SENSITIVITY 59.77//this number will convert 10bit analog values
                                 //into Gs
char XAxis[30];
char ZAxis[30];
char *txtx;
char *txtz;
char TextZ[32];
char TextX[32];
signed int oldXanalogvalue=0;
signed int oldZanalogvalue=0;

void MyDelay(int time)      // Delay routines
{
 switch (time)
 {
 case 10 : delay_us(10);
 case 100 : delay_ms(100);
 }
}

int ReadXAxis (void)    // Read Xaxis values from DE-ACCM3D
{
     signed int analogvalue=0;
     signed int temp=0;
     long Gvaluelong=0;
     signed int Gvalue=0;
     ADCON0 = 0b11001101;     // setting the A/D module for AN1
     analogvalue = ADC_Read(1);
      MyDelay(10);
      analogvalue += ADC_Read(1);//take an average of 2 readings to reduce noise
      analogvalue = analogvalue / 2;
      temp = analogvalue-oldXanalogvalue;

      if( temp>1 || temp<-1 ) //ignore small changes to make display more readable
      {
         //convert analog value into G digits
         oldXanalogvalue=analogvalue;
         Gvalue=analogvalue-CALIBRATED_0G_X;
         Gvaluelong=Gvalue*100;              //  multiply by 100 before dividing to get more accuracy for int
         Gvalue=(int)Gvaluelong/CALIBRATED_SENSITIVITY;
         return Gvalue;
      }
      return 1;
}

int ReadZAxis (void)    // Read Zaxis values from DE-ACCM3D
{
     signed int analogvalue=0;
     signed int temp=0;
     signed int Gvalue=0;
     long Gvaluelong=0;
     ADCON0 = 0b11010101;     // setting the A/D module for AN2
     analogvalue = ADC_Read(2);
     MyDelay(10);
     analogvalue += ADC_Read(2);//take an average of 2 readings to reduce noise
     analogvalue = analogvalue / 2;
     temp = analogvalue-oldZanalogvalue;

      if( temp>1 || temp<-1 ) //ignore small changes to make display more readable
      {
         //convert analog value into G digits
         oldZanalogvalue=analogvalue;
         Gvalue=analogvalue-CALIBRATED_0G_Z;
         Gvaluelong=Gvalue*100;
         Gvalue=(int)Gvaluelong/CALIBRATED_SENSITIVITY;
         return Gvalue;
      }
     return 1;
}


void main(){
     int XValues = 0;
     int ZValues = 0;
     float XValuesf = 0;
     float ZValuesf = 0;
     int temp=0;
     char teksti[10];
     OSCCON = 0b01110100;  // Set internal oscillator to 8mhz
     ADCON0 = 0b11010000;     // setting the A/D module for AN2
     ADCON1 = 0b11000000;        // Set all AN ports to Analog
     TRISA  = 0b00000110;     //Set RA2 & RA1 as input, others are output
     TRISB  = 0b00000000;     // Set all RB as output
     Lcd_Init();                        // Initialize Lcd
     
  while(1) {                         // Endless loop
         temp = ReadXAxis();
         if (temp != 1) XValues = temp;   // Check to see if values updated or not
         temp = ReadZAxis();
         if (temp != 1) ZValues = temp;
         XValuesf = (float)XValues/100;   // Divide to get to right decimal
         ZValuesf = (float)ZValues/100;
         fltToa(XValuesf,txtx,2);   // Put float value to char and 2 decimal
         fltToa(ZValuesf,txtz,2);
         Lcd_Cmd(_LCD_CLEAR);
         Lcd_Cmd(_LCD_CURSOR_OFF);
         Lcd_Out(1,1,"Z=");
         Lcd_Out_Cp(Ltrim(txtz));
         Lcd_Out_Cp("G");
         Lcd_Out(2,1,"X=");
         Lcd_Out_Cp(Ltrim(txtz));
         Lcd_Out_Cp("G");
         MyDelay(100);
      }
 }

I have the fltotoa function in separate header file.
 

PIC16F819 has 4 KB ROM and your code (.hex file) is exceeding 4 KB and so you have to change the PIC. The problem is not with FloatToStr() or any string.

If the code you posted is the final code that is if there is no more additions to the code then choose a PIC with 8 KB ROM and compile. Just choose a PIC with 8 KB ROM and compile the code, then mikroC will show you the size of the Program.

I was wrong. The code compiled. I just decreased the array (string) sizer from 30 to 23. Can you tell why you were using 30 for array sizes ? Is your numerical value obtained contain 30 digits ? I think FloatToStr() will not print more than 6 digits after decimal point.

Project which compiles is attached.
 

Attachments

  • test.rar
    50.9 KB · Views: 136
Last edited:
Oh, but it was missing the float2ascii header file. Here's my complete project files.
View attachment TEST.zip

Is the program memory flash bytes 3584 the amount the c files shouldn't exceed? :roll:
 

What is the problem in using FloatToStr() function ? I commented out the to Flaot2Ascii() function called and it Compiled. Maybe the program size is exceeding the ROM size for the PIC used. Try selecting a different PIC which has 8 KB ROM and compile the code. See if it Compiles successfully. If yes then it is time to change the PIC. Also your two functions ReadXAxis() and ReadZAxis() looks similar. So, make a common function named ReadAxis() and then call it twice and read the Axis you want. The function should have option the send the ADC channel value and based on the ADC channel value provided as argument the corresponding axis value is read.

s the program memory flash bytes 3584 the amount the c files shouldn't exceed?

The amount of bytes in .hex file should not exceed ROM size.
 

hello,

I try to write your program by using local variables and get direct result in floating point values
but result gives ...
102 342 There is not enough ROM space __Lib_MathDouble.c
as you got yourself..

No way to use _lib_Mathdouble wich takes too much rom place..

with FloatToStr as an empty function, iget
// 0 1144 Used ROM (program words): 1207 (59%) Free ROM (program words): 841 (41%)
// 0 1144 Used RAM (bytes): 61 (25%) Free RAM (bytes): 179 (75%)

revised code( but not OK with this PIC):
View attachment TEST.zip

with PIC16F877, compiling is OK, i get
// 16F877
// Q=4MHZ
//CONFIG : $2007 : 0x3B7A
//0 1144 Used ROM (program words): 2162 (26%) Free ROM (program words): 6030 (74%)
//0 1144 Used RAM (bytes): 77 (22%) Free RAM (bytes): 275 (78%)

and with FloatToStr as empty function, iget
0 1144 Used ROM (program words): 1196 (15%) Free ROM (program words): 6996 (85%)
0 1144 Used RAM (bytes): 61 (17%) Free RAM (bytes): 291 (83%)

so, about 1K ROM is used by float function.. Without using C_Math library !!
 
Thank you all, you've been very helpful. I changed the chip to 18F45K22 and build it. It compiled without errors. It says used rom 5742 bytes, but the hex file is only 86 bytes. So where did 5626bytes disappeared? It seems that the hex file size depends on mcu selected.

Perhaps I'll just order another mcu for this project. Is there any selector that I could just choose the same specs than 16F819 but with 7kb or more of memory? If I interpret the datas right eg. PIC16F1847 would be direct swap?
 

PIC16F1847 would be direct swap?

Yes, it is.

For 16F1847 it compiled without error(s). You can use FloatToAscii() with 16F1847.
 
Alright Gents... So I got some more chips with more oomph but unfortunately Pickit 2 was only able to program PIC16F1847 so only more memory than before. I did some streamlining the code and it compiles without errors. Still it doesn't work with all the features on. I'm not sure is it lack of ram or what memory does the chip use when storing those variables? Anyway, I commented all instructions that had to be left out for it to work. Those do work if I comment out something else so basically everything should work. Currently it does show G-values on both rows but only plain values. I've tried to add maximum value after the current value (that's commented out in code). Even if I uncomment that one extra Lcd_Out_Cp from the code, display doesn't update at all. Is it limited how many times you can call that procedure? How can I make this to work and what am I doing wrong?

Code:
#include "float2ascii.h"
// Lcd module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

#define CALIBRATED_0G_Z 368 //this is the analog value for the zero G point for Z
#define CALIBRATED_0G_X 349   //this is the analog value for the zero G point for X
#define CALIBRATED_SENSITIVITY 59.77//this number will convert 10bit analog values
                                 //into Gs
char XAxis[19];
char ZAxis[19];
char maxXAxis[19];
char maxZAxis[19];
char *txtx;
char *txtz;
char *MaxZ;
char *MaxX;


void MyDelay(int time)      // Delay routines
{
 switch (time)
 {
 case 1 : delay_us(10); break;
 case 2 : delay_ms(100); break;
 }
}

int ReadAxis (char channelbinary, unsigned char channel)    // Read Zaxis values from DE-ACCM3D
{
     signed int analogvalue=0;
     signed int temp=0;
     signed int Gvalue=0;
     long Gvaluelong=0;
     ADCON0 = channelbinary;     // setting the A/D module for AN2 or AN1
     analogvalue = ADC_Read(channel);  // Read from spesific channel
     MyDelay(10);
     analogvalue += ADC_Read(channel);//take an average of 2 readings to reduce noise
     analogvalue = analogvalue / 2;
         //convert analog value into G digits
         if (channel == 2) {
                        Gvalue=analogvalue-CALIBRATED_0G_Z;
                 }
                 if (channel == 1) {
                        Gvalue=analogvalue-CALIBRATED_0G_X;
                 }
         Gvaluelong=Gvalue*100;  // Multiply by 100 to get more resolution before dividing
         Gvalue=(int)Gvaluelong/CALIBRATED_SENSITIVITY;
         return Gvalue;
}


void main(){
     int XValues = 0;
     int ZValues = 0;
     float XValuesf = 0;
     float ZValuesf = 0;
     int i=0;
     float Zmax = 0;
     float Xmax = 0;
     OSCCON = 0b01111010;  // Set internal oscillator to 16mhz
     OSCSTAT = 0b00011001;
     OSCTUNE = 0b00011111;
     ADCON0 = 0b00001000;     // setting the A/D module
     ADCON1 = 0b10000011;        // Set VREF+ to fixed voltage, fosc/2, A/D right justified
     DACCON0.b7 = 0;          // DAC disabled
     SRCON0.b7 = 0;           // SR latch disabled
     CM1CON0.b7 = 0;          // Disable comparator 1
     CM2CON0.b7 = 0;          // Disable comparator 2
     TRISA  = 0b00000110;     //Set RA2 & RA1 as input, others are output
     TRISB  = 0b00000000;     // Set all RB as output
     ANSELA = 0b00000110;     // Set RA1 & RA2 as analog
     ANSELB = 0b00000000;     // Set all B ports as digital
     Lcd_Init();                        // Initialize Lcd
     Lcd_Cmd(_LCD_CLEAR);
     Lcd_Cmd(_LCD_CURSOR_OFF);

  while(1) {                         // Endless loop
         if (i == 1) {               // In one round update only other value
         XValues = ReadAxis(0b00000111,1);   // Read X axis
         XValuesf = (float)XValues;   // Typecast to float for division
         XValuesf = XValuesf/100;     // Divide to get to right decimal
         Float2Ascii(XValuesf,txtx,2);   // Put float value to char and 2 decimal
/*         if (XValuesf > Xmax) {     // Update maximum X axial G-force
            Xmax = XValuesf;
            Float2Ascii(Xmax, maxX,2);
            maxX = maxXAxis;
         } */
         XValuesf = 0;                   // Reset float to release memory. Without this it doesn't work
         XValues = 0;
         txtx = XAxis;           // Initialize pointer
         Lcd_Out(1,1,XAxis);   // Print X axis G-value to first line
         Lcd_out_cp("G ");     // Add G
//         Lcd_Out_cp(maxXaxis); // Print maximum registered X axis G force
         }
//------------Z axis--------------------------------------------------------------------------------------
         if (i == 2) {
         ZValues = ReadAxis(0b00001011,2);  // Read Z Axis
         ZValuesf = (float)ZValues;
         ZValuesf = ZValuesf/100;
         Float2Ascii(ZValuesf,txtz,2);
/*         if (ZValuesf > Zmax) {
            Zmax = ZValuesf;
            Float2Ascii(Zmax, maxZ,2);
            maxZ = maxZAxis;
         }     */
         ZValuesf = 0;
         ZValues = 0;
         txtz = ZAxis;
         Lcd_Out(2,1,ZAxis);  // Print Zaxis G-value to second line
//         Lcd_out_cp("G   ");
//         Lcd_Out_cp(maxZaxis); // Print maximum registered Z axis G force
         i = 0;
         }
         i++;

         MyDelay(2);
      }
 }
 

The Compiler is eliminating some variables which are used. I don't know why. So, set Optimization level to zero in Project>Edit Project...>General Output Settings... and then Compile the code. I hope this will solve the problem.
 
How I wish I could answer that it solved the problem, it didn't. It actually acts bit different now as I'm able to see light squares on top row instead of completely dead display. Anyhow, I had the chance to try this code with CCS pic compiler (of course convert compiler related things to match CCS). First it looked like it's gonna work as it show all the four values on two rows but they were not right. Then I realized that the int's were 8 bit which is too short for 10 bit adc result so I changed all necessary int to int16. Result was the same as with mikroC -> nothing on display. So my guestion is for all you experts that how can I make this to work? Will it work with PIC18, or do I need PIC24 or perhaps PIC32? Is this memory related issue or processor speed? I'm really desperate with this...
 

Disable ADC read instruction in code and assign a know fixed value instead and then debug the code step by step and see values of all variables. See what is causing the problem in mikroC debugger.
 
I tried to "synchronize" to the thread discussion, but I failed. I was expecting a solution using integer aithmetic, as stated in your initial post, but I see a lot of float operations and float variables in your latest code (in post #15). So in a brief, what are you presently trying to achieve? The original idea to use integers number with decimal fixed point scaling seems clear and easily to implement.
 

Try declaring like this for strings.


Code C - [expand]
1
2
3
4
char *txtx = "                ";
char *txtz = "                ";
char *MaxZ = "                ";
char *MaxX = "                ";



If you don't define like this the string will be always 0 length and float2ascii result will not be assigned to txtx, etc...

Please explain in detail what exactly you are trying to achieve.

- - - Updated - - -

Try this code.


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
139
140
141
#include "float2ascii.h"
 
// Lcd module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
 
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
 
#define CALIBRATED_0G_Z        368.00   //this is the analog value for the zero G point for Z
#define CALIBRATED_0G_X        349.00   //this is the analog value for the zero G point for X
#define CALIBRATED_SENSITIVITY  59.77   //this number will convert 10bit analog values
                                        //into Gs
char Axis[23];
char maxi[23];
 
double Zmax = 0.0;
double Xmax = 0.0;
double XValuesf = 0.0;
double ZValuesf = 0.0;
 
int i = 0.0;
 
void MyDelay(char time) {                // Delay routines
 
      switch(time) {
          case 1:
                delay_us(10);
                break;
          case 2:
                delay_ms(100);
                break;
      };
}
 
double ReadAxis (char channel) {    // Read Axis values from DE-ACCM3D
 
      double analogvalue = 0.0;
      double Gvalue = 0.0;
 
      analogvalue =  ADC_Read(channel);                       //ADC_Read(channel);  // Read from spesific channel
      MyDelay(1);
      analogvalue += ADC_Read(channel);                       //ADC_Read(channel);//take an average of 2 readings to reduce noise
      analogvalue /= 2.0;
                                                              //convert analog value into G digits
      if (channel == 1) {
             Gvalue = analogvalue - CALIBRATED_0G_X;
      }
      if (channel == 2) {
             Gvalue = analogvalue - CALIBRATED_0G_Z;
      }
      
      Gvalue = Gvalue * 100.0;                                  // Multiply by 100 to get more resolution before dividing
      Gvalue /= CALIBRATED_SENSITIVITY;
      return Gvalue;
}
 
 
void CopyStr(char *dest, char *src) {
 
       while(*src)
            *dest++ = *src++;
 
       *dest = '\0';
}
     
void main() {
 
      OSCCON = 0b01111010;     // Set internal oscillator to 16mhz
      OSCSTAT = 0b00011001;
      OSCTUNE = 0b00011111;
      
      ADCON1 = 0b10000011;        // Set VREF+ to fixed voltage, fosc/2, A/D right justified
      
      DACCON0.b7 = 0;          // DAC disabled
      
      SRCON0.b7 = 0;           // SR latch disabled
      
      CM1CON0.b7 = 0;          // Disable comparator 1
      CM2CON0.b7 = 0;          // Disable comparator 2
      
      TRISA  = 0b00000110;     //Set RA2 & RA1 as input, others are output
      TRISB  = 0b00000000;     // Set all RB as output
      ANSELA = 0b00000110;     // Set RA1 & RA2 as analog
      ANSELB = 0b00000000;     // Set all B ports as digital
      
      Lcd_Init();              // Initialize Lcd
      Lcd_Cmd(_LCD_CLEAR);
      Lcd_Cmd(_LCD_CURSOR_OFF);
 
      while(1) {                                  // Endless loop
      
            if(i == 1) {                          // In one round update only other value
                
                XValuesf = ReadAxis(1) / 100.0;   // Read X axis
                Float2Ascii(XValuesf, Axis, 2);   // Put float value to char and 2 decimal
                
                if(XValuesf > Xmax) {             // Update maximum X axial G-force
                      Xmax = XValuesf;
                      Float2Ascii(Xmax, maxi, 2);
                }
                
                XValuesf = 0;                     // Reset float to release memory. Without this it doesn't work
                Lcd_Out(1,1,Axis);               // Print X axis G-value to first line
                Lcd_out_cp("G ");                 // Add G
                Lcd_Out_cp(maxi);                 // Print maximum registered X axis G force
            }
            
            //------------Z axis--------------------------------------------------------------------------------------
            
            if(i == 2) {
            
                ZValuesf = ReadAxis(2) / 100.0;   // Read Z Axis
                Float2Ascii(ZValuesf, Axis, 2);
                
                if(ZValuesf > Zmax) {
                      Zmax = ZValuesf;
                      Float2Ascii(Zmax, maxi, 2);
                }
                
                ZValuesf = 0;
                Lcd_Out(2,1,Axis);               // Print Zaxis G-value to second line
                Lcd_out_cp("G ");
                Lcd_Out_cp(maxi);                // Print maximum registered Z axis G force
                
                i = 0;
            }
            
            i++;
 
            MyDelay(2);
      }
}

 
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…