How do I speed up my program??

I finally got my water meter/alarm sketch working! I have only been doing Arduino for a few weeks. (Thanks to other users who gave me advice!).

It pretty much is doing what I want it to, except, that it is somewhat slow to read my flow meter, which it is doing with the “get_frequency” function in the program. There is a lag of a few seconds before the LED goes on and the water starts getting measured…so it apparently is losing some of the water measurement for short turn-ons.

I assume this is because the program is executing calls and doing calculations. I put in a “goto” to skip sections of code under certain conditions, but the lag is still there.

This reading of the flow meter was faster earlier in the sketch development, but that version was not correctly calculating the water use (GPM).

Any advice?? Thanks for your help!

Peter

water_timer1_25_2016.ino (6.5 KB)

I assume this is because the program is executing calls and doing calculations. I put in a "goto" to skip sections of code under certain conditions, but the lag is still there.

You assume wrong. The type and amount of calculation required in this case is trivial - a few microseconds at most.

NEVER NEVER NEVER use goto. As you have used it I will not look at your code.

Mark

I had a "while" function for the timer loop, but it seems like I got better performance by using "goto". I also had to use nested "whiles", which seemed cumbersome, and possibly slow.

I know what you programmers think about "goto", but what works, works.

I have done quite a few permutations of the control structures, and the loop with "goto" and conditions to exit seemed the fastest.

I'm not quite so precious about goto (just don't use goto - gotos are bad, m'kay?)

How to speed up the code. Hmmm, lemme see.

 delay(2000);
Serial.begin(9600);

The delays have already been mentioned. To find out where the program is spending its time, ensure you have one Serial.print before each delay, in each function and in each loop. You are not resetting the value of "old_buttonstate" so subsequent presses of "Button" will be immediately acted on without a 10 second wait. Instead of doing a 10 second delay to check if a button has been held down, you could do something like this which allows the loop to continue doing other things:

unsigned long buttonExpiryMillis = 0 ;
int button_state = LOW;

void loop() {

...
...
if ( digitalRead(Button) == HIGH && Button_state == LOW) {
     button_state = HIGH ;
     buttonExpiryMillis = millis() + 10000 ;  
   
     // Action to be performed as soon as button depressed.
}

if ( digitalRead(Button) == LOW && Button_state == HIGH ) {
    // optional : cancel button press, if released before 10 seconds.
     button_state = LOW ;
     buttonExpiryMillis = 0; 
}

if ( Button_state == HIGH && millis() >= buttonExpiryMillis ) {
   
  // action here performed 10 seconds after button press

button_state = LOW  ;

}
....
....


}

Thanks for the suggestion regarding checking the time for a button press, however, the program would only be delayed if the button were being held down. The problem is that is seems slow in the loop were it is reading the frequency of the flow meter and calculating the water useage when the frequency is greater than the lower limit.

I found some code elsewhere that did this using interrupts, but it did not work. I wonder if that would be faster than the pulseIn() function?

Peter

It does then look like your problem is the behaviour of pulseIn() and an interrupt would be be a better approach.

I guess from your code that your measuring device delivers pulses on pin 12 and you are expecting first a HIGH, then a LOW. Once you have the time of a HIGH / LOW pair, you calculate the frequency.

I'd try the following: (1) before you give up with pulseIn, set a timeout on it (see See https://www.arduino.cc/en/Reference/PulseIn ) and do a Serial.print whenever the timeout is reached ie pulseIn() returns 0 so you see how it behaves with different timeout values. (2) if you can't get any further with that, create a minimal sketch which reads your measuring device, but using interrupts and experiment with that. If it is say an Uno, move the measuring device to pin 2 or pin 3 so you can test interrupts. The interrupt service routine should set your global variable 'frequency' which you can test as before in your sketch. It would be something like this:

volatile float frequency;
unsigned long oldMillis  = 0; 

void setup() {
attachInterrupt(digitalPinToInterrupt(2), ISR_frq, RISING);   // meter connected to pin 2
}

void ISR_frq() {
// Interrupt Service Routine called by rising pulse on pin 2
unsigned long pulseLength = millis() - oldMillis ;
frequency = 1 / (1000 * pulseLength) ;  // your formula here to get the required units.
Serial.println ( frequency) ;  // only for testing. ISR must be fast.
oldMillis = millis() ;
}

void loop() { }