Millis logic not working properly

I tried but still the size is bit big for ATtiny MC. I am going to use only for few pins why should we go for big MC?

I need the requirement like this...

      case OFF:
        if (pin1State == HIGH) {
          digitalWrite(RELAY_PIN, OFF);
} else {
           if (pin2State == LOW) {
digitalWrite(RELAY_PIN, OFF);

delay(10000); --> instead of delay I need timer logic
        }
}
        break;

  • It is important you tell us that you only had 2k of memory for the sketch.
    Not doing so steels our time.
    In the future, please, give us all pertinent information so volunteers can best gauge if they should even try to contribute to a thread.

  • Please follow the posting guidelines so we can best help you with answers.

sorry that's my mistake. I will use Arduino nano for testing purpose.

  • The sketch from Post #9 should work on a NANO; it is based on the preamble in Post #8.
  • You can remove the Serial code, but I don’t think it will be enough for 2k memory.

void setup()
{
  Serial.begin(115200);   <——-<<<<<   remove

  • Okay, I removed floating point math and Serial, the size is now down to only

1436 Bytes

:+1:

Try this version

//================================================^================================================
//
//  https://forum.arduino.cc/t/millis-logic-not-working-properly/1363091
//
//  Millis Problem
//
//  Version    YY/MM/DD    Comments
//  =======    ========    ========================================================================
//  1.00       25/03/12    Running code
//
//
//
// Notes:
// I have the following sketch.
// At power up time, the relay is opended
// If pin2 is closed, pin1 is open, and relay is opened, then the relay should close.
//
// While relay is closed, if pin2 opens, the relay should go OFF
// and then the device should be in suspended state for 20 seconds.
//
// Within this 20 seconds all input pins should not work but other output pins should work as usual like blink led.
//


#include <digitalWriteFast.h>


//================================================
#define LEDon              HIGH   //PIN---[220R]---A[LED]K---GND
#define LEDoff             LOW

#define PRESSED            LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define RELEASED           HIGH

#define OPENED             HIGH  //+5V---[Internal 50k]---PIN---[Switch]---GND
#define CLOSED             LOW

#define ENABLED            true
#define DISABLED           false

#define RELAYopened        HIGH
#define RELAYclosed         LOW



//                          millis() / micros()   B a s e d   T I M E R S
//================================================^================================================
//
/*
  //========================
  makeTIMER toggleLED =
  {
     //.TimerType, .Interval, .TimerFlag, .Restart
     MILLIS/MICROS, 500ul, ENABLED/DISABLED, YES/NO

  TIMER functions we can access:
  toggleLED.checkTIMER();
  toggleLED.enableRestartTIMER();
  toggleLED.restartTIMER()
  toggleLED.disableTIMER();
  toggleLED.expireTimer();
  toggleLED.setInterval(100ul);

*/


//These TIMER objects are non-blocking
class makeTIMER
{
#define MILLIS             0
#define MICROS             1

#define ENABLED            true
#define DISABLED           false

#define YES                true
#define NO                 false

#define STILLtiming        0
#define EXPIRED            1
#define TIMERdisabled      2


  private:

  public:

    unsigned long            Time;            //when the TIMER started

    //these "members" are needed to define a TIMER
    byte                     TimerType;       //what kind of TIMER is this? MILLIS/MICROS
    unsigned long            Interval;        //delay time which we are looking for
    bool                     TimerFlag;       //is the TIMER enabled ? ENABLED/DISABLED
    bool                     Restart;         //do we restart this TIMER   ? YES/NO

    //================================================
    //constructor with no parameters
    makeTIMER()
    {
      TimerType = MILLIS;
      Interval = 1000ul;
      TimerFlag = ENABLED;
      Restart = YES;

      Time = 0;
    }

    //================================================
    //constructor with parameters
    makeTIMER(byte _TimerType, unsigned long _Interval,
              bool _TimerFlag, bool _Restart)
    {
      TimerType = _TimerType;
      Interval = _Interval;
      TimerFlag = _TimerFlag;
      Restart = _Restart;

      Time = 0;
    }


    //================================================
    //condition returned: STILLtiming (0), EXPIRED (1) or TIMERdisabled (2)
    //function to check the state of our TIMER  ex: if(myTimer.checkTIMER() == EXPIRED);
    byte checkTIMER()
    {
      //========================
      //is this TIMER enabled ?
      if (TimerFlag == ENABLED)
      {
        //has it expired ?
        if (getTime() - Time >= Interval)
        {
          //============
          //should this TIMER restart again?
          if (Restart == YES)
          {
            //restart this TIMER
            Time = getTime();
          }

          //this TIMER has expired
          return EXPIRED;
        }

        return STILLtiming;

      } //END of   if (TimerFlag == ENABLED)

      //========================
      else
      {
        //this TIMER is disabled
        return TIMERdisabled;
      }

    } //END of   checkTime()

    //================================================
    //function to enable and restart this TIMER  ex: myTimer.enableRestartTIMER();
    void enableRestartTIMER()
    {
      TimerFlag = ENABLED;

      //restart this TIMER
      Time = getTime();

    } //END of   enableRestartTIMER()

    //================================================
    //function to disable this TIMER  ex: myTimer.disableTIMER();
    void disableTIMER()
    {
      TimerFlag = DISABLED;

    } //END of    disableTIMER()

    //================================================
    //function to restart this TIMER  ex: myTimer.restartTIMER();
    void restartTIMER()
    {
      Time = getTime();

    } //END of    restartTIMER()

    //================================================
    //function to force this TIMER to expire ex: myTimer.expireTimer();
    void expireTimer()
    {
      //force this TIMER to expire
      Time = getTime() - Interval;

    } //END of   expireTimer()

    //================================================
    //function to set the Interval for this TIMER ex: myTimer.setInterval(100);
    void setInterval(unsigned long value)
    {
      //set the Interval
      Interval = value;

    } //END of   setInterval()

    //================================================
    //function to return the current time
    unsigned long getTime()
    {
      //return the time             i.e. millis() or micros()
      //========================
      if (TimerType == MILLIS)
      {
        return millis();
      }

      //========================
      else
      {
        return micros();
      }

    } //END of   getTime()

}; //END of   class makeTIMER


//                             D e f i n e   a l l   o u r   T I M E R S
//================================================^================================================
/*example

  //========================
  makeTIMER toggleLED =
  {
     //.TimerType, .Interval, .TimerFlag, .Restart
     MILLIS/MICROS, 500ul, ENABLED/DISABLED, YES/NO

  };

  TIMER functions we can access:
  toggleLED.checkTIMER();
  toggleLED.enableRestartTIMER();
  toggleLED.restartTIMER()
  toggleLED.disableTIMER();
  toggleLED.expireTimer();
  toggleLED.setInterval(100ul);

*/

//========================
//example: uses default library values
//makeTIMER testTIMER{};

//========================
makeTIMER heartbeatTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 500ul, ENABLED, YES
};

