Timer using millis()

Im trying to make a timer which controls an output signal for 20 min and 240 min.

When I get a signal with over 4 volts in port A0 and A1 a timer should start. In this case it controls my led, just to se if its working. But its not...

The program compiles as it should and everything seems to work but I cant get that led light working as it suppose to.

#include "Arduino.h"

int minutes_1 = 60000; // 1000*60
int minutes_20 = 1200000; // 1000*60*20
int minutes_240 = 14400000; // 1000*60*240

unsigned long current_time_1;
unsigned long current_time_2;

int timer_running_1 = 0;
int timer_running_2 = 0;
int led = 13;

void setup() 
{
  Serial.begin(9600);
  pinMode(led, OUTPUT);
}

void loop() 
{  
  int sensorValue_A0 = analogRead(A0);
  float Voltage_A0 = sensorValue_A0*(5.0/1023.0); // reads signal from A0
  
  int sensorValue_A1 = analogRead(A1);    
  float Voltage_A1 = sensorValue_A1*(5.0/1023.0);  // reads signal from A1
  
  if(Voltage_A0 > 4) // if signal is over 4 volts
  {
    timer_running_1 = 1; // enters a condition to start timer1
    current_time_1 = millis(); // saves the current time to have something to compare with
  }
  
  if(Voltage_A1 > 4)
  {
    timer_running_2 = 1;
    current_time_2 = millis();
  }
   
   
  if (timer_running_1 == 1) // timer1
  {   
    if((long)(millis() - (minutes_20 + current_time_1)) >= 0)  // once 20 min has past this condition should set an end for the timer.
    {
      digitalWrite(led, LOW);
      timer_running_1 = 0;
    }
    else // otherwise we keep sending out the signal, in this case the led light
      digitalWrite(led, HIGH);
  }
  
    if (timer_running_2 == 1) // timer2
  {
    if((long)(millis() - (minutes_240 + current_time_2)) >= 0) 
    {
      digitalWrite(led, LOW);
      timer_running_2 = 0;
    }
    else
      digitalWrite(led, HIGH);
  }
}

first tip:

you need to use

unsigned long minutes_240 = 14400000UL

otherwise the vars overflow.

same for minutes 1 and 20 .

(you can print the value to serial monitor to debug the values used!)

succes

if (timer_running_1 == 1) // timer1
  {   
    if((long)(millis() - (minutes_20 + current_time_1)) >= 0)  // once 20 min has past this condition should set an end for the timer.
    {
      digitalWrite(led, LOW);
      timer_running_1 = 0;
    }
    else // otherwise we keep sending out the signal, in this case the led light
      digitalWrite(led, HIGH);
  }
  
    if (timer_running_2 == 1) // timer2
  {
    if((long)(millis() - (minutes_240 + current_time_2)) >= 0) 
    {
      digitalWrite(led, LOW);
      timer_running_2 = 0;
    }
    else
      digitalWrite(led, HIGH);
  }

Why do you cast the variables to long??? They should always be used as unsigned long.

Maybe because you re-set timer_running_1 to 1 in the next loop if the voltage is still above 4V. Try to change this line:

if(Voltage_A0 > 4)

to

if(Voltage_A0 > 4 && timer_running_1 == 0)

robtillaart: first tip:

you need to use

unsigned long minutes_240 = 14400000UL

otherwise the vars overflow.

same for minutes 1 and 20 .

(you can print the value to serial monitor to debug the values used!)

succes

I will look into it and try that, thanks. What about that debug? I use an arduino UNO without any display, is it possible to show messages in cmd on the computor? or do I have to buy a seperate display?

IN the Arduino IDE you have a button called Serial monitor. This shows the serial output when the Arduino is connected to your PC with USB.

The code below show how you can see a variable and the internal clock, the delay is to prevent too much output

void setup()
{
  Serial.begin(9600);  // the baud rate should be equal to the serial monitor
}

void loop()
{
  int x = 3;
  Serial.print(millis());
  Serial.print("   ");
  Serial.println(x);
  delay(250);
  x = x + 1;
}

You can add similar statements within your application.

I removed that (long) statement in the if-case. Now it looks like this:

if((millis() - (minutes_240 + current_time_2)) >= 0)

However this is what gets shown in the serial monitor:

A06693A16693timer stop 16693timer stop 26694A06694A16694timer stop 16696timer stop 26713A16719timer stop 26735A06742A16749timer stop 16765timer stop 26781A06788A16794timer stop 16810timer stop

It seems like the break condition gets activated right away and I dont understand why.

my whole code:

#include "Arduino.h"

unsigned long minutes_1 = 60000;
unsigned long minutes_20 = 1200000;
unsigned long minutes_240 = 14400000;

unsigned long current_time_1;
unsigned long current_time_2;

int timer_running_1 = 0;
int timer_running_2 = 0;
int led = 13;

void setup() 
{
  Serial.begin(9600);
  pinMode(led, OUTPUT);
}

