Timer

I'm looking to delay a section of my sketch for am hour so it will only run that section of the loop if an hour has past. I have this working in my testing but haven't extended it past 5 minutes yet. The code below is a simplified version of the code that I am using. I will be running this on an Arduino Mega that will be powered up for months on end.

2 questions to the experts(all of you that know more than me)

  1. With the code below will I have trouble at the 50ish day when the timer rolls over?
  2. What is the max feasible value that I can use as INTERVAL?
int led = 13;
unsigned long timer; // the timer
unsigned long INTERVAL = 1000; // the repeat interval

void setup() {
  pinMode(led, OUTPUT); // initialize LED output
  timer = millis(); // start timer
}

void loop() {
  if ((millis()-timer) > INTERVAL) {
    // timed out
    timer += INTERVAL;// reset timer by moving it along to the next interval 
    //    toggle led
    if (digitalRead(led)) {
      digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
    } else {
      digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
    }
  }
}

Thanks,
Guru

unsigned long INTERVAL = 1000UL * 60UL * 60UL;

AWOL is writing it that way and letting the Arduino do the caculation better than me just putting

unsigned long INTERVAL = 3600000

gurufarmer:
AWOL is writing it that way and letting the Arduino do the caculation better than me just putting

unsigned long INTERVAL = 3600000

It is more clear where the number comes from when someone else reads it or when you come back to this code after some time away. It's just for the humans. The compiler and processor couldn't care less how you write that.

It isn't the Arduino which does the calculation, it's the compiler.

It's certainly better than writing

unsigned long INTERVAL = 1000 * 60 * 60;

Ok, that makes since.

Will it have any issues when the timer rolls over?

I don't foresee any problems, but for accuracy I suggestif ((millis()-timer) >= INTERVAL) {

"1) With the code below will I have trouble at the 50ish day when the timer rolls over?"
No, as you use subtraction to do elapsed time check.

"2) What is the max feasible value that I can use as INTERVAL?"
Probably something close to 1/2 of 49 days?
Say < 1/2 + <1/2 = 0xfffffffa, and millis() was at 0xfffffff0.
Then 0xfffffff0 - 0xfffffffa = 0xfffffff6, which is greater than 7ffffffd, so guess that would still work.
Just > 1/2 of 49 days? 80000001
So 80000001 + 80000001 = 2, fffffff0 - 2 = ffffffef which is greater then 80000001, so I guess that works too.
Do some experimenting with a calculator, like Win calculator in Programmer mode, use hex, keep your entries to 32 bits (8 characters), and only look at 32 bit results, any above that drop off in unsigned long math.

I'm working on a sketch that I though I had working correctly but found a flaw today. The sketch is to send an SMS message every time motion is detected but I only want 1 SMS if motion has been detected in the last >60 minutes. With the sketch below I get 1 SMS for every hour however if their is no motion detected for lets say 6 hours once motion is detected I get 6 SMS messages. So instead of just 1 SMS when motion is detected even though no motion has occurred in 6 hours I get 6 SMS messages 1 for every hour that no motion was detected. How can I get it so even if no motion is detected for 3 days but on the 3rd day motion is detected I only get 1 SMS and if motion is only detected for lets say 59 minutes and only on the 61st minutes I get the second SMS. I'm just trying to keep it from bombarding me with SMS messages but still get the knowledge that motion has been detected. The sketch below is shortened up to only the key code for this issue.

unsigned long motiontimer;          // the motion timer
unsigned long motionINTERVAL = 1000UL * 60UL * 60UL;  // How often to report motion

void setup() {
  motiontimer = millis(); // start motion timer
}

void loop() {
  //------------Motion Detection------------
  //If Motion is detected send Text
    int value = digitalRead(MotionPin);
    if (value == HIGH)
    {
      if ((millis() - motiontimer) > motionINTERVAL)
      {
        motiontimer += motionINTERVAL;// reset timer by moving it along to the next interval
        digitalWrite(ledMotionSMSPin, HIGH);
        mySerial.println("AT + CMGS = \"+1512202xxxx\"");
        delay(100);
        mySerial.println("Motion has been detected!");//the content of the message
        delay(100);
        mySerial.println((char)26);//the ASCII code of the ctrl+z is 26
        delay(100);
        mySerial.println();
        delay(500); //Just to keep LED on longer for testing
        digitalWrite(ledMotionSMSPin, LOW);
      }
    }
}  //END OF LOOP
void setup() {
  motiontimer = millis(); // start motion timer
}

