Pulse timing with millis()

So I'm coding a carwash and I need to check many conditions to make sure there's no problem. So my idea is to use millis() so I never block my code. I know how to use millis() to make an event happen every given time, but my problem is: I need to check if the input is high for a given time. let's say I want to know if that button was pressed for 10 seconds and if so, something happens. My code needs to happen in the loop because these conditions need to be checked periodically. I've heard of the function pulseIn, but it is blockant. If any of you has a solution, sharing it would be greatly appreciated.

Thank you

Suggest you use Nick Gammon’s ‘SwitchManager’ for switch timing.

Read this thread.

Checking if something is ON for a certain length of time is slightly perverse - you need to reset the timer any time you find it OFF. Like this

buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {  // assumes HIGH means not pressed
   lastTimeButtonNotPressed = millis();
}

if (millis() - lastTimeButtonNotPressed >= requiredInterval) {
   // do stuff, the button has been pressed throughout the interval
}

...R

Robin2:

buttonState = digitalRead(buttonPin);

if (buttonState == HIGH) {  // assumes HIGH means not pressed
  lastTimeButtonNotPressed = millis();
}

if (millis() - lastTimeButtonNotPressed >= requiredInterval) {
  // do stuff, the button has been pressed throughout the interval
}

So what if I have many inputs combined for a condition to be true?

“So what if I have many inputs combined for a condition to be true?”

Tell us ‘exactly’ what the issue is.

I basically want to use millis() as a timer. My condition becomes true, start the timer. That's simple, the thing is I need to be able to check that timer at any given time because if some conditions are true during a certain time, I need to know and act from there.

  1. A Do you want to know if a switch was held for >= 10 seconds 'when released'.
    OR
    B Do you want to know after 10 seconds if the switch is still pushed?

  2. You also want to know at any time if the switch is being pushed?

I would have an if statement to do something if it's been 10 seconds that the switch is on and yes checking my switch is in my loop so basically checked at any moment

Still a bit confused.

//VERSION 1

unsigned long currentMillis;
unsigned long heartBeatMillis;
unsigned long switchMillis;
unsigned long checkingMillis;

const unsigned long heartFlashRate = 500UL;       // time the led will change state
const unsigned long longPress      = 10 * 1000UL; // 10 seconds

bool pushedFlag         = false;

const byte heartBeatLED = 13;
const byte mySwitch     = 2;   //LOW if switch is press
const byte TenSecLED    = 3;   //LED goes ON if switch is pressed >= 10 seconds

//**********************************************************************
void setup()
{
  Serial.begin(9600);

  //gives a visual indication if the sketch is blocking
  pinMode(heartBeatLED, OUTPUT);
  //Turn ON at 10 seconds
  pinMode(TenSecLED, OUTPUT);

  pinMode(mySwitch, INPUT_PULLUP);

} //END of   setup()


//**********************************************************************
void loop()
{
  //leave this line of code at the top of loop()
  currentMillis = millis();

  //***************************
  //some code to see if the sketch is blocking
  if (CheckTime(heartBeatMillis, heartFlashRate, true))
  {
    //toggle the heartBeatLED
    digitalWrite(heartBeatLED, !digitalRead(heartBeatLED));
  }

  //***************************
  //check the switch every 50ms
  if (CheckTime(switchMillis, 50, true))
  {
    checkSwitch();
  }

  //***************************
  if(pushedFlag == true)
  {
    //the switch is being pushed stuff
  }


  //*********************************
  //put other non-blocking stuff here
  //*********************************

} //END of   loop()


//                        C h e c k T i m e ( )
//**********************************************************************
//Delay time expired function
//parameters:
//lastMillis = time we started
//wait = delay in ms
//restart = do we start again

boolean CheckTime(unsigned long  & lastMillis, unsigned long wait, boolean restart)
{
  //has time expired for this task?
  if (currentMillis - lastMillis >= wait)
  {
    //should this start again?
    if (restart)
    {
      //yes, get ready for the next iteration
      lastMillis = millis();
    }
    
    return true;
  }
  
  return false;

} //END of   CheckTime()


//**********************************************************************
void checkSwitch()
{
  byte switchState = digitalRead(mySwitch);

  //**************************
  if (switchState == LOW)
  {
    if (pushedFlag == false)
    {
      //the time the switch was first pushed
      checkingMillis = millis();
    }

    pushedFlag = true;
  }

  else
  {
    pushedFlag = false;
  }

  //**************************
  if (pushedFlag == true && millis() - checkingMillis >= longPress)
  {
    //do all your switch pressed for >= 10 second

    //example LED ON
    digitalWrite(TenSecLED, HIGH);
  }

  else
  {
    //example LED OFF
    digitalWrite(TenSecLED, LOW);
  }

  //**************************


} //END of   checkSwitch()

