How to avoid floating point math

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...

what is one to do

When posting in the Programming forum it's generally advisable to POST SOME CODE!

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

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

#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;
        }      

  
    
}

void setup() {

sei(); // ← THIS SERVES NO USEFUL PURPOSE. REMOVE IT.

}

(float)720.0

Why are you casting a float to a float?

     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.

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

How does incrementing stopped_flag add 5 seconds to running time length?

  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.

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

void Toggle()
{ 
  state++;
  if(state == 2)
    state=0;
}
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.

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… :slight_smile:

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.

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.

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.

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.

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...

    case (0):       
    state0();    
    break;

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


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:

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

And it doesn't do much:

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

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

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.

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

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;
  }
}

Code tags? Makes it easier to read.

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...

ahem...what's a code tag? Ok got it. Revised. Thanks

As long as you are trying, we’ll be pleased to help.

I don’t see interrupts being the issue here. You have two ISRs that you say are called every couple of seconds, so they are hardly the issue.

Then you have one which does a couple of adds. How many times a second do you expect it to be called? Let’s put a metric on this.

And what data types are total_pulses, Count, tenth_gallon and running?

cornwallav8r:
ahem…what’s a code tag?

OK, here’s some boilerplate. Read it, though:

Read this before posting a programming question

Please edit your post, select the code, and put it between [code][/code] tags.

You can do that by hitting the # button above the posting area.

[quote author=Nick Gammon link=topic=134912.msg1014733#msg1014733 date=1354258185] As long as you are trying, we'll be pleased to help.

I don't see interrupts being the issue here. You have two ISRs that you say are called every couple of seconds, so they are hardly the issue.

Then you have one which does a couple of adds. How many times a second do you expect it to be called? Let's put a metric on this.

And what data types are total_pulses, Count, tenth_gallon and running? [/quote]

Very good questions those...

I expect no more than say, 100 pulses in a second. total_pulses-unsigned long, Count-unsigned int, tenth_gallon- unsigned int and running-boolean.

The calculating interrupt is done every 5 seconds, so I guess that can't be such an overhead issue, right?

Well out of interest, I set up a test. This code:

  total_pulses++ ;  
  Count++;
  tenth_gallon++;   
  running=1;

Takes about 2.8 uS to execute. So if you do 100 of them you have taken 280 microseconds. Add in the overhead of 100 interrupts, say 5 uS each, and that is another 500 uS. So in total 780 uS.

You have not even used up 1/1000 of the time you have in a second. Time to look elsewhere.

Besides, none of those are floating point variables. I thought you were worried about that?

No actually, it is this interrupt and its floating point math that I jumped to conclusions about…thoug I may simply have more dumb programming mistakes to fix instead.

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 / (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=true;
  }      //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=true;  //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;
  }