I'm looking to create a timer that when a low signal is sent to the arduino, the timer starts counting to 60seconds.
Once the timer hits 60 seconds I want it to have the arduino send a signal to a relay.
But if a high signal is sent to the arduino before 60 seconds, the timer resets to 0 and waits for another low signal.
Ive been looking into the millis command, but its a loop that runs continuously. I dont know how I would implement this.
mils = millis();
if ( digitalRead(input_pin) == LOW ) // checking input for signal "low"
{
if ( mils - wasmils >= 1000 ); // increasing variable "seconds" every second
{
seconds ++;
wasmils = mils;
}
}
else
{
seconds = 0; // if signal is HIGH, reseting variable "seconds"
digitalWrite( output_pin, LOW );
}
if ( seconds == 60 ) // sending signal HIGH ( or low ) to relay when "seconds" reaches 60 and reseting variable
{ digitalWrite(output_pin, HIGH);
seconds = 0;
}
This is only "pseudocode" but might give you some idea. This would run in loop offcourse and keep relay signal HIGH as long as input signal is LOW. if you want it to happen only once , you could use FOR loop .
unsigned long currentTime = 0; //this variable will be overwritten by millis() each iteration of loop
unsigned long pastTime = 0; //no time has passed yet
int currentState = 0; //the default state
unsigned long seconds = 0;
void loop()
{
pastTime = currentTime; //currentTime at this point is the current time from the previous iteration, this should now be pastTime
currentTime = millis(); //currentTime is now the current time (again).
unsigned long timePassed = currentTime - pastTime; //this is roll-over proof, if currentTime is small, and pastTime large, the result rolls over to a small positive value, the time that has passed
if (digitalRead(11) == LOW) //Pressure switch on knob not pressed, stove knob is turned "POWER ON", if timerReset = LOW
{
//TIMER START
if ( timePassed >= 1000 ); // increasing variable "seconds" every second
{
seconds ++;
pastTime = currentTime;
}
//else
//{
//seconds = 0;
//}
if ( seconds == 60 ) // sending signal HIGH ( or low ) to relay when "seconds" reaches 60 and reseting variable
{
digitalWrite(relayInput, LOW); //relayInput = LOW; //turns off relay, turning off burner
keepburnerOFF = true; //Keeps burner off even if an object is placed on the burner after 60 seconds & timerReset not HIGH
seconds = 0;
}
//TIMER END
}
This is what I got, Would this setup work? Just the timer, I left other things out that i have in the actual code
Dugan:
Actually helped, I'm going to try it out! Thanks, Im guessing wasmils is declared 0 to start?
Im so use to other languages, when I try this one I'm not use to the infinite loop
I would recommend initializing wasmils to millis(). I also suggest bumping wasmils by 1000 instead of setting it to mils. This will prevent creep and in the long run will keep much more accurate time.
Um. I think you're going to have problems with that one. It looks like you're setting pastTime every time the loop executes. You're not timing how long it has been since the trigger went low, you're timing how long since the last time through the loop function. You also didn't specify whether the signal to the relay was HIGH or LOW, and when to reset the relay, but with some guessing, here's a possibility:
// untested code
const byte inputPin = 11;
const byte relayPin = 12; // guessing here
void setup()
{
pinMode(inputPin, INPUT);
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, LOW); // Start the relay low
}
void loop()
{
static unsigned long LowTimeStamp = 0L; // Time stamp when input went LOW
static byte State = 0; // 0 = input HIGH, 1 = input LOW and timing, 2 = input LOW timed out and and relay tripped
byte inputState;
inputState = digitalRead(inputPin);
if (State == 0)
{
if (inputState == LOW) // Input just went LOW. Start the Timer.
{
LowTimeStamp = millis();
State = 1;
}
}
else if (State == 1)
{
if (inputState == HIGH) // input went back high before the timeout. Reset state
{
State = 0;
}
else
{
if (millis() - LowTimeStamp >= 60000L) // 60 seconds
{
digitalWrite(relayPin, HIGH);
State = 2;
}
}
else if (State == 2)
{
if (inputState == HIGH)
{
digitalWrite(relayPin, LOW);
State = 0;
}
}
}
}
unsigned long currentTime = 0; //this variable will be overwritten by millis() each iteration of loop
unsigned long pastTime = 0; //no time has passed yet
int currentState = 0; //the default state
boolean keepburnerOFF = false; //Default false so stove can work
unsigned long seconds = 0;
void setup(){
Serial.begin(19200);
}
void loop(){
pastTime = currentTime; //currentTime at this point is the current time from the previous iteration, this should now be pastTime
currentTime = millis(); //currentTime is now the current time (again).
unsigned long timePassed = timePassed+(currentTime - pastTime); //this is roll-over proof, if currentTime is small, and pastTime large, the result rolls over to a small positive value, the time that has passed
//TIMER START
if ( timePassed >= 1000 ); // increasing variable "seconds" every second
{
seconds ++;
timePassed = timePassed - 1000;
}
if ( seconds == 5000000 ) // sending signal HIGH ( or low ) to relay when "seconds" reaches 60 and reseting variable
{
Serial.println("Tick");
seconds = 0;
}
//TIMER END
}
Im using this code to test it, 5,000,000 is roughly 37.5-38.5 seconds. Anyone see why this is being so off? I would expect 5000 to be 5 seconds, but it loops so fast at 5000 there is no way its 5 seconds.
unsigned long timePassed = timePassed+(currentTime - pastTime); //this is roll-over proof, if currentTime is small, and pastTime large, the result rolls over to a small positive value, the time that has passed
Using a variable while you're initializing it may not be the best idea.
I don't get why you are incrementing seconds every 1000ms, then counting until you have 60s, why not just wait until 60000ms have passed, it's even more accurate this way as you don't get the rounding error each time you add a second (e.g. if 1005ms have passed).
unsigned long end_time;
void setup(){
end_time=millis()+60000;
}
void loop(){
if(millis()>=end_time){
//60 s have passed!!
end_time=millis()+60000; //reset the timer
}
}
(I used end time rather than start time as it's slightly more efficient, if you used start time the if statement would be if(millis()-start_time>=60000) so it has to calculate millis()-start_time every cycle, whereas this way it only does the calculation once)
@tobyb121 You can end the drift if you change the bump line to:
end_time+=60000; //reset the timer
This way it doesn't matter how late you get here, in the long run it will be much more accurate.
Dugan:
If it is defined low, why is it reading a high sometimes??
It's not "defined low". Despite the name, sensorOutput is defined as an INPUT. All the digitalWrite(sensorOutput, LOW); does is turn off the pull-up resistor.
Unless you have connected something to pin 3 the input state will be floating and digitalRead() will return arbitrary values.