//**********************************************************************

Jdufresne:
So what if I have many inputs combined for a condition to be true?

The EXACT SAME WAY as described in #2, just with more than a single condition in the if statement.

When the combination of those many inputs is false, record the time. Otherwise, check whether sufficient time has passed.

There are many "short press - long press" examples.
For a short sketch it can be simple, as shown in the answer by Robin2.

Sometimes I like to turn pressing the buttons into events.
For the moment (the event) that the button is pressed, use the State Change Detection example.

When you need to start the timer, remember the millis() by storing it.
After that you need to know if the button is still pressed, then you can calculate how long it was pressed.

Sometimes it is good to split the loop() into two parts (or three parts). The first part collects all the information from the buttons and sensors and stores that in variables. The second part processes that information. A third part can be the output part where relais and leds are controlled, but that is often combined with the second part.

When your sketch tries to deal with many different situations, then a Finite State Machine might be used.
Tutorial: The Finite State Machine | Majenko Technologies.
In a Final State Machine, the 'state' sometimes holds the information if a button is pressed or not.
Sometimes a Final State Machine makes a sketch easier to understand and maintain, but sometimes it makes it harder to understand.

The larger your sketch, the more important it is to split the different things into different sections. The best solution depends on how complex your sketch is. Dealing with multiple buttons is still easy :wink:

Jdufresne:
So what if I have many inputs combined for a condition to be true?

For readability and troubleshooting make a series of summations. Say there are four pressure switches, three photoelectrics, four tank empty switches, a thermostat switch, two motor contacts. You could:

Group all the pressure switches together - allPressure = PS1 && PS2 && PS3 && PS4

Group the photos together - allPhoto = PE1 && PE2 && !PE3

Likewise for the tank empty switches - allTanksOK = TK1 && TK2 && TK3 && TK4

Put the thermostat and motor contacts together.

Now group the groups - runPermissive = allPressure && allPhoto && allTanksOK && thermoMotor

if(runPermissive == true) {
do something
}

Of course, in the real world you'll want to make the groups represent something logical like, infeedSignals, outfeedSignals, etc. Whatever works for you.

I suspect the problem is that @dougp has given more thought to defining the problem than the OP.

Reply #5 was not a satisfactory response to Reply #4. Reply #5 does not have any details.

The devil is in the detail and until the OP can write down clearly ALL of the things he needs to test and the relationships between them this project won't make progress. Writing this down does not require any knowledge of programming - programming only starts after the requirement has been fully defined.

...R

 pseudocode:
unsigned long start, interval; 

................

if ( intervalMs )  // 1-shot do after time is up
{
  if ( millis() - start >= interval )
  {
     // do the interval is over thing
    interval = 0; // 1-shot is done
  }
}

...........

if ( intervalMs )  // 1-shot do until time is up
{
  if ( millis() - start < interval )
  {
     // do until the interval is over thing
  }
  else
  {
    interval = 0; // 1-shot is done
  }
}

Millis timed code needs to be run over and over in order to keep up with time passing. Blocking wrecks that.
These 1-shots do that only when they need to time some action.
Other code in void loop() triggers a 1-shot by setting interval > 0.

Okay, i'm sorry if I'm not being clear, my problem is not simple to explain in text. Let's start simple with a real case:
I have a pump which is driven by a VFD that is used to push the water in the carwash. There's a pressure switch to know if the water pressure is good. If there's a LOW pressure the switch goes HIGH. if my switch goes HIGH and my pump is running, then it means there's a problem. When the low pressure happens, I need to start the time. If it's been more than 5 seconds, I need to open a bypass valve which brings more water in. If the switch is still HIGH after 30 seconds, then I have to stop everything because the system is in fault.

Referring to Reply #14 ...

What you have described can be accommodated with the sort of code I posted in Reply #2

At the start of the process everything is Normal. If the first (5 second) interval expires (i.e. HIGH continuously for 5 seconds) then the system changes to Bypass mode. If a further interval (30 seconds) expires then (because it is in Bypass mode and the time has expired) it changes to Fault mode and switches the system off.

This is a classic case for a State Machine with states of Normal, Bypass and Fault. If you know how to use ENUMs you can use them for the states. If not you can just use a char variable with values of 'N', 'B' or 'F'

...R

This should work just fine! Thanks to everyone!

Sounds like what you need is a finite state machine implementation.

Jdufresne:
This should work just fine!

S a y w h a t ?