A 60 second timer

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.

Any help is appreciated!

  • Joe
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 .

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

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.

Try declaring this variable static:

 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.

  unsigned long timePassed = timePassed+(currentTime - pastTime);

Using the timePassed variable on the right side of the equal sign is a mistake. You need to correct this.

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)

1 Like

@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.

As Toby says you know when you start just wait sixty seconds.

Arduino keeps the time. It just keeps it in a simple count. Trying to keep track of seconds is over thinking the problem.

/* 
 watches for LOW signal  at alarmPin 
 when detected delays for alarmDelay 
 then turns on relay
 
 opening the circuit at alarmPin resets anytime 
 */

const byte alarmPin = 2;   
const byte relayPin = 6;    
const unsigned long alarmDelay = 60000UL;

void checkAlarm(){
  static boolean tripped = false;
  static unsigned long trippedTime;
  if (tripped && digitalRead(alarmPin) == HIGH)
  {
    tripped = false;
    digitalWrite(relayPin, LOW);
  } 
  if (tripped && millis() - alarmDelay > trippedTime)
  {
    digitalWrite(relayPin, HIGH);
  }
  if (!tripped && digitalRead(alarmPin) == LOW)
  {
    tripped = true;
    trippedTime = millis();
  }
}

void setup(){
  pinMode (alarmPin, INPUT_PULLUP);
  pinMode (relayPin, OUTPUT);
}

void loop(){
  checkAlarm();
}

Here is a try with interrupts

int pin = 2;

int relay = 4;

volatile int state = LOW;

volatile int timer = 0;

void setup()
{
  pinMode(pin, INPUT);
  
  pinMode(relay, OUTPUT);
  
  digitalWrite(relay, LOW);
  
  attachInterrupt(0, wait, FALLING);
  
  attachInterrupt(0, reset, RISING);
  
}

void loop()
{
}

void wait()
{
  timer = 1;
  unsigned int waitTime = 60000;
  unsigned long startTime = millis();
  unsigned long endTime = millis();
  
  while (endTime - startTime < waitTime && timer == 1)  
  {
    endTime = millis();
  }
  
    if (endTime - startTime >= waitTime)
  {
    digitalWrite(relay, HIGH);
  }
}

void reset()
{
  timer = 0;
}

I think I got the timer working, but im having an issue with my high/low input/output pins. Weirdest thing ever.

#define sensorPin 9
#define sensorOutput 3 


void setup()
{
  Serial.begin(19200);
  pinMode(sensorPin, OUTPUT); //Powers the Sensor
  pinMode(sensorOutput, INPUT); //Input pin from sensor
}



void loop(){
  digitalWrite(sensorPin, HIGH); 
  digitalWrite(sensorOutput, LOW); 

  
int val = digitalRead(sensorOutput);
if (val == HIGH)
{        
   Serial.println("HIGH");
}

if (val == LOW)
{        
   Serial.println("LOW");
}

}

So when it reads out on the serial monitor it reads:

LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
LOW
HIGH
LOW
LOW
LOW
LOW
LOW
HIGH
LOW
LOW
LOW
LOW
LOW
HIGH
LOW
LOW
LOW
LOW
LOW
HIGH
LOW
LOW
LOW
LOW
LOW
LOW
HIGH

If it is defined low, why is it reading a high sometimes??

Also the voltage out of pin 3 (sensorOutput) is .650V when defined LOW, but when defined HIGH, if it was changed the voltage jumps to 4.45V.

Is .650V considered low?

Thanks

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.