//========================
makeTIMER switchesTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 5ul, ENABLED, YES
};

//========================
makeTIMER relayDelayTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 1000ul, DISABLED, NO
};


//                                  c l a s s    m a k e I n p u t
//================================================^================================================
//a class to define input objects, switches or sensors
//
#define NOTvalidated       0
#define VALIDATED          1
#define NOchange           2

//================================================
class makeInput
{
  private:

  public:

    static byte filter;
    //say the above validating "filter" variable is set to 10
    //if we scan "inputs" every 5ms
    //i.e. we sample our inputs every 5ms looking for a change in state.
    //5ms * 10 = 50ms is needed to validate a switch change in state.
    //i.e. A switch change in state is valid "only after" 10 identical changes are detected.
    //This technique is used to filter out EMI (spikes), noise, etc.
    //i.e. we ignore switch changes in state that are less than 50ms.

    byte pin;                       //the digital input pin number
    byte lastState;                 //the state the input was last in

    unsigned long switchTime;       //the time the switch was closed
    byte counter;                   //a counter used to validate a switch change in state

    //================================================
    //constructor with parameters
    makeInput(byte _pin, byte _lastState)
    {
      pin = _pin;
      lastState = _lastState;

      switchTime = 0;
      counter = 0;

      pinMode(pin, INPUT_PULLUP);
    }


    //================================================
    //condition returned: NOTvalidated (0), VALIDATED (1) or NOchange (2)
    //check to see if the input object has had a valid state change
    byte validChange()
    {
      byte pinState = digitalRead(pin);

      //===================================
      //has there been an input change in state ?
      if (lastState != pinState)
      {
        counter++;

        //is this "change in state" stable ?
        if (counter >= filter)
        {
          //an input change has been validated
          //get ready for the next sequence
          counter = 0;

          //update to this new state
          lastState = pinState;

          return VALIDATED;
        }

        return NOTvalidated;
      }

      //===================================
      //there has not been an input change in state
      counter = 0;

      return NOchange;

    } //END of   validChange()

}; //END of   class makeInput

//===================================
//initialize the validating filter
byte makeInput::filter = 10;


//                              G P I O s   A n d   V a r i a b l e s
//================================================^================================================
//

//INPUTS
//================================================
//

//============  GPIO 2
makeInput switch1 =
{
  //.pin, .lastState
  2, OPENED
};

//============  GPIO 3
makeInput switch2 =
{
  //.pin, .lastState
  3, OPENED
};




//OUTPUTS
//================================================
const byte relayPin               = 4;
const byte heartbeatLED           = 5;


//VARIABLES
//================================================
//
//unsigned long suspenedInterval  = 10 * 1000ul;  //10 seconds
unsigned long suspenedInterval    = 20 * 1000ul;  //20 seconds


//                                           s e t u p ( )
//================================================^================================================
//
void setup()
{
  digitalWriteFast(heartbeatLED, LEDoff);
  pinMode(heartbeatLED, OUTPUT);

  //at power up time, the relay is opended
  digitalWriteFast(relayPin, RELAYopened);
  pinMode(relayPin, OUTPUT);

} //END of   setup()


//                                            l o o p ( )
//================================================^================================================
//
void loop()
{
  //================================================
  //Print the time it takes to return to this same spot.
  //comment the next 3 lines when no longer needed
  //static unsigned long startTime;
  //Serial.println(micros() - startTime);
  //startTime = micros();


  //========================================================================  T I M E R  heartbeatLED
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //is it time to toggle the heartbeat LED ?
  if (heartbeatTIMER.checkTIMER() == EXPIRED)
  {
    //toggle the heartbeat LED
    digitalWriteFast(heartbeatLED, digitalRead(heartbeatLED) == HIGH ? LOW : HIGH);
  }

  //========================================================================  T I M E R  switches
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //is it time to check our switches ?
  if (switchesTIMER.checkTIMER() == EXPIRED)
  {
    checkSwitches();
  }

  //========================================================================  T I M E R  relayDelay
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //has this TIMER expired ?
  if (relayDelayTIMER.checkTIMER() == EXPIRED)
  {
    //we are finished with this TIMER
    relayDelayTIMER.disableTIMER();
  }


  //================================================
  //       Other non blocking code goes here
  //================================================


} //END of   loop()


//                                   c h e c k S w i t c h e s ( )
//================================================^================================================
//object.validChange()    - checks to see if there was a valid state change
//object.pin              - hardware pin number
//object.lastState        - the state the switch is in right now
//object.switchTime       - an unsigned long variable where we can save millis()

void checkSwitches()
{
  //========================================================================  switch1
  //was there a validated input change ?
  if (switch1.validChange() == VALIDATED)
  {
    //========================
    //did this switch go closed ?
    if (switch1.lastState == CLOSED)
    {
    }

    //========================
    //this switch went opened
    else
    {
    }

  } //END of mySwitch1


  //========================================================================  switch2
  //was there a validated input change ?
  if (switch2.validChange() == VALIDATED)
  {
    //========================
    //did this switch go closed ?
    if (switch2.lastState == CLOSED)
    {
      //condition returned: STILLtiming, EXPIRED or TIMERdisabled
      //make sure we are not timing
      if (relayDelayTIMER.checkTIMER() == TIMERdisabled)
      {
        if (digitalRead(relayPin) == RELAYopened)
        {
          if (switch1.lastState == OPENED)
          {
            digitalWriteFast(relayPin, RELAYclosed);
          }
        }
      }
    }

    //========================
    //this switch went opened
    else
    {
      if (digitalRead(relayPin) == RELAYclosed)
      {
        digitalWriteFast(relayPin, RELAYopened);

        //set TIMER interval
        relayDelayTIMER.setInterval(suspenedInterval);

        //Start timing
        relayDelayTIMER.enableRestartTIMER();
      }
    }

  } //END of switch2

} //END of   checkSwitches()


//================================================^================================================

EDIT, updated sketch

REMOVED 10 more bytes.

Nano pin 1 is used for Serial.

I did have questions in post #16 but the parallel tasks method I showed (which has no Serial, ATtiny serial is different anyway) takes little room.

The ATtiny's I have are 84's with 8K flash and 8 pins. :slight_smile:

I mean ATtiny2313 MC.

Code uploaded and I observed the following

  • When I connected pin3 to GND, the relay was triggered.
  • After removing pin3 from GND, if I reconnect pin3 to GND within 20 seconds, the input on pin3 doesn't respond. However, if I wait for more than 20 seconds and then connect pin3 to GND, the relay is triggered as expected.
  1. When I connect pin3 with GND, Relay triggered then I removed pin3 from GND and within 20 seconds the PIN3 is connected to GND. I observed that the relay is not triggered even after 20 seconds passed though the pin3 is already connected with GND. Ideally it should on as timer reset.
  • Please confirm this preamble.
// Notes:
// - At power up time, the relay is opended
// - If GPIO 3 is closed, GPIO 2 is open, and relay is opened: the relay should close.
//
// - While relay is closed, if pin2 opens, the relay should go OFF and
//   then the device should be in suspended state for 20 seconds.
//
// - When the relay is suspended and the GPIO 3 is closed and kept closed (GPIO 2 still open),
//   the relay closes again.   <-----<<<<< N E W  parameter
// 
//

small correction

// Notes:
// - At power up time, the relay is opended
// - If GPIO 3 is closed, GPIO 2 is open, and relay is opened: the relay should close.
//
// - While relay is closed, if pin3 opens, the relay should go OFF and
//   then the device should be in suspended state for 20 seconds.
//
// - When the relay is suspended and the GPIO 3 is closed and kept closed (GPIO 2 still open),
//   the relay closes again.   <-----<<<<< N E W  parameter

I see that. I meant ATtiny85 which is physically smaller (8 pins) but has 8K flash and 256 bytes RAM. 3 of those can fit in a 24 pin socket!

I wanted to know about pin 1 and if pin 1 or pin 2 are connected to a button or other kind of contact switch like a microswitch?

Once millis timing is used and there is no blocking code.. there is no need to keep the status blink or button code in the -pin 1-pin 2-relay code- at all, the final hex can be very small.

But I wonder about the role of pin 1 and did leave 4 possible states for that ... if you would like to go that route.
Otherwise I will stop tracking this thread.

see post#34

The code I gave in Reply #18 is 1202 bytes (compiled for a Nano, I don't have the AtTiny chips downloaded)

Update: Using the digitalWriteFast library reduced it down to 1060 bytes

  • New parameter incorporated.

  • Try the version:

//================================================^================================================
//
//  https://forum.arduino.cc/t/millis-logic-not-working-properly/1363091
//
//  Millis Problem
//
//  Version    YY/MM/DD    Comments
//  =======    ========    ========================================================================
//  1.00       25/03/12    Running code
//
//
//
//
// Notes:
// - At power up time, the relay is opended
// - If GPIO 3 (switch2) is closed, GPIO 2 (switch1) is open, and relay is opened: the relay should close.
//
// - While relay is closed, if GPIO 3 (switch2) opens, the relay should open and
//   then the device should be in suspended state for 20 seconds.
//
// - When the relay is no longer suspended and the GPIO 3 (switch2) is closed and 
//   kept closed (GPIO 2 (switch1) still open), the relay closes again.    
//
//



#include <digitalWriteFast.h>


//================================================
#define LEDon              HIGH   //PIN---[220R]---A[LED]K---GND
#define LEDoff             LOW

#define PRESSED            LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define RELEASED           HIGH

#define OPENED             HIGH  //+5V---[Internal 50k]---PIN---[Switch]---GND
#define CLOSED             LOW

#define ENABLED            true
#define DISABLED           false

#define RELAYopened        HIGH
#define RELAYclosed        LOW



//                          millis() / micros()   B a s e d   T I M E R S
//================================================^================================================
//
/*
  //========================
  makeTIMER toggleLED =
  {
     //.TimerType, .Interval, .TimerFlag, .Restart
     MILLIS/MICROS, 500ul, ENABLED/DISABLED, YES/NO

  TIMER functions we can access:
  toggleLED.checkTIMER();
  toggleLED.enableRestartTIMER();
  toggleLED.restartTIMER()
  toggleLED.disableTIMER();
  toggleLED.expireTimer();
  toggleLED.setInterval(100ul);

*/


//These TIMER objects are non-blocking
class makeTIMER
{
#define MILLIS             0
#define MICROS             1

#define ENABLED            true
#define DISABLED           false

#define YES                true
#define NO                 false

#define STILLtiming        0
#define EXPIRED            1
#define TIMERdisabled      2


  private:

  public:

    unsigned long            Time;            //when the TIMER started

    //these "members" are needed to define a TIMER
    byte                     TimerType;       //what kind of TIMER is this? MILLIS/MICROS
    unsigned long            Interval;        //delay time which we are looking for
    bool                     TimerFlag;       //is the TIMER enabled ? ENABLED/DISABLED
    bool                     Restart;         //do we restart this TIMER   ? YES/NO

    //================================================
    //constructor with parameters
    makeTIMER(byte _TimerType, unsigned long _Interval,
              bool _TimerFlag, bool _Restart)
    {
      TimerType = _TimerType;
      Interval = _Interval;
      TimerFlag = _TimerFlag;
      Restart = _Restart;

      Time = 0;
    }


    //================================================
    //condition returned: STILLtiming (0), EXPIRED (1) or TIMERdisabled (2)
    //function to check the state of our TIMER  ex: if(myTimer.checkTIMER() == EXPIRED);
    byte checkTIMER()
    {
      //========================
      //is this TIMER enabled ?
      if (TimerFlag == ENABLED)
      {
        //has it expired ?
        if (getTime() - Time >= Interval)
        {
          //============
          //should this TIMER restart again?
          if (Restart == YES)
          {
            //restart this TIMER
            Time = getTime();
          }

          //this TIMER has expired
          return EXPIRED;
        }

        return STILLtiming;

      } //END of   if (TimerFlag == ENABLED)

      //========================
      else
      {
        //this TIMER is disabled
        return TIMERdisabled;
      }

    } //END of   checkTime()

    //================================================
    //function to enable and restart this TIMER  ex: myTimer.enableRestartTIMER();
    void enableRestartTIMER()
    {
      TimerFlag = ENABLED;

      //restart this TIMER
      Time = getTime();

    } //END of   enableRestartTIMER()

    //================================================
    //function to disable this TIMER  ex: myTimer.disableTIMER();
    void disableTIMER()
    {
      TimerFlag = DISABLED;

    } //END of    disableTIMER()

    //================================================
    //function to restart this TIMER  ex: myTimer.restartTIMER();
    void restartTIMER()
    {
      Time = getTime();

    } //END of    restartTIMER()

    //================================================
    //function to force this TIMER to expire ex: myTimer.expireTimer();
    void expireTimer()
    {
      //force this TIMER to expire
      Time = getTime() - Interval;

    } //END of   expireTimer()

