-
Try the sketch attached below.
-
I used the preamble shown in post #8.
-
I always start off a new sketch with a skeleton as seen in the code below.
I then modify it to do what my preamble says.
-
The sketch below uses a class, makeTIMER and a class, makeInput.
-
Classes might make code look complicated, however, classes make your code organized and documented.
Example make a TIMER object:
//========================
makeTIMER relayDelayTIMER =
{
//.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
MILLIS, 20 * 1000ul, DISABLED, NO, 0
};
Example, make an Input object:
//============ GPIO 2
makeInput switch1 =
{
//.pin, .lastState
2, OPENED
};
- BTW, in the future, you must be consistent in your code, always use named variables with unique names; don’t use HIGH/LOW, true/false.
//================================================^================================================
//
// 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, .SpeedAdjustPin
MILLIS/MICROS, 500ul, ENABLED/DISABLED, YES/NO, A0-A5
//.SpeedAdjustPin defaults to 0 i.e. no speed adjustment is used
//if .SpeedAdjustPin = A0-A5, a potentiometer on this pin adjusts the TIMER's speed (for diagnostics)
//class static flag "makeTIMER::normalFlag" can be used to ENABLE/DISABLE adjustable TIMER speed,
//ENABLE = normal speed, DISABLED = potentiometer controls TIMER speed
};
TIMER functions we can access:
toggleLED.checkTIMER();
toggleLED.enableRestartTIMER();
toggleLED.restartTIMER()
toggleLED.disableTIMER();
toggleLED.expireTimer();
toggleLED.setInterval(100ul);
makeTIMER::normalFlag = ENABLED/DISABLED
*/
//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:
static bool normalFlag; //when ENABLED, adjustable TIMERs run at normal speed
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
byte SpeedAdjustPin; //a potentiometer on this pin, A0-A5, adjusts TIMER speed
//================================================
//constructor with no parameters
makeTIMER()
{
TimerType = MILLIS;
Interval = 1000ul;
TimerFlag = ENABLED;
Restart = YES;
SpeedAdjustPin = 0;
Time = 0;
}
//================================================
//constructor with parameters
makeTIMER(byte _TimerType, unsigned long _Interval,
bool _TimerFlag, bool _Restart, byte _SpeedAdjustPin = 0)
{
TimerType = _TimerType;
Interval = _Interval;
TimerFlag = _TimerFlag;
Restart = _Restart;
SpeedAdjustPin = _SpeedAdjustPin;
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)
{
//============
//is this an adjustable TIMER OR is the "normalSpeed" switch closed ?
if (SpeedAdjustPin == 0 || normalFlag == ENABLED)
{
//TIMER is not speed adjustable
//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;
}
}
//============
//we are using a potentiometer to adjust the TIMER speed
else
{
//for diagnostics, use a potentiometer to adjust TIMER speed
//has it expired ?
if (getTime() - Time >= Interval / adjustInterval())
{
//============
//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()
//================================================
//for diagnostics, a potentiometer on an analog pin is used to adjust TIMER speed, thanks alto777
float adjustInterval()
{
int Speed = analogRead(SpeedAdjustPin);
float fSpeed = 1.0 + Speed * 12.0 / 1023.0;
return fSpeed;
} //END of adjustInterval()
}; //END of class makeTIMER
//create/initialize static "normalFlag" of class makeTIMER
bool makeTIMER::normalFlag = DISABLED;
//================================================^================================================
// 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, .SpeedAdjustPin
MILLIS/MICROS, 500ul, ENABLED/DISABLED, YES/NO, A0-A5
//.SpeedAdjustPin defaults to 0 i.e. no speed adjustment is used
//if .SpeedAdjustPin = A0-A5, a potentiometer on this pin adjusts the TIMER's speed (for diagnostics)
//class static flag "makeTIMER::normalFlag" can be used to ENABLE/DISABLE adjustable TIMER speed,
//ENABLE = normal speed, DISABLED = potentiometer controls TIMER speed
};
TIMER functions we can access:
toggleLED.checkTIMER();
toggleLED.enableRestartTIMER();
toggleLED.restartTIMER()
toggleLED.disableTIMER();
toggleLED.expireTimer();
toggleLED.setInterval(100ul);
static variable access
makeTIMER::normalFlag = ENABLED/DISABLED */
//========================
//example: uses default library values
//makeTIMER testTIMER{};
//========================
makeTIMER heartbeatTIMER =
{
//.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
MILLIS, 500ul, ENABLED, YES, 0
};
//========================
makeTIMER switchesTIMER =
{
//.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
MILLIS, 5ul, ENABLED, YES, 0
};
//========================
makeTIMER relayDelayTIMER =
{
//.TimerType, .Interval, .TimerFlag, .Restart, .SpeedAdjustPin
MILLIS, 1000ul, DISABLED, NO, 0
};
// 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()
{
Serial.begin(115200);
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();
//================================================
//PULSE62D13;
//PULSE62D13;
//======================================================================== 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()
//================================================^================================================
Try out the above sketch, if you have questions, ask them.
EDIT
Updated sketch