Timer - millis()?

Hi.

What I am trying to do:
-Use a PIR sensor to turn on and off the lights(which is controlled by RF 433.94 MHz).
-Also play music from a SD card when the lights turn on.

What I need help with:
I need a timer so that the lights will stay on for atleast 30 minutes after last motion detected.
I know I can use millis(). My system will close to never be switched off, so the return value of millis() will be extremely high, does this give me any problems? Should I use another method?

Do you guys have any recommendations for me?

I have been looking around for timers, but I haven't found anyone that fits my needs.

(This is my first arduino project, so please bear with me)

Greetings,
Joakim

There are several ways to handle the millis.
Most people say subtract the start time from the current milis, but I prefer a more readable approach (for me), such as :

void loop(){
	nowMilli=millis();  // used to simulate multi-tasking
	if(nowMilli< lastMilli ) { // for 6 week rollover 
		logSpeed();
		toggleLed();
		updateLcd();
	}
	lastMilli=nowMilli;

	if(nextMilliLogSpeed<nowMilli) logSpeed();
	if(nextMilliLedToggle<nowMilli) toggleLed();
	if(nextMilliUpdateLcd<nowMilli) updateLcd();
	loopCounter++;
}
void toggleLed() { //toggle led
	digitalWrite(led, ! digitalRead(led)); 
	nextMilliLedToggle = nowMilli+99;
	if (digitalRead(led) == LOW){
		nextMilliLedToggle = nowMilli+4999;
	}

}

Then inside each function, it sets the nextMilli time to run.
Just my opinion.

Most people say subtract the start time from the current milis, but I prefer a more readable approach

I find this perfectly readable

void loop()
{
  unsigned long currentTime = millis();
  if (currentTime - startTime >= requiredPeriod)
  {
    //execute code at the end of the required period
  }
}

No messing around with exceptions for the rollover. It just works, as long as the variables are declared as unsigned longs.

electrofun123:
I know I can use millis(). My system will close to never be switched off, so the return value of millis() will be extremely high, does this give me any problems? Should I use another method?

Do you guys have any recommendations for me?

You will never get into trouble if you declare your "lastMoveDetectMillis" as an "unsigned long" value, and if your timeout condition is creating the time difference between the current millis() and the previously stored value before comparing against a timeout value.

And if you never try to compare values which are older than the millis() counter needs to create an overflow (ca. 50 days).

Perhaps like that:

void setup() {
  // init input and output pins here
}

boolean motionDetect()
{
  // function should return motion detection of motion sensor
};

const byte lightPin=13;
boolean lightState;
#define TIMEOUT (30L * 60000L)    // 30 minutes in milliseconds
unsigned long lastMotionMillis;

void loop() {
  if (motionDetect())
  {
    lightState=HIGH;
    lastMotionMillis=millis(); // remember time when last motion was detected
  }
  if (lightState && (millis()-lastMotionMillis>=TIMEOUT)) lightState=LOW;
  digitalWrite(lightPin, lightState);
}
if (currentTime - startTime >= requiredPeriod)

With this, how do I toggle the LED, off for 5 seconds, then on for 1/10 seconds. I need help understanding that. Thanks.

"requiredPeriod" could be made = 5000 then made 100 then back to 5000 etc.

use:
digitalWrite(pin,!digitalRead(pin)); // to toggle pin

[quote author=jack wp date=1436731827 link=msg=2313786]

if (currentTime - startTime >= requiredPeriod)

With this, how do I toggle the LED, off for 5 seconds, then on for 1/10 seconds. I need help understanding that. [/quote]

Always blinking 5 seconds off and 100 milliseconds on?

  currentTime=millis();
  if (currentTime-startTime)>=5100 startTime+=5100;
  if (currentTime - startTime < 5000) lightState=LOW;
  else lightState=HIGH;
  digitalWrite(lightPin, lightState);

jurs:

#define TIMEOUT (30L * 60000L)    // 30 minutes in milliseconds

To be correct, make it unsigned, too.
I prefer using const, but this may be a matter of taste

const uint32_t SECOND = 1000; // millis per second
const uint32_t MINUTE = 60 * SECOND; // millis per minute
const uint32_t TIMEOUT_lights = 4 * MINUTE;

@olf2012
Maybe add UL to your numbers for the compiler.
ex 1000UL etc.

.

@LarryD

The compiler output is exactly the same after adding UL.
I think it is not necessary because

  • in line 1: an int is assigned to an unsigned long, so it is promoted to UL
  • in line 2 and 3: an int is multiplied by an unsigned long, so it is also promoted to UL

Hi, again and thanks for all responds!

I've made one example code, could you see if this would work?(in general + rollovers).

Is unsigned long and uint32_t the same? If not: which should I use?

unsigned long lastMotionDetectedTime;
const unsigned long requiredTime = 30*60*1000;
bool lightState = false;


void setup() {
  //Setup done here.
}

void loop() {
  unsigned long currentTime = millis();
  
  if(motionDetected()){
    lastMotionDetectedTime = millis();
    if(lightState == false){
      lightsOn();
      lightState = true;
    }
  }
  
  if(currentTime - lastMotionDetectedTime >= requiredTime){
    lightsOff();
    lightState = false;
  }
}
const unsigned long requiredTime = 30*60*1000;

Try printing the value of requiredTime. You may be surprised at what you see.

Then try

const unsigned long requiredTime = 30UL * 60 * 1000;

and print it. Is that better ?

UKHeliBob:

const unsigned long requiredTime = 30*60*1000;

Try printing the value of requiredTime. You may be surprised at what you see.

Then try

const unsigned long requiredTime = 30UL * 60 * 1000;

and print it. Is that better ?

You are correct! That did surprise me! What happens?

What happens?

Unless you tell the compiler differently it uses integer maths when doing the multiplication. Explicitly making one or more of the elements of the multiplication an unsigned long (UL) makes the result of the multiplication an unsigned long. I also separated the constants and the operators to make it easier to read that that has nothing to do with the result.

olf2012:
@LarryD

The compiler output is exactly the same after adding UL.
I think it is not necessary because

  • in line 1: an int is assigned to an unsigned long, so it is promoted to UL
  • in line 2 and 3: an int is multiplied by an unsigned long, so it is also promoted to UL

See post #13 by UKHeliBob
But go ahead and leave it off, you reap the benefits ;).
.