Pages: [1] 2   Go Down
Author Topic: How to avoid floating point math  (Read 1935 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 54
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have now 2 weeks solid in programming a new project, and as a newbie I don't mind figuring out my screwups on my own, but now I have what appears to be stack overflow issues due to the overhead of multiple timing interrupts and sensor pulse input interrupts overloading the processor....so my question is....I need to eliminate the floating point math I threw in....I can't remember the tips I read somewhere about how to avoid floating point where workarounds can be done....fractions in my case will kill the project, what is one to do...

Are you to multiply the parts by say, 100 or 1,000 before multiplying or dividing, to move the fractional part up, then afterwards divide it back down, thus preserving the initial decimal fractional part?  Is there more to it?
Thanks as always...
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 547
Posts: 45982
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
what is one to do
When posting in the Programming forum it's generally advisable to POST SOME CODE!
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 121
Posts: 8432
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the easiest way is to work with large integer numbers with small granularity.

For example you need volts to 3 decimal places. Do all the work in mV and drop a decimal point in the right place when displaying data to a human.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Jr. Member
**
Karma: 0
Posts: 54
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


    The whole code is too large but here are the 3 interrupt routines and associated calcs needing revision...basically I am calculating flow rate and its average going forward

Code:
#include <LiquidCrystal.h>
#include <Time.h> //added to do one second   timer
#include <TimeAlarms.h> //added to do one second   timer
#include <EEPROM.h>




void setup() {  
needed for 1 sec timer
  
  Alarm.timerRepeat(5,Repeats);    // timer for every (5) seconds  calls Repeats subroutine- upped to 5 due to low counts in a few seconds  
  Alarm.timerRepeat(3,Toggle);    //switch displays while operating
  Alarm.timerRepeat(60,ElapsedTime);    //increment operating time by one minute while operating
  
  
  state=0;
  lcd.clear();
  lcd.begin(16, 2); //rows x cols
  lcd.setCursor(0,0);
  lcd.print("Fuel Flow Gauge");
  
  

  
  
  Serial.begin(9600);
 
  k_factor = eepromReadInt(9);  
  delay(5);
 
  lcd.setCursor(0,1);
   lcd.print("K-factor is ");
  lcd.print(k_factor);  
  Serial.print("K-factor is ");
  Serial.println(k_factor);
  delay(1000);
 
  
    hobbs_hours = eepromReadInt(6);  //reads 2 bytes of integer hours
    delay(5);
    hobbs_minutes = EEPROM.read(8);   //reads stored minutes..
    delay(5);
       lcd.clear();
       lcd.print("Hobbs=   ");
       lcd.print(hobbs_hours,2);
       lcd.print(":");
       lcd.print(hobbs_minutes,2);          
                  Serial.print("Hobbs stored time is ");
                  Serial.print(hobbs_hours);
                   Serial.print(":");
                   Serial.println(hobbs_minutes);
 
for (int thisReading = 0; thisReading < numReadings; thisReading++)
   readings[thisReading] = 0;  
  delay(1000);
  pinMode(hallsensor, INPUT); //initializes DIGITAL pin 2 as an input
  attachInterrupt(0, IncrementFlowPulse, RISING); //and the interrupt is attached
  
  sei(); //go ahead and start counting
}



void IncrementFlowPulse ()    
{
        
   total_pulses++ ;  
      Count++;
      tenth_gallon++;  
    running=1;
  }  


 
void Repeats(){
 
  
    
     Calc = ((float)Count* ((float)720.0 / (float)k_factor)); //(Counts in 5 seconds/ number counts per gallon, converted from seconds to hours
                          //using a large value we can select any k-factor - use counts per gallon - perfect
                          // Calc is the gallons per hour.
                          
     if (!flag){  //reset flag so running total flag is run only once
    flag=1;}      //this is used for averaging routine for average flow rate

  if (Count>0){
     stopped_flag++; //add 5 seconds to running time length
    
     }
    if (stopped_flag>5){  
                            
       stopped_flag=5;
                      
          }
    
  if (Count==0){
     stopped_flag--;
  
      }
      if (stopped_flag<=0){
       stopped_flag=0;  // no longer running
         }
        else { running=1;  
         }
        
  Count=0;  //reset for next interrupt
  
                
    if ((stopped_flag<=0) && (running) ){
  
    state=10;  
    return;
    }
    
  
    
    
 }

void Toggle(){
  
  if (state==0){
    state=1;
    return;
  }
  if (state==1){
    state=2;
    return;
  }
    if (state==2){
    state=0;
    return;
  }
}  

void ElapsedTime(){
  if ((stopped_flag>0) && (running)){    
     Elapsed_min++;    
    }
   if (Elapsed_min>59){
   Elapsed_min=0;
   Elapsed_hour++;
   return; }
  }
 

void loop ()  
{      
   Alarm.delay(1);


  if (flag){  
    
    
      total= total - readings[index];        
       
      readings[index] = Calc;
    
      total= total + readings[index];      
    
      index++;                    

  
      if (index >= numReadings)              
  
        index = 0;                          

    
 
      average = total / (float)numReadings;        
    
      delay(1);      
  }
  
                          
  if ((tenth_gallon) >=(k_factor/10)){  
      decrement_fuel_level();  
                        
          tenth_gallon=0;    // reset it fro another count
      }
        
     switch (state) {  
     case (0):      
        state0();    
        break;
      case (1):
        state1();  
        break;
      case (2):
        state2();  
        break;
    case (6):
        state6();  
        break;
    case (7):
        state7();  
        break;
     case (8):
        state8();  
        break;
     case (9):
        state9();  
        break;
     case (10):  
        state10();  
        break;
    default:  
        break;
           }  
}
         // end of loop  
 
void state0()  
  {
    lcd.clear();
    lcd.noBlink();  
    lcd.setCursor(0,0);
    lcd.leftToRight();
    lcd.print (Calc, 2);
    lcd.leftToRight();
    lcd.setCursor(5,0);
    lcd.print ("gal/hr inst");
      if (total_pulses ==0){
        average=0;
    }
    
    lcd.setCursor(5,1);
    lcd.print ("gal/hr avg");
    lcd.setCursor(0,1);
    lcd.leftToRight();
    lcd.print (average, 2);
    
    

  check_keypad();  //see if state has changed via select button
   if (key != -1) {  //only change value once, don't reset it
       a=key;  
   }
    delay(60);  
   switch (a) {
    case 4:
        state=6;  //go to first menu ...
        break;
    default:  //else do nothing
        break;
        }      

  
    
}
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 176
Posts: 12285
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


void setup() { 
  ...
  sei(); // <-- THIS SERVES NO USEFUL PURPOSE.  REMOVE IT.
  ...
}
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 547
Posts: 45982
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
(float)720.0
Why are you casting a float to a float?

Code:
     if (!flag){  //reset flag so running total flag is run only once
    flag=1;}      //this is used for averaging routine for average flow rate
Make up your mind. The variable flag is either a boolean or it isn't. If it is, use true or false when assigning it a value. If is isn't, don't treat it like one in an if test.

Code:
  if (Count>0){
     stopped_flag++; //add 5 seconds to running time length
     
     }
How does incrementing stopped_flag add 5 seconds to running time length?

Code:
  if (Count==0){
     stopped_flag--;
   
      }
      if (stopped_flag<=0){
       stopped_flag=0;  // no longer running
         }
        else { running=1; 
         }
Has anyone ever told you that your indenting is atrocious? Well, now they have. The Tools + Auto Format menu item sorely needs to be executed.

Code:
void Toggle(){
 
  if (state==0){
    state=1;
    return;
  }
  if (state==1){
    state=2;
    return;
  }
    if (state==2){
    state=0;
    return;
  }
would certainly be a lot shorter as
Code:
void Toggle()
{
  state++;
  if(state == 2)
    state=0;
}

Code:
void loop ()   
{     
   Alarm.delay(1);


  if (flag){ 
     
     
      total= total - readings[index];       
       
      readings[index] = Calc;
     
      total= total + readings[index];     
   
      index++;                   

 
      if (index >= numReadings)             
   
        index = 0;                         

     
 
      average = total / (float)numReadings;       
     
      delay(1);       
  }
 
                           
  if ((tenth_gallon) >=(k_factor/10)){ 
      decrement_fuel_level(); 
                         
          tenth_gallon=0;    // reset it fro another count
      }
       
     switch (state) { 
     case (0):       
        state0();   
        break;
      case (1):
        state1();   
        break;
      case (2):
        state2();   

Blank lines galore, and then suddenly everything's jammed together. Is there a reason for that?

Personally, what I see here is a lot of slow writing to a LCD, and yet you want to do away with a few floating point operations in the hopes of speeding up the program. I think you're looking in the wrong place for bottlenecks to deal with.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 54
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the input, but please keep the insults to a minimum. People come here to learn and get tips and help not passive aggressive putdowns.  The formatting got trashed when I pasted it in here...my original coding is 1300 lines and is indented reasonably well, though maybe not to your standards.  The pasted mess above looks formatted completely different.  Though I have of course a lot to learn, and appreciate the feedback.    I will pick up the fixes above and keep truckin'.  Though I think what is happening, is when the counts get high due to high flow,  stack overflow occurs, and the thing crashes.  So I suspect there are still problems....

regarding float of a float, I have been trying all kinds of things to get math to work, didn't catch that the number wasn't converted back to integer.. newbies do that... :-)
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 176
Posts: 12285
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Are you to multiply the parts by say, 100 or 1,000 before multiplying or dividing, to move the fractional part up, then afterwards divide it back down, thus preserving the initial decimal fractional part?  Is there more to it?

Roughly, sort of.  Powers-of-2 are also common.  There are minor advantages and disadvantages to each.

Quote
but now I have what appears to be stack overflow issues

Unless you are trying to run your program on an ATtiny13 processor I don't see it.

Quote
due to the overhead of multiple timing interrupts and sensor pulse input interrupts overloading the processor....

Huh?


Take a step back.  Take a deep breath.  Describe the symptom(s) rather than what you believe to be the cause.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 54
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Auto format. That's pretty cool.  Is there a users' manual for this simple IDE somewhere out there? i haven't seen one.  Lots to learn.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 54
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The reason I suspect stack overflow....there are plenty of places in the code for me to learn and fix things, but it basically works.
When I blow into the flow sensor for testing, I get real world reasonable flow rates, (1-12 gallon per hour) and see the fuel level indicator decrement properly, but if I blow a bit harder, which would simulate when an engine is first started up and fills the fuel line, the rate will jump really high....when I do that, I get trashed values, even the fuel quantity value, which is incremented downward linearly with flow, goes to some unknown silly value, I think it is 655 replacing the unit and tenths digits. Which is why I think the interrupts can't keep up...   
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    case (0):       
    state0();   
    break;

The brackets around the zero are not necessary, and are confusing.



Quote
now I have what appears to be stack overflow issues due to the overhead of multiple timing interrupts and sensor pulse input interrupts overloading the processor

I only see one interrupt:

Code:
  attachInterrupt(0, IncrementFlowPulse, RISING); //and the interrupt is attached

And it doesn't do much:

Code:
void IncrementFlowPulse ()     
{
  total_pulses++ ; 
  Count++;
  tenth_gallon++;   
  running=1;



Although without seeing the data types it is hard to be sure.

Quote
I need to eliminate the floating point math I threw in ...

This is guesswork, really. The code you've shown in an interrupt would hardly slow it down that much.

I'm not sure what you mean by "stack overflow issues".

Possibly you are simply writing off the end of an array. Hard to say without seeing all the code.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 54
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

3 interrupts...correct, the first and third are pretty simple. The middle one though, has floating point calcs

Code:
void IncrementFlowPulse ()     //This is the function that the flow sensor interrupt on pin 2 calls to add to the count and total count
{
  //This function measures the rising and falling edge of the hall effect sensors signal
  total_pulses++ ;  //change to this variable so running tally is incremented in the background...
  Count++;
  tenth_gallon++;   //be careful here, fuel_tenth and plural exist. this is used to decrement by tenth gallon once it is high enough
  running=1;
}  

// The setup()  runs once, when the sketch starts
// the FOLLOWING loop() method runs over and over again,
// as long as the Arduino has power
//****************************************************************************************    

void Repeats(){ //interrupt timer1 repeats every second-changed to 5 seconds...

  //here is the math...we sample every 5 seconds.  9200 counts per gallon. FIXED-use float cast to convert integers to float before calculating

  Calc = ((float)Count* ((float)720.0 / (float)k_factor)); //(Counts in 5 seconds/ number counts per gallon, converted from seconds to hours
  //using a large value we can select any k-factor - use counts per gallon - perfect
  // Calc is the gallons per hour.

  if (!flag){  //reset flag so running total flag is run only once
    flag=1;
  }      //this is used for averaging routine for average flow rate

  if (Count>0){
    stopped_flag++; //add 5 seconds to running time length

  }
  if (stopped_flag>5){  //this is to delay the time till we stop and wait....
    //30 seconds or so...it decrements with no flow
    stopped_flag=5; //add 5 seconds to length of time running, up to 30 seconds
    //-each unit of increase = 5 seconds of stoppage
  }

  if (Count==0){  //decrement once per 5 second with zero flow...
    stopped_flag--;

  }
  if (stopped_flag<=0){
    stopped_flag=0;  // no longer running
  }
  else {
    running=1;  //added this to ensure it stays running with flow
  }

  Count=0;  //reset for next interrupt

  //For some reason, when we start back up from stop, we re-enter the save routine.
  if ((stopped_flag<=0) && (running) ){  //we were running, then stopped

    state=10;  //keeps returning to state 10, stop and save, and looping again
    return;
  }




}
//****************************************************************************************

void Toggle(){ //this is an interrupt to switch screens every few seconds

  if (state==0){
    state=1;
    return;
  }
  if (state==1){
    state=2;
    return;
  }
  if (state==2){
    state=0;
    return;
  }
}  
« Last Edit: November 30, 2012, 01:57:32 am by cornwallav8r » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code tags? Makes it easier to read.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 54
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I sorta wish I had dived into the forum last week, one can learn a lot in a big hurry with such awesome quick feedback.
I just don't want to be any more hassle than one has to be, don't want to be that noob who thinks somebody needs to implant knowledge in his brain without indulging first and learning some the hard way...
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 54
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ahem...what's a code tag?
Ok got it. Revised. Thanks
« Last Edit: November 30, 2012, 01:58:46 am by cornwallav8r » Logged

Pages: [1] 2   Go Up
Jump to: