MillisDelay 230624 with

Hello Arduino Form,

Working on turning on several lights with a motion detector (PIR HC-SR501).

Had been relying on the variable pot on the PIR to turn the lights off when
the PIR stopped sending a signal but
the pots are pretty crude and it would be good if the lights stayed on
approx. the same amount of time. Some ideas on how to time several
events were found at:
Timing without using Delay()

The sketch copied herewith below marked '/* Simple MillsDelay, One LED */' works and
is tested on the PCB.

The next step is to have the PIR trigger turn the light on and have MillisDelay function turn the light off.

The sketch copied below marked '/* Simple MillsDelay, One LED */' works and
is tested normal on the PCB.

The sketch copied below the 'Simple' sketch marked 'MIllisDelay_1_PIR_1_LED_Pin2_230624' is an attempt to add reading a value from the PIR input and then using the
'delayRunning1 && ((millis() - delayStart1' constuct to turn on the light to turn
on the light for the time spec;d in DELAYTIME1.
Have tried several versions. The one posted below seems to just ignore
the PIR because it just blinks the light on and off.

If someone could give me an idea about how to how to make the PIR operate with
the MillisDelay function it would be most appreciated.
Thanks.
Allen Pitts

/* Simple MillsDelay, One LED */
#include <millisDelay.h>
int led1 = 2;

unsigned long DELAY_TIME1 = 1000;  // 1.5 sec
unsigned long delayStart1 = 0;     // the time the delay started
bool delayRunning1 = false;        // true if still waiting for delay to finish

bool ledOn1 = false;  // keep track of the led state

void setup() {
  pinMode(led1, OUTPUT);    // initialize the digital pin as an output.
  digitalWrite(led1, LOW);  // turn led off
  ledOn1 = false;

  // start delay
  delayStart1 = millis();
  delayRunning1 = true;
}

void checkToggleLed1() {       // led task
                               // check if delay has timed out
     if (delayRunning1 && ((millis() - delayStart1) >= DELAY_TIME1)) {
      delayStart1 += DELAY_TIME1;  // this prevents drift in the delays
      // toggle the led
      ledOn1 = !ledOn1;
      if (ledOn1) {
        digitalWrite(led1, HIGH);  // turn led on
      } else {
        digitalWrite(led1, LOW);  // turn led off
      }
    }
  }
void loop() {
  checkToggleLed1();  // call to toggle led based on timer
}

MIllisDelay_1_PIR_1_LED_Pin2_230624*

/***************************************************
MIllisDelay_1_PIR_1_LED_Pin2_230624
code and ideas on using the millis() function instead of delay() come from
https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
https://roboticsbackend.com/how-to-do-multitasking-with-arduino/
https://www.instructables.com/Simple-Multi-tasking-in-Arduino-on-Any-Board/
*/

#include <millisDelay.h>
int led1 = 2;
int PIRA5 = A5;

int valA5 = 0;

unsigned long DELAY_TIME1 = 1000;  // 1.5 sec
unsigned long delayStart1 = 0;     // the time the delay started
bool delayRunning1 = false;        // true if still waiting for delay to finish

bool ledOn1 = false;  // keep track of the led state

void setup() {
  pinMode(led1, OUTPUT);    // initialize the digital pin as an output.
  digitalWrite(led1, LOW);  // turn led off
  ledOn1 = false;
  pinMode(PIRA5, INPUT);


  // start delay
  delayStart1 = millis();
  delayRunning1 = true;
}

void checkToggleLed1() {       // led task
     // check if delay has timed out
  valA5 = digitalRead(PIRA5);  // read input value
  if (valA5 == HIGH) {         // check if the input is HIGH
    if (delayRunning1 && ((millis() - delayStart1) >= DELAY_TIME1)) {
      delayStart1 += DELAY_TIME1;  // this prevents drift in the delays
      // toggle the led
      ledOn1 = !ledOn1;
      if (ledOn1) {
        digitalWrite(led1, HIGH);  // turn led on
      } else {
        digitalWrite(led1, LOW);  // turn led off
      }
    }
  }
}
void loop() {
  checkToggleLed1();  // call to toggle led based on timer
}

Hello,

Here is an example t1141348 - Wokwi ESP32, STM32, Arduino Simulator

code that demonstrates a certain functionality is good.
IMHO For beginners two things are important:

  1. really self-explaining variable names where the names are chosen in a way that the variable-names almost create a normal-worded sentence
  2. explaining comments are added

This is contradictionary how "professional" coders write code

For sure! A program that shall "professionally" explain how the code works has a different aim than code that shall "professionally" just work.

This is what this WokSim is doing

best regards Stefan

So one thing about the simulations, they don't account for resetting everything if the motion stops and then resumes while light is already on. Basically if the person stands still for a few seconds you don't want to kill the lights.

Set your sensor to whatever you think a good time delay is (I just set it to the minimum pot setting) and make sure it is jumpered for continuous mode. Then use a State Machine code model as has been suggested. Here is a simple first pass with not much frill:

// Sketch simulates turning a  light on or off based on motion sensor using the onboard LED as the light

const int LED_PIN = 13;  // LED on Pin 13 of Arduino
const int PIR_PIN = 7; // Input for HC-S501

//Defines for sensor states to make switch logic clear
#define noMotionDetected LOW
#define motionDetected HIGH

//Define elapsedMillis to read a value of millis and subtract the millis reading from when the timer was fist started
#define elapsedMillis millis() - startTimeMillis

//Declare a const for the light off delay value in millis once no motion is detected
const int LIGHT_OFF_DELAY = 5000;

//Declare variables
unsigned long startTimeMillis = 0;
int pirValue = 0;
bool isLightOffTimeActive = false;
bool isLightOn = false;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(PIR_PIN, INPUT); 
  digitalWrite(LED_PIN, LOW);
  Serial.begin(9600);
}

void loop() {

  //Read the current sensor value
  pirValue = digitalRead(PIR_PIN);

  switch(pirValue)
  {
      case motionDetected:
        //An LED you could just always turn on every loop but real lights you probably don't want to pulse the switch
        //so use a boolean 
        if(!isLightOn)
        {
          digitalWrite(LED_PIN, HIGH);
          isLightOn = true;
        }
        // Time flag could be active because a person was moving then stood still then moved again. 
        // As long as we have motion, reset the time flag to keep the lights on
        isLightOffTimeActive = false;
        break;

      case noMotionDetected:
        //If both isLightOn and !isLightOffTimeActive this is our first pir LOW after motion so start the time
        if((isLightOn) && (!isLightOffTimeActive))
        {
            isLightOffTimeActive = true;
            startTimeMillis = millis();
        }
        else
        {
            //If light is on also evaluate the timer
            if((isLightOn) && (elapsedMillis >= LIGHT_OFF_DELAY))
            {
              // Turn off light and reset
              digitalWrite(LED_PIN, LOW);
              isLightOn = false;
              isLightOffTimeActive = false;
              startTimeMillis = 0;
            }
            // Else do nothing, sensor is LOW but either time has not elapsed yet or time flag and light are off.
        }
        break;

        default:
            //Should not hit this but do nothing
            Serial.println("Hit default");
            break;

  }

}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.