how to create a state checker/timer

Hello Forum....

i dont exactly know how to explain this, and i have no experience programming with C or any other language other than Arduino. Ive used my Arduino for a while, but i set it aside for a good 6ish months and im starting to fiddle with it again. Im working on a project to use a Parallax Passive IR Sensor to tell an Arduino communicating with a Processing sketch to update my cat's Twitter status when he goes to eat.

absolutely pointless i know, but its fun.

thats why i use the Arduino, its fun in a nerdy way, which i love, and i learn while doing it and enjoy it. Ive just started getting into using Processing and i have some of my basic code written out, but i digress. On to the background behind my question.

BACKGROUND BEHIND QUESTION:

I have the Arduino reading a digital value, either HIGH or LOW from the PIR to determine whether there is motion. The data pin from the PIR is connected to digital pin 2. It reads a value from the PIR every 2 seconds. When the arduino reads a HIGH value it will output a "1" to the serial port. Just for ease of paying attention while keeping my cat from eating my cords, i also have it output a message "movement detected". Now, when it doesn't detect a HIGH value, it doesnt output anything.

Now i dont want to have my Twitter App overloaded with status updates, so i want to create a function/loop/statement (i dont know the correct term) that checks how long its been since the last time its received a HIGH value. The reason for this is the PIR, when it detects motion it turns on its own onboard red LED and it stays on for about 2-3 seconds, so for 2-3 seconds the serial port is receiving "1"s and "movement detected" messages. That means that if i finished this app everytime my cat went to eat there would be about 3 or 4 status updates in a row saying, im eating, which would be stupid. My question is....

QUESTION:

How can i create a function/loop/statement (i dont know the correct term) that checks how long its been since the last time its received a HIGH value, and depending on whether the function/loop/statement is true, it will output a message to the serial port?

Oh and here is my code for anyone who wants to review it....its simple and to the point.

int sensorPin = 2;    // select the input pin for motion sensor
int sensorValue = 0;  // variable to store the value coming from the sensor
int activationPin = 13; //light up a giant matte red LED when motion is detected for shits and giggles.
                                     
void setup() {
  Serial.begin(9600); 
  pinMode(activationPin, OUTPUT);
  pinMode(sensorPin, INPUT);
}

void loop() {
  
  sensorValue = digitalRead(sensorPin);    // read the input pin
  delay(2000);                                     // wait a bit
  
  if (sensorValue == HIGH) { 
    Serial.println("1");                           // data that will this trigger status update --> yummmm....nom nom time! =) - example status update sent by processing
    delay(1000);                                  //wait a bit
    Serial.println("movement detected"); // let me know movement was detected
    
    digitalWrite(activationPin, HIGH);     // light up an LED in case im busy
    delay(250);                                   // wait a bit
    digitalWrite(activationPin, LOW);     // turn off the LED
  }
  
  else (sensorValue == LOW ); {            // if the sensor value is low, dont do shit.
  }
}

Make an unsigned long variable the survives passes through the loop (so static or a global variable). Save the current time (gotten with millis()) to that variable. Then, when you want to know how long it has been, take the current time and subtract the variable from it.

void loop() {
  static unsigned long lastEatTime = 0;
  
  if (digitalRead(3)) {
    lastEatTime = millis();
  }

  Serial.print("It has been ");
  Serial.print(millis() - lastEatTime);
  Serial.println(" milliseconds since the cat has last eaten");

  if (millis() - lastEatTime > 1000UL * 60UL * 60UL * 4) { // four hours
    Serial.println("He must be getting hungry!");
  }
}

this is sort of what im looking for, but i want the variable to look at the state of the PIR sensor, and if its read a HIGH value within 3 seconds it wont update the twitter status. i think this code would definitely work i just dont understand how i would modify it to do what i just said.

i think this code would definitely work i just dont understand how i would modify it to do what i just said.

You'd also need to keep track of the last time you twitted. If the need to twit again arises when less than n seconds/minutes/hours have elapsed, don't twit.

yeah well i wouldn't necessarily need to read from twitter, i could just keep track of the last time i updated a status, and if its within the time specified like 10mins it shouldn't update it

i wouldn't necessarily need to read from twitter

I never said you would.

i could just keep track of the last time i updated a status, and if its within the time specified like 10mins it shouldn't update it

That's what I thought I said.

ah ok i misunderstood you. so how would i use that code that WizenedEE posted to check the time since the last update?

When you send an update, record the time using millis() when you want to check how long it's been since then, subtract the time recorded from millis() and you have the number of milliseconds it has been since the last update.

ok cool. so how would i do that?

The example above shows you how to both record the time, as well as compare the time since to a number.

ok so i think i have made some progress in incorporating this into my code....heres what i have please dont tear me a new one since its probably not right.

int sensorPin = 2;    // select the input pin for motion sensor
int sensorValue = 0;  // variable to store the value coming from the sensor
int activationPin = 13;
                                     
void setup() {
  Serial.begin(9600); 
  pinMode(activationPin, OUTPUT);
  pinMode(sensorPin, INPUT);
}