    //================================================
    //function to set the Interval for this TIMER ex: myTimer.setInterval(100);
    void setInterval(unsigned long value)
    {
      //set the Interval
      Interval = value;

    } //END of   setInterval()

    //================================================
    //function to return the current time
    unsigned long getTime()
    {
      //return the time             i.e. millis() or micros()
      //========================
      if (TimerType == MILLIS)
      {
        return millis();
      }

      //========================
      else
      {
        return micros();
      }

    } //END of   getTime()

}; //END of   class makeTIMER


//                             D e f i n e   a l l   o u r   T I M E R S
//================================================^================================================
/*example

  //========================
  makeTIMER toggleLED =
  {
     //.TimerType, .Interval, .TimerFlag, .Restart
     MILLIS/MICROS, 500ul, ENABLED/DISABLED, YES/NO

  };

  TIMER functions we can access:
  toggleLED.checkTIMER();
  toggleLED.enableRestartTIMER();
  toggleLED.restartTIMER()
  toggleLED.disableTIMER();
  toggleLED.expireTimer();
  toggleLED.setInterval(100ul);

*/

//========================
//example: uses default library values
//makeTIMER testTIMER{};

//========================
makeTIMER heartbeatTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 500ul, ENABLED, YES
};

//========================
makeTIMER switchesTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 5ul, ENABLED, YES
};

//========================
makeTIMER relayDelayTIMER =
{
  //.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
  MILLIS, 1000ul, DISABLED, NO
};


//                                  c l a s s    m a k e I n p u t
//================================================^================================================
//a class to define input objects, switches or sensors
//
#define NOTvalidated       0
#define VALIDATED          1
#define NOchange           2

//================================================
class makeInput
{
  private:

  public:

    static byte filter;
    //say the above validating "filter" variable is set to 10
    //if we scan "inputs" every 5ms
    //i.e. we sample our inputs every 5ms looking for a change in state.
    //5ms * 10 = 50ms is needed to validate a switch change in state.
    //i.e. A switch change in state is valid "only after" 10 identical changes are detected.
    //This technique is used to filter out EMI (spikes), noise, etc.
    //i.e. we ignore switch changes in state that are less than 50ms.

    byte pin;                       //the digital input pin number
    byte lastState;                 //the state the input was last in

    unsigned long switchTime;       //the time the switch was closed
    byte counter;                   //a counter used to validate a switch change in state

    //================================================
    //constructor with parameters
    makeInput(byte _pin, byte _lastState)
    {
      pin = _pin;
      lastState = _lastState;

      switchTime = 0;
      counter = 0;

      pinMode(pin, INPUT_PULLUP);
    }


    //================================================
    //condition returned: NOTvalidated (0), VALIDATED (1) or NOchange (2)
    //check to see if the input object has had a valid state change
    byte validChange()
    {
      byte pinState = digitalRead(pin);

      //===================================
      //has there been an input change in state ?
      if (lastState != pinState)
      {
        counter++;

        //is this "change in state" stable ?
        if (counter >= filter)
        {
          //an input change has been validated
          //get ready for the next sequence
          counter = 0;

          //update to this new state
          lastState = pinState;

          return VALIDATED;
        }

        return NOTvalidated;
      }

      //===================================
      //there has not been an input change in state
      counter = 0;

      return NOchange;

    } //END of   validChange()

}; //END of   class makeInput

//===================================
//initialize the validating filter
byte makeInput::filter = 10;


//                              G P I O s   A n d   V a r i a b l e s
//================================================^================================================
//

//INPUTS
//================================================
//

//============  GPIO 2
makeInput switch1 =
{
  //.pin, .lastState
  2, OPENED
};

//============  GPIO 3
makeInput switch2 =
{
  //.pin, .lastState
  3, OPENED
};



//OUTPUTS
//================================================
const byte relayPin               = 4;
const byte heartbeatLED           = 5;


//VARIABLES
//================================================
//
//unsigned long suspenedInterval  = 10 * 1000ul;  //10 seconds
unsigned long suspenedInterval    = 20 * 1000ul;  //20 seconds