void loop() 
{  
  int sensorValue_A0 = analogRead(A0);
  float Voltage_A0 = sensorValue_A0*(5.0/1023.0); // läser in signalen på port A0
  
  int sensorValue_A1 = analogRead(A1);    
  float Voltage_A1 = sensorValue_A1*(5.0/1023.0);  // läser in signalen på port A1
  
  if(Voltage_A0 > 4  && timer_running_1 == 0) // kontrollerar om det är över 4 volt jag får in
  {
    timer_running_1 = 1; // sätter igång ett vilkor för att börja köra den första timern
    current_time_1 = millis();
    Serial.print("A0");
    Serial.print(millis());
  }
  
  if(Voltage_A1 > 4  && timer_running_2 == 0)
  {
    timer_running_2 = 1;
    current_time_2 = millis();
    Serial.print("A1");
    Serial.print(millis());
  }
   
  if (timer_running_1 == 1)
  {   
    if((millis() - (minutes_1 + current_time_1)) >= 0) // när det har gått 20 min så går vi in och bryter signalen
    {
      digitalWrite(led, LOW);
      timer_running_1 = 0;
      Serial.print("timer stop 1");
      Serial.print(millis());
      
    }
    else
      digitalWrite(led, HIGH);
  }
  
    if (timer_running_2 == 1)
  {
    if((millis() - (minutes_240 + current_time_2)) >= 0) // när det har gått 240 min så går vi in och bryter signalen
    {
      digitalWrite(led, LOW);
      timer_running_2 = 0;
      timer_running_1 = 0;
      Serial.print("timer stop 2");
      Serial.print(millis());
    }
    else
      digitalWrite(led, HIGH);
  }
}

First layout/format your code this will help you and us!

Then make your debug statements clearer eg

Serial.print("A0= "); // this gives you A0= Serial.println(A0); // this prints the value of A0 and then a new line

Mark

Why do you cast the variables to long?

Having a signed type makes detecting overflow infinitely easier.

holmes4: First layout/format your code this will help you and us!

Then make your debug statements clearer eg

Serial.print("A0= "); // this gives you A0= Serial.println(A0); // this prints the value of A0 and then a new line

Mark

of course, care to tell how to make a new line in monitor?

print prints it println prints and then a newline.

Mark

I recently wrote a timer library to do just what you need. It handles millis() roll-over and just sets a bit when it has counted the time you specified. I mention it only because I am very new to Arduino and the library uses the simplest of code and is verbosely commented. There is no clever in-depth C and no interrupts. I am not suggesting that this code id anything special or clever but it is useful, simple, and taught me a great deal when I built it.

I will be happy to send you the code, which you could easily use outside a library, if you would like to play with it.

Al

omegaman: if((millis() - (minutes_240 + current_time_2)) >= 0)

That doesn't handle overflow correctly, although to be fair that would only be an issue if you're expecting to leave this running for weeks and weeks. Still, it's best to get into the habit of using a construct that handles overflow correctly:

if((millis() - current_time_2) >= minutes_240)

(I'm assuming here that current_time_2 is an unsigned long holding a previous value of millis(), and minutes_240 is an unsigned long that holds the required duration in milliseconds.)

This is the code I talked about, it is working fine for me.
Please keep in mind that this is just simple stuff but it should get you started.

I hope you find it useful … I learned loads doing and didn’t think it at all simple at the time :cold_sweat:

Al

GeneralTimer.zip (5.41 KB)

PeterH:

omegaman: if((millis() - (minutes_240 + current_time_2)) >= 0)

That doesn't handle overflow correctly, although to be fair that would only be an issue if you're expecting to leave this running for weeks and weeks. Still, it's best to get into the habit of using a construct that handles overflow correctly:

if((millis() - current_time_2) >= minutes_240)

(I'm assuming here that current_time_2 is an unsigned long holding a previous value of millis(), and minutes_240 is an unsigned long that holds the required duration in milliseconds.)

My intention is actually to leave this on and have it run for ever. So thank you for your suggestion.

My intention is actually to leave this on and have it run for ever.

In that case, you may want to think about implementing a SysTick styled timer using timer0.

What happens if the roll over in the millis() happens when my timer is running? Then my current_time variable will be huge and the millis will start all over. Which should mean that would take 49 days minus my pretedermined time break the timer?

In that case there are a certain times that potentially can ruin my whole program?

What happens if the roll over in the millis() happens when my timer is running?

The same thing that happens when your watch rolls over at noon and midnight. As you can imagine, nothing.

As long as you always use subtraction to determine interval, rather than addition to define "next time".

In that case there are a certain times that potentially can ruin my whole program?

Only if your interval exceeds 49 days.

PaulS:

What happens if the roll over in the millis() happens when my timer is running?

The same thing that happens when your watch rolls over at noon and midnight. As you can imagine, nothing.

As long as you always use subtraction to determine interval, rather than addition to define "next time".

In that case there are a certain times that potentially can ruin my whole program?

Only if your interval exceeds 49 days.

I dont understand how that can be the case.

What if my current_time gets triggered that millisecend before the millis() rolls over. That would cause my current_time to store a huge number mean while millis() will start from 0. Then it will take some time for that millis() - current_time >= 0. Or have I gotten it all wrong?

There was a long thread a while ago that explained why subtraction involving unsigned variables was guaranteed to work. You could try to find that thread, if you are interested in why it works.

But, think about your watch. It rolls over every 12 hours. If you had lunch at 11:30, you don't have any trouble determining that, at 1:30, it's been two hours since you've eaten, even though then (1130) is larger than now (130). The Arduino doesn't either.