void loop() {
  
  sensorValue = digitalRead(sensorPin);    // read the input pin
  
  delay(2000);
  
  static unsigned long laststatusUpdate = 0;
  
  if (sensorValue == HIGH) { 
    
    if (millis() - laststatusUpdate > 1000UL * 60UL * 10) { // if the milliseconds - laststatusUpdate time is greater than 10 minutes
    
    Serial.println("1"); // update the twitter status by sending a 1 to the serial port to Processing
    
    Serial.println("movement detected");
    
    digitalWrite(activationPin, HIGH);
    
    delay(250);
    
    digitalWrite(activationPin, LOW);
    
    if (digitalRead(sensorPin)) {
    
    laststatusUpdate = millis();
    
  }
  
  } 

  }
  
  else (sensorValue == LOW ); {
    
  Serial.print("It has been ");
  Serial.print(millis() - laststatusUpdate);
  Serial.println(" milliseconds since the cat has last eaten");  
  } 
}
  sensorValue = digitalRead(sensorPin);
  ...
  if (sensorValue == HIGH) { 
    ...
    delay(250);
    
    if (digitalRead(sensorPin)) {
    ...

Why are you taking a second reading? Is it your intention that the sensorValue must be HIGH when you first read it AND a quarter second later for it to not repeat?

else (sensorValue == LOW );

else means that the sensor value is not HIGH. Because it's a digital pin, if it's not HIGH, it's LOW. There is no need to give it the condition of == LOW when that is already implied. I doubt it even works written that way.

I think what you want to do is to take my first snippet and use it to see if the sensor has been high for 3 seconds. Then, you make another variable to say when you last tweeted. When you see that it's been high for 3 seconds, check to see if it's been more than 10 minutes since the last tweet. If they're both true, tweet.

You can also when when the sensor was high for more than 3 seconds, save the current time and write the activationPin HIGH. Then if it's been 250 milliseconds since you wrote it HIGH, write it LOW.

void loop() {
  static unsigned long PIRstartTime = 0;
  static unsigned long lastTweetTime = 0;
  
  if (digitalRead(3)) {
    PIRstartTime = millis();
  }

  Serial.print("It has been ");
  Serial.print(millis() - lastEatTime);
  Serial.println(" milliseconds since the cat has last played");

  static unsigned long startActivationTime = 0;
  if (millis() - PIRstartTime > 3000UL) { // 3 seconds
    if (millis() - lastTweetTime > 1000UL * 60UL * 10UL) { // 10 minutes
      Serial.println("1");
    }
    digitalWrite(activionPin, HIGH);
    startActivationTime = millis();
  }
  
  if (millis() - startActivationTime > 250) {
    digitalWrite(activationPin, LOW);
  }
}

(Sorry if this is too much of an easy answer, I got excited)

@Arrch the only reason im reading it twice is when i didnt have it read it the first time in my code, it didnt work. and that second read was supposed to update the laststatusupdate variable so that it would update everytime a status has been updated.

@WizenedEE thats exactly what i wanted!

so now i just wish i understood how you did that. do you have any good links where they explain how to do it so i can do it on my own in the future?

actually that code doesn't exactly work the way i was thinking it would.....it still prints out multiple values to the serial bus...it doesn't just print out one. i dont know how to make it so if it receives a high value within 2500 ms it wont print out to the serial bus.

Oops -- I forgot to set lastTweetTime. You can probably figure out how/where to do that.

(Hint: You set it to the current time when you tweet)

Your cat has a Twitter account? I'm impressed. Mine doesn't, but he isn't that technologically savvy.

i think i figured it out....but what does the startActivationTime variable do?

int sensorPin = 2;    // select the input pin for motion sensor
int sensorValue = 0;  // variable to store the value coming from the sensor
int activationPin = 13;
                                     
void setup() {
  Serial.begin(9600); 
  pinMode(activationPin, OUTPUT);
  pinMode(sensorPin, INPUT);
}

void loop() {
  
  static unsigned long PIRstartTime = 0;
  static unsigned long lastTweetTime = 0;
  
  if (digitalRead(sensorPin)) {
    PIRstartTime = millis();
  }

  Serial.print("It has been ");
  Serial.print(millis() - lastTweetTime);
  Serial.println(" milliseconds since the cat has last ate");

  static unsigned long startActivationTime = 0;
  
  if (millis() - PIRstartTime > 2500UL) { // 3 seconds
    if (millis() - lastTweetTime > 1000UL * 60UL * 3UL) { // 3 minutes
      Serial.println("1");
      
      lastTweetTime = millis();
      
      digitalWrite(activationPin, HIGH);
      delay(250);
      digitalWrite(activationPin, LOW)
    }
    
    startActivationTime = millis();
  }
  
  if (millis() - startActivationTime > 250) {
    digitalWrite(activationPin, LOW);
  }
}

[quote author=Ryan J Blajda link=topic=114884.msg866334#msg866334 date=1342790559]
i think i figured it out....but what does the startActivationTime variable do?

It is a static variable, which means it retains its value from one call to loop to another. It tracks when the LED or whatever is on pin 13 was turned on, and turns it off 250 mili-seconds (1/4 second) after it was turned on.