carduinomotioninfraredsensors

Arduino - PIR motion sensor code without using delay()


I have an Arduino set up with multiple sensors printing to serial port. Initially, I had the PIR sensor implemented with several delays built in so it would not spam the motion detected message. However, the delay() function, of course, pauses the whole code and interferes with the other sensors.

What I want to do:

1)When the motion sensor is high for x amount of time, print ONE message to the serial

2)Insert a brief period of time here where it does not detect motion

3)If the motion sensor is high for time < x it does nothing

The general idea being to use software to minimize false positives as well. I've been trying to use the millis() function to control it, but haven't had much success. Its probably a really simple solution and I'm just not seeing it.

void loop() {

  // Get value from motion sensor
  pirValue = digitalRead(pirPin);  //detectedPin
  // See if motion Detected
  unsigned long currentMillis = millis();

  if (pirValue == 1 && (currentMillis - previousMillis >= interval) ){
    previousMillis = millis();

    // Display Triggered LED for 3 seconds
    digitalWrite(detectedLED, HIGH);
    motionDetected = 1;
    Serial.println("motion detected");
    //delay(3000);

  } else {
    digitalWrite(detectedLED, LOW);
  }

I know this is absolutely wrong, as I think the way its set now the loop will never get entered. I've tried several other structures, but I'm not seeing what I need to do. Is this a situation where I'd need to construct a state machine essentially? Any help thinking through this would be appreciated!


Solution

  • You're close. You just need to set previousMillis somewhere. So what's the start point of your timing? It's when the PIR sensor first detects motion. Right? Or put another way, you want to time from the last time that it didn't detect motion. So just add a line so that if the PIR doesn't see any motion then it sets previousMillis to millis(). That way whenever it does pick up motion previousMillis will have the last time where it didn't.

    void loop() {
    
      // Get value from motion sensor
      pirValue = digitalRead(pirPin);  //detectedPin
      // See if motion Detected
      unsigned long currentMillis = millis();
      if (pirValue == LOW) {
        previousMillis = millis();
      }
    
      if (pirValue == HIGH && (currentMillis - previousMillis >= interval) ){
    
        // Display Triggered LED for 3 seconds
        digitalWrite(detectedLED, HIGH);
        motionDetected = 1;
        Serial.println("motion detected");
        //delay(3000);
    
      } else {
        digitalWrite(detectedLED, LOW);
      }
    

    You don't want to set previousMillis where you have it now. Because that would start you timing from that point. This would lead to you getting a "motion detected" every interval milliseconds since you're basically starting the timing over every time you print that.