Delaying once within a loop then not again

Ok.
We are trying to make a motor move when you get within a certain distance of it.
We have an ultrasonic range finder which triggers the motor and a switch to turn it on and off.

The current code works but we need to make it so that we can turn it on, then wait 20 seconds before the motion sensor IF statements take effect. I’d like to know the simplest way to use the delay once, then move on to the motion sensor detection without the loop returning to the delay.

# define ECHOPIN 3
# define TRIGPIN 2
const int MOTORPIN = 9;
const int BUTTONPIN = 4;

void setup()
{
Serial.begin(1200);
pinMode(BUTTONPIN, INPUT);
pinMode(ECHOPIN, INPUT);
pinMode(TRIGPIN, OUTPUT);
pinMode(LEDPIN, OUTPUT);
pinMode(MOTORPIN, OUTPUT);
}

void loop()
{

// ULTRASONIC BIT
//Start ranking-generating a trigger of 10 Microseconds burst

digitalWrite(TRIGPIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIGPIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGPIN, LOW);

//Distance calculation

float distance = pulseIn(ECHOPIN, HIGH);
distance= distance/58;
Serial.print(distance);
Serial.print(" cm");




//BUTTON BIT

int BUTTONState;
BUTTONState = digitalRead(BUTTONPIN);
 Serial.print("  Button: ");
  Serial.println(BUTTONState);



// THE CONDITIONAL BIT WE NEED HELP WITH!
//When button is pushed, wait 20 seconds, then turn motor


 if (BUTTONState == HIGH) { 
 
   delay(20000);
   
   if (distance < 100) {
      digitalWrite(MOTORPIN, HIGH); // turn the motor on (full speed)
      delay(3000);
      digitalWrite(MOTORPIN, LOW);
      delay(100000000);
    }

   if (distance > 100) {
      digitalWrite(MOTORPIN, LOW);
    }
    
}
    
    

 if (BUTTONState == LOW) {
  digitalWrite(MOTORPIN, LOW);
  }  

}

We also have a couple of minor issues which may be connected to one another?

  1. We wondered if there was a simpler way to trigger the motor for a short period, then turn it off
    instead of using delay(1000000000)

  2. Serial print stalls at the moment after we turn the button on.

If you want something to happen once then you need a variable to record its state - has it happened or not. For example

boolean firstButtonPress = true; // put this line before setup()

if (firstButtonPress) {
  delay(xxx);
  firstButtonPress = false;
}

You really should not use delay() for timing as nothing else can happen while the delay() is in progress. It is much better (essential, even) to use the technique in the Blink Without Delay example sketch and in the demo several things at a time.

...R

Great! Thanks :) I think I understand. Will give it a go in the circuit.

I also mentioned a couple of other problems but cleverly hid them at the bottom beneath the code... So if anyone has the inclination to answer, we'd also like to solve a couple of minor issues which may be connected to one another?

  1. We wondered if there was a simpler way to trigger the motor for a short period, then turn it off instead of using delay(1000000000)

  2. Serial print stalls at the moment after we turn the button on and we're not sure why...

Hi,

you want to look at blink without delay example. you want to avoid using delays because they will pause the arduino and prevent any response to any other actions while the delay is happening. For example if you want to have Motor A run for 30 seconds and right before it quits you want motor b to start up and run, you wouldn't be able to do that. or if you want the 2nd button press to turn off the motor it won't do anything till the delay has been completed.

sambushes: I also mentioned a couple of other problems but cleverly hid them at the bottom beneath the code...

And I hid the answer at the bottom of my earlier post :)

...R

Robin2: If you want something to happen once then you need a variable to record its state - has it happened or not. For example

boolean firstButtonPress = true; // put this line before setup()

if (firstButtonPress) {   delay(xxx);   firstButtonPress = false; }

The subtle features of C++ allow us to shorten this to a single declaration:

void loop() {
  static bool runOnce = (delay( 500 ), false);
}

You can put the declaration inside an if to "run once" on a condition.

 if (BUTTONState == HIGH) { 

   static bool runOnce = (delay( 20000 ), false);
}

However, like you say, delay should be put aside and proper timing constructs used.

pYro_65: The subtle features of C++ allow us to shorten this to a single declaration:

void loop() {
  static bool runOnce = (delay( 500 ), false);
}

For me, this would save a small amount of typing at the expense of a huge loss in clarity - probably because I don't use C/C++ often enough to be familiar with its idioms. Truthfully I only use C/C++ when I have no choice.

...R