//                                           s e t u p ( )
//================================================^================================================
//
void setup()
{
  digitalWriteFast(heartbeatLED, LEDoff);
  pinMode(heartbeatLED, OUTPUT);

  //at power up time, the relay is opended
  digitalWriteFast(relayPin, RELAYopened);
  pinMode(relayPin, OUTPUT);

} //END of   setup()


//                                            l o o p ( )
//================================================^================================================
//
void loop()
{
  //================================================
  //Print the time it takes to return to this same spot.
  //comment the next 3 lines when no longer needed
  //static unsigned long startTime;
  //Serial.println(micros() - startTime);
  //startTime = micros();


  //========================================================================  T I M E R  heartbeatLED
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //is it time to toggle the heartbeat LED ?
  if (heartbeatTIMER.checkTIMER() == EXPIRED)
  {
    //toggle the heartbeat LED
    digitalWriteFast(heartbeatLED, digitalRead(heartbeatLED) == HIGH ? LOW : HIGH);
  }

  //========================================================================  T I M E R  switches
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //is it time to check our switches ?
  if (switchesTIMER.checkTIMER() == EXPIRED)
  {
    checkSwitches();
  }

  //========================================================================  T I M E R  relayDelay
  //condition returned: STILLtiming, EXPIRED or TIMERdisabled
  //has this TIMER expired ?
  if (relayDelayTIMER.checkTIMER() == EXPIRED)
  {
    //we are finished with this TIMER
    relayDelayTIMER.disableTIMER();

    //is switch2 now closed and switch1 is still open ?
    if (switch2.lastState == CLOSED && switch1.lastState == OPENED)
    {
      digitalWriteFast(relayPin, RELAYclosed);
    }
  }


  //================================================
  //       Other non blocking code goes here
  //================================================


} //END of   loop()


//                                   c h e c k S w i t c h e s ( )
//================================================^================================================
//object.validChange()    - checks to see if there was a valid state change
//object.pin              - hardware pin number
//object.lastState        - the state the switch is in right now
//object.switchTime       - an unsigned long variable where we can save millis()

void checkSwitches()
{
  //========================================================================  switch1
  //was there a validated input change ?
  if (switch1.validChange() == VALIDATED)
  {
    //========================
    //did this switch go closed ?
    if (switch1.lastState == CLOSED)
    {
      //nothing to do here
    }

    //========================
    //this switch went opened
    else
    {
      //nothing to do here
    }

  } //END of mySwitch1


  //========================================================================  switch2
  //was there a validated input change ?
  if (switch2.validChange() == VALIDATED)
  {
    //========================
    //did this switch go closed ?
    if (switch2.lastState == CLOSED)
    {
      //condition returned: STILLtiming, EXPIRED or TIMERdisabled
      //make sure we are not timing
      if (relayDelayTIMER.checkTIMER() == TIMERdisabled)
      {
        if (digitalRead(relayPin) == RELAYopened)
        {
          if (switch1.lastState == OPENED)
          {
            digitalWriteFast(relayPin, RELAYclosed);
          }
        }
      }
    }

    //========================
    //this switch went opened
    else
    {
      if (digitalRead(relayPin) == RELAYclosed)
      {
        digitalWriteFast(relayPin, RELAYopened);

        //set TIMER interval
        relayDelayTIMER.setInterval(suspenedInterval);

        //Start timing
        relayDelayTIMER.enableRestartTIMER();
      }
    }

  } //END of switch2

} //END of   checkSwitches()


//================================================^================================================

Your whole code looks good and to the point.
But what if PIN1 is on a bouncy-switch? Or did I miss that detail somewhere?

By default at startup all AVR pins are INPUT LOW.

Yes it is working as expected :slight_smile:

You are correct, I am not debouncing the switches. That could be added, it could also be done with hardware. I merely went off the info I was given and nothing more.

  • Good

  • Go through the sketch and examine what the code looks like.

  • If you want to learn this stuff, ask questions on the how and why things are done.

  • Before starting to code your projects, always start with a schematic and an accurate preamble.