That is NOT starting a timer. That is recording when an event happens (setup() gets called). it is misleading to call that a timer.

Timing is the wrong approach. The PIR sensor is a switch. It can be HIGH or it can be LOW. The thing that is interesting is when it changes from LOW to HIGH or HIGH to LOW. In one case, it means that motion was detected. In the other, it means that motion is no longer being detected.

You want to send the message when the state changes, not when the state is, as you are doing it now.

The state change detection example has some clues.

PaulS:

void setup() {

motiontimer = millis(); // start motion timer
}



That is NOT starting a timer. That is recording when an event happens (setup() gets called). it is misleading to call that a timer.

I realize its not starting a timer just setting current millis to variable motiontimer. I need to remove the description.

I also do understand a PIR is just a switch and I could change it to using state but here's why I am reading if it is HIGH. The PIR that I have is always HIGH if motion is being detected and only LOW if no motion is detected. I am using a timer only because I only want 1 SMS if motion is detected every hour. I'm trying to keep it from sending an SMS everytime the loop is processed.

To help understand my goal, here is my use. I am selling a house that no one currently lives in and I live a great distance from it so cant go check on it without calling friends and family. I just want 1 SMS if someone enters the house. If lets say the realtor enters the house I only want 1 SMS even if they are showing the house for 45 minutes. Only if they are in the house for more than 60 minutes do I want another SMS. If the realtor again shows the house 3 days later I only want 1 SMS when they enter and again only a second if they have been in the house more than 60 minutes. If I remove the timer everytime they enter a room and come back to the room the PIR is in then I'll again get another SMS. I can change the delay on the PIR to slow the messages down some but only to like 5 minutes if I recall correctly.

If lets say the realtor enters the house I only want 1 SMS even if they are showing the house for 45 minutes.

Then, when the state (of the PIR sensor) changes from "no motion" to "motion", send an SMS.

Only if they are in the house for more than 60 minutes do I want another SMS.

So, this requires that you record the time (NOT timer) that the state changes from "no motion" to "motion" and set the time to 0 when the state changes from "motion" to "no motion".

Independent from checking the state changes, you need to see if the "motion started" time is not 0. If it is, see if now minus then exceeds 1 hour. If it does, send another SMS and set the time to when you send the message.

I made a few changes. I didn't add a state change yet, its still just checking to see if the current state of the PIR is high when the loop hits this portion but I changed the time check so it just checks if the current millis - motiontime is higher than the interval. If it is then it continues an resets the current millis as the motiontime variable. Should that get rid of the problem with it looping for the number of times that it missed with no motion?

unsigned long motiontime;          // the motion timer
unsigned long motionINTERVAL = 1000UL * 60UL * 60UL;  // How often to report motion

void setup() {
  motiontime = millis(); // Sets motiontime to curent time at system startup
}

void loop() {
  //------------Motion Detection------------
  //If Motion is detected send Text
  int motionState = digitalRead(MotionPin);
  if (motionState == HIGH && (millis() - motiontime) > motionINTERVAL)
  {
    motiontime = millis();// reset timer by moving it along to the next interval
    digitalWrite(ledMotionSMSPin, HIGH);
    mySerial.println("AT + CMGS = \"+1512202xxxx\"");
    delay(100);
    mySerial.println("Motion has been detected!");//the content of the message
    delay(100);
    mySerial.println((char)26);//the ASCII code of the ctrl+z is 26
    delay(100);
    mySerial.println();
    digitalWrite(ledMotionSMSPin, LOW);
  }
}  //END OF LOOP

I didn't add a state change yet

Then you are wasting your time and ours.

How would that be wasting time. Am I wrong in thinking that when the loop cycle hits this section of code if the state of that input is HIGH it will match the if statement?

No, you're not wrong.
Ask yourself how often it matches the if condition.

It should match only when the PIR is high and with the time check it should match no more than once per hour. Is this not correct? Typically days will go by with no one in the house so when someone enters the PIR will be HIGH and it will be past an hour from the last time it tripped so it should send 1 SMS right away.

The original sketch in post #8 works and sends 1 SMS only once per hour if motion is detected at every hour interval but if no motion is detected for days it sends tons of SMSs in a row once motion is detected. That what I'm trying to cure is so no mater how long no motion has been detected once motion is detected I only get 1 SMS.