Delay or Millis() in a void function. Can't figure it out!

Hello - trying to do what I thought would be a simple program. I have several void functions that I call when a momentary push button is pushed. In two of the void functions I need to have some sort of time delay while a relay is open, and then at the end of a duration of time closes. At the end I want it then to flash an LED and wait for a button to be pushed (Same buttons pushed as in the Void Loop) and also be on the look out for an E-Stop or Float Valve Sensor. (Both E-stop and Float Valve need to be monitored for signals during the time duration above.

From my understanding (and much frustration) a delay() can't be used in a void function. We've been trying with millis() but also no luck at all.

Here is the full code below. I have commented out the lines that cause issues. I have it uploaded now and the unit works minus the time delays. But at least it will function. It's just not "automated".

Any insights (and explanations so I can learn) would be great appreciated! I've spent a lot of time watching videos and reading online over the past weeks, and I never like posting on a forum unless I've exhausted all other means of trying to figure it out.

Thanks in advance


unsigned long time_1 = 0;
const int delay1 = 5000;  // 4.25 minutes // SET TO 5000 FOR TESTING
unsigned long time_2 = 0;
const int delay2 = 5000;  // 30 s // SET TO 5000 FOR TESTING

int Buttonflag3;
int Buttonflag4;
int Buttonflag1;
int sesnsorflag1;


const int Button1_LED = 25;
const int Button2_LED = 26;
const int Button3_LED = 27;

const int Button1_Normal_On = 10; // Momentary Pushbutton
const int Button2_Drain_Tank = 11; // Momentary Pushbutton
const int Button3_Rinse_Tank = 12; // Momentary Pushbutton
const int Button4_E_Stop = 53; // E-Stop Button

const int Float_Valve_1 = 22; // Float Valve Digital Input
const int Solenoid1_Diaphragm = 2; // Relay 1
const int Solenoid2_Air_Drill = 3; // Relay 2 
const int Solenoid3_Rinse_Water = 4; // Relay 3 
const int Solenoid4_Water_To_Tumblers = 5; // Relay 4
const int Audible_Alarm = 7; // Relay
const int Relay_120v_Main_Water_Pump = 9; // Relay 120V 8


// NORMAL OPERATION - BUTTON 1 - "RUN CYCLE"
void Button_1_Pressed() {
  digitalWrite(Button1_LED, HIGH); // Button 1 LED ON
  digitalWrite(Button2_LED, LOW); // Button 2 LED OFF
  digitalWrite(Button3_LED, LOW); // Button 2 LED OFF
  
  digitalWrite(Relay_120v_Main_Water_Pump, LOW); // ON
  digitalWrite(Solenoid1_Diaphragm, LOW); // ON
  digitalWrite(Solenoid2_Air_Drill, HIGH); // OFF  
  digitalWrite(Solenoid3_Rinse_Water, HIGH); // OFF
  digitalWrite(Solenoid4_Water_To_Tumblers, LOW); // ON
}

// MIX + DRAIN TANK CYCLE - BUTTON 2 "MIX"
void Button_2_Pressed() {
  digitalWrite(Button1_LED, LOW); // Button 1 LED OFF
  digitalWrite(Button2_LED, HIGH); // Button 2 LED ON
  digitalWrite(Button3_LED, LOW); // Button 2 LED OFF
  
  digitalWrite(Relay_120v_Main_Water_Pump, HIGH);  // OFF
  digitalWrite(Solenoid1_Diaphragm, HIGH); // OFF
  digitalWrite(Solenoid2_Air_Drill, LOW); // ON - STIR CYCLE FOR DELAY TIME (4.25 mins)
  digitalWrite(Solenoid3_Rinse_Water, HIGH); // OFF
  digitalWrite(Solenoid4_Water_To_Tumblers, HIGH); // OFF


 
// int  a=1;
//if ((millis() - time_1) >= delay1 && sesnsorflag1==0 && a==1 || Buttonflag4==0){
//  digitalWrite(Solenoid2_Air_Drill, LOW); // ON
// a=0;
//}


// *** Here the program needs to run for 4.25 Minutes (so Solenoid2_Air_Drill is LOW / aka ON.)  
// *** After 4.25 minutes it needs to turn off using the code line below
// *** During this 4.25 minutes the program should be checking for E-Stop or FloatValve_1 Sensor High and going to appropriate function
 /// this line added into millis function
 //    digitalWrite(Solenoid2_Air_Drill, HIGH); // TURN MIXER OFF

///

//while (Buttonflag3==0 && sesnsorflag1==1 || Buttonflag4==0){
  
//  digitalWrite(Button2_LED,0);
//  delay(100);
//  digitalWrite(Button2_LED,1);
//  delay(100);
//  }



  
//^^^^^^^^ *** Here the program should continously blink Button2_LED until Button3_Rinse_Tank is pressed and then it goes to function Button_3_Pressed
// *** Should also be checking for E-Stop or FloatValve_1 Sensor High and going to appropriate function

  
}

// RINSE TANK - BUTTON 3
void Button_3_Pressed() {
  digitalWrite(Button1_LED, LOW); // Button 1 LED OF
  digitalWrite(Button2_LED, LOW); // Button 2 LED OFF
  digitalWrite(Button3_LED, HIGH); // Button 3 LED ON

  digitalWrite(Relay_120v_Main_Water_Pump, LOW); // ON
  digitalWrite(Solenoid1_Diaphragm, HIGH); // OFF
  digitalWrite(Solenoid2_Air_Drill, HIGH); // OFF 
  digitalWrite(Solenoid3_Rinse_Water, LOW); // ON
  digitalWrite(Solenoid4_Water_To_Tumblers, HIGH); // OFF
  digitalWrite(Audible_Alarm, HIGH); // OFF

// *** Here the program needs to run for 30 SECONDS (so Solenoid3_Rinse_Water is LOW / aka ON.)  
// After 30 seconds it needs to turn off using the code line below
// During this 30 seconds the program should be checking for E-Stop or FloatValve_1 Sensor High and going to appropriate function 


//int b=1;
//if (((millis() - time_2) >= delay2 )&& sesnsorflag1==1 && b==1 || Buttonflag4==0){
//   digitalWrite(Solenoid3_Rinse_Water, LOW); // ON
//  digitalWrite(Relay_120v_Main_Water_Pump, LOW); // ON
// b=0;
//}

//  digitalWrite(Solenoid3_Rinse_Water, HIGH); // OFF
//  digitalWrite(Relay_120v_Main_Water_Pump, HIGH); // OFF
//  digitalWrite(Button3_LED,0);

  

// *** Here the program should continously blink Button3_LED until Button1Normal_On is pressed and then it goes to function Button_3_Pressed
// *** Should also be checking for E-Stop or FloatValve_1 Sensor High and going to appropriate function
//while (Buttonflag0==1 && sesnsorflag1==1 || Buttonflag==0){
  
//  digitalWrite(Button3_LED,0);
//  delay(100);
//  digitalWrite(Button3_LED,1);
//  delay(100);
//  }

 
}



// E-STOP - ALL OFF 
void Button_4_E_Stop() {
  digitalWrite(Button1_LED, LOW); // Button 1 LED OFF
  digitalWrite(Button2_LED, LOW); // Button 2 LED OFF
  digitalWrite(Button3_LED, LOW); // Button 2 LED OFF
  
  digitalWrite(Relay_120v_Main_Water_Pump, HIGH); // OFF
  digitalWrite(Solenoid1_Diaphragm, HIGH); // OFF
  digitalWrite(Solenoid2_Air_Drill, HIGH); // OFF
  digitalWrite(Solenoid3_Rinse_Water, HIGH); // OFF
  digitalWrite(Solenoid4_Water_To_Tumblers, HIGH); // OFF
  digitalWrite(Audible_Alarm, HIGH); // RESET ALARM TO OFF
}

// HIGH WATER ALARM - Stops all and turns audible alarm on
void Float_Valve_1_HIGH() {
  digitalWrite(Button1_LED, LOW); // Button 1 LED OFF
  digitalWrite(Button2_LED, LOW); // Button 2 LED OFF
  digitalWrite(Button3_LED, LOW); // Button 2 LED OFF
  
  digitalWrite(Relay_120v_Main_Water_Pump, HIGH); // OFF
  digitalWrite(Solenoid1_Diaphragm, HIGH); // OFF
  digitalWrite(Solenoid2_Air_Drill, HIGH); // OFF
  digitalWrite(Solenoid3_Rinse_Water, HIGH); // OFF
  digitalWrite(Solenoid4_Water_To_Tumblers, HIGH); // OFF
  digitalWrite(Audible_Alarm, LOW); // ON
}


void setup() {

  pinMode(Button1_LED, OUTPUT);
  pinMode(Button2_LED, OUTPUT);
  pinMode(Button3_LED, OUTPUT);
  
  pinMode(Button1_Normal_On, INPUT_PULLUP);
  pinMode(Button2_Drain_Tank, INPUT_PULLUP);
  pinMode(Button3_Rinse_Tank, INPUT_PULLUP);
  pinMode(Button4_E_Stop, INPUT_PULLUP);
  
  pinMode(Float_Valve_1, INPUT_PULLUP);

  pinMode(Relay_120v_Main_Water_Pump, OUTPUT);
  pinMode(Solenoid1_Diaphragm, OUTPUT);
  pinMode(Solenoid2_Air_Drill, OUTPUT);
  pinMode(Solenoid3_Rinse_Water, OUTPUT);
  pinMode(Solenoid4_Water_To_Tumblers, OUTPUT);
  pinMode(Audible_Alarm, OUTPUT);
  
  digitalWrite(Relay_120v_Main_Water_Pump, HIGH);
  digitalWrite(Solenoid1_Diaphragm, HIGH);
  digitalWrite(Solenoid2_Air_Drill, HIGH);
  digitalWrite(Solenoid3_Rinse_Water, HIGH);
  digitalWrite(Solenoid4_Water_To_Tumblers, HIGH);
  digitalWrite(Audible_Alarm, HIGH);


}

void loop() {

int Button1 = digitalRead(Button1_Normal_On);


if (Button1==1){
  
   Buttonflag1=1 ; }
else if (Button1==0){
  
   Buttonflag1=0;  }



  

int Button2 = digitalRead(Button2_Drain_Tank);
int Button3 = digitalRead(Button3_Rinse_Tank);
if (Button3==1){Buttonflag3=1 ; }
else if (Button3==0){  Buttonflag3=0;  }


int Button4 = digitalRead(Button4_E_Stop);
if (Button4==1){
  
   Buttonflag4=1 ; }
else if (Button4==0){
  
   Buttonflag4=0;  }

int Sensor1 = digitalRead(Float_Valve_1);

if (Sensor1==1){
  
   sesnsorflag1=1 ; }
else if (Sensor1==0){
  
   sesnsorflag1=0;  }
//....

//
  ////



if (Button1 == LOW) {
  Button_1_Pressed();
}
if (Button2 == LOW) {
  Button_2_Pressed();
}
if (Button3 == LOW) {
  Button_3_Pressed();
}
if (Button4 == LOW) { 
  Button_4_E_Stop();
}
if (Sensor1 == HIGH) {
  Float_Valve_1_HIGH();
}

}

Let’s take this one step at a time.

Let’s do 1 (one) example pair.

Let’s say you have 1 LED and 1 switch.

What might be something you want to happen with these 2 components ?

Push the switch.
LED starts flashing until you push the switch again.

Can you follow everything that is being done here ?


// Name.ino

// Web Link

//********************************************^************************************************
// Version    YY/MM/DD    Description
// 1.00       YY/MM/DD    Running sketch
//
//



//********************************************^************************************************
#define CLOSED                        LOW
#define OPENED                        HIGH

#define PUSHED                        LOW
#define RELEASED                      HIGH

#define LEDon                         HIGH
#define LEDoff                        LOW

#define RELAYon                       LOW
#define RELAYoff                      HIGH

#define RUNNING                       true
#define notRUNNING                    false

#define ENABLED                       true
#define DISABLED                      false

//********************************************^************************************************
const byte buttonPin                = 2;      // +5V---[50k Pullup]---[Input Pin]---[Switch]---GND
const byte flashingLED              = 3;      // [Pin3]---[220R]---[A->|-K]---GND
const byte heartbeatLED             = 13;     // [Pin13]---[220R]---[A->|-K]---GND

byte lastButtonPinState;

byte flashingFlag                   = DISABLED;

//****************************
//timing stuff
unsigned long heartbeatTime;
unsigned long switchTime;
unsigned long flashingLedTime;


//                                       s e t u p ( )
//********************************************^************************************************
void setup()
{
  Serial.begin(9600);

  pinMode(buttonPin, INPUT_PULLUP);  // +5V---[50k Pullup]---[Input Pin]---[Switch]---GND

  pinMode(flashingLED, OUTPUT);
  pinMode(heartbeatLED, OUTPUT);

}  //END of   setup()


//                                        l o o p ( )
//********************************************^************************************************
void loop()
{
  //*************************************                     heartbeat T I M E R
  //to see if the sketch has blocking code,
  //toggle the heartbeat LED (every 1000ms)
  if (millis() - heartbeatTime >= 1000ul)
  {
    //restart the TIMER
    heartbeatTime = millis();

    //toggle the LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //*************************************                     switch T I M E R
  //is it time to check the switches ? (every 50ms)
  if (millis() - switchTime >= 50ul)
  {
    //restart the TIMER
    switchTime = millis();

    //go and check the switches
    checkSwitches();
  }

  //*************************************                     flashingLED T I M E R
  //if the flashingLED is allowed to flash,
  //is it time to toggle the LED ?
  if (flashingFlag == ENABLED && millis() - flashingLedTime >= 200ul)
  {
    //restart the TIMER
    flashingLedTime = millis();

    //toggle the LED
    digitalWrite(flashingLED, !digitalRead(flashingLED));
  }

  //*********************************
  //other non blocking code goes here
  //*********************************

} //END of   loop()


//                              c h e c k S w i t c h e s ( )
//********************************************^************************************************
void checkSwitches()
{
  byte currentState;
  
  //*************************************                     b u t t o n P i n
  //buttonPin code
  currentState = digitalRead(buttonPin);

  //*****************************
  //was there a change in state ?
  if (lastButtonPinState != currentState)
  {
    //update to the new state
    lastButtonPinState = currentState;

    //*************
    //was the switch closed ?
    if (currentState == CLOSED)
    {
      //toggle the flashingFlag
      flashingFlag = !flashingFlag;

      //restart the TIMER
      flashingLedTime = millis();
    }

    //*************
    //switch was OPENED
    else
    {

    }

  } //END of this switch

  //*************************************                     n e x t S w i t c h

} //END of   checkSwitches()






I suggest a small adjustment. Unless I am wrecking a feature:


    //was the switch closed ?
    if (currentState == CLOSED)
    {
      //toggle the flashingFlag
      flashingFlag = !flashingFlag;

      // we not flashing, extinguish the LED
      if (!flashingFlag)
        digitalWrite(flashingLed, ledOff);

      //restart the TIMER
      flashingLedTime = millis();
    }

When the flashing behaviour is switched off, the LED should go off. Not just stay in whatever state it was in.

There are a few other more subtle aesthetic issues, but this is the big one - especially if the LED were to be replaced with a buzzer...

a7

1 Like

Was hoping the OP would have come back with that problem but you get the points.

another tutorialfor which I claim that it is easy to understand.
This tutorial does not exactly show your application switch on something and after a certain amount of time switch it off again.

It shows the basic principle of non-blocking timing based on an everyday example.

You have your code running except the timing thing.
There is another approach which requires learning a new concept which is called state-machine.

I want to emphasize: learning a new concept called statemachine and then applying this concept to your project. The code will look pretty different from your code as it is now.

or in case if there is a trigger-signal and something shall stay switched "ON" for some time then switch off again

best regards Stefan

1 Like

I put @LarryD's code from #4 above, with @alto777's adjustment, in the wokwi.


Play with it here


Since there are points in play (!) I challenge, well, anyone, to discover a less important but still annoying behaviour of the current code.

Hint: understand what makes the flashing happen at a certain frequency, and try s l o w i n g it down quite a bit...

The wokwi simulator is the best I've seen. I will admit to looking at nothing else sim-wise since discovering it recently.

Don't be mislead by the ESP32 claim - the wokwi does a number of Arduino boards. I usually just grab an UNO to play with.

A time, money and grief saver. You can truly focus on the software issues.

a7

1 Like

Might have to learn how to use that tool. :+1:

Hello PTerp

This is an example for an Event-controlled timer coukd be included to your project.

/* BLOCK COMMENT
  - Event-controlled timer
  - This sketch may contain traces of C++.
  - In case of indisposition:
  - https://www.learncpp.com/
  - Hardware:
  - Thanks to LarryD
  - https://aws1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
  - Tested @ Arduino: Mega[X] - UNO [ ] - Nano [ ]
*/
enum Cntrl {Off, On};
struct BLINKLED
{
  const byte Pin;
  const unsigned long Duration[2];  // Off/On time
  unsigned long stamp;
  int cntrlOnOff;
};
BLINKLED blinkLed {9, {250, 500}, 0, Off};

void setup()
{
  Serial.begin(9600);
  Serial.println(F("insert 1 to start - insert 2 to stopp blinking"));
  pinMode(blinkLed.Pin, OUTPUT);
}

void loop()
{
  if (Serial.available())
  {
    switch (Serial.read())
    {
      case '1':
        blinkLed.cntrlOnOff = On;
        digitalWrite(blinkLed.Pin, On);
        break;
      case '2':
        blinkLed.cntrlOnOff = Off;
        digitalWrite(blinkLed.Pin, Off);
        break;
    }
  }
  if (millis() - blinkLed.stamp >= blinkLed.Duration[digitalRead(blinkLed.Pin)] && blinkLed.cntrlOnOff)
  {
    blinkLed.stamp = millis();
    digitalWrite(blinkLed.Pin, !digitalRead(blinkLed.Pin));
  }
}

Due to the use of C++, this example can be extended to n event-controlled timers as needed simply.

Have fun programming and good luck.

Fixed that for ya. :wink:

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.