Delay On Delay Off Timing With Leds

Hello Friends, I have been trying to implement delays in the following code but the delays are not working as expected. The code does the same on Proteus and on Arduino Hardware.

I want if the analogValue1 goes below <512
"led1" will delay 5 seconds before coming on and consequently, "deviceStatus0 = 1; "

If the analogValue2 goes below <512
"led2" will delay 5 seconds before coming on and consequently, "deviceStatus1 = 1;"

If analogValue1 is >512
"led1" will go off without delay and "deviceStatus0 = 0;

If analogValue2 is >512
"led2" will delay 5 seconds before going off and "deviceStatus1 = 0;

Now I see that none of the delays are consistence. From reset, the delayOn0 and delayOn1 are accurate but once the conditions are changed they are no longer consistence. The delayOff is the worst of all, it does not work unless I comment the delayOn0 and delayOn1 functions.

The "led3" functions very well.

Please can someone correct this code where I am wrong? I will appreciate every help from you all.

Thanks.

#define led1 7
#define led2 6
#define led3 5

int deviceStatus0;
int deviceStatus1;
unsigned long delayOn0 = 5000;
unsigned long delayOn1 = 5000;
unsigned long delayOff = 5000;
unsigned long timeNow0 = 0;
unsigned long timeNow1 = 0;
unsigned long timeoff = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
  int analogValue1 = analogRead(A0);
  int analogValue2 = analogRead(A1);

  if (analogValue1 < 512)

    if ((unsigned long)(millis() - timeNow0) > delayOn0) {
      timeNow0 = millis();
      digitalWrite(led1, 1); //led1 will delay 5 seconds before coming on
      deviceStatus0 = 1;
    }
  if (analogValue1 > 512)
  {
    digitalWrite(led1, 0); //led1 will go fff without a delay
    deviceStatus0 = 0;
  }
  if (analogValue2 < 512)

    if ((unsigned long)(millis() - timeNow1) > delayOn1) {
      timeNow1 = millis();
      digitalWrite(led2, 1); //led2 will delay 5 seconds before coming on
      deviceStatus1 = 1;
    }

  if (analogValue2 > 512)

    if ((unsigned long)(millis() - timeoff) > delayOff) {
      timeoff = millis();
      digitalWrite(led2, 0); //led2 will delay 5 seconds before going off
      deviceStatus1 = 0;
    }


  if (deviceStatus0 == 0 && deviceStatus1 == 0) {
    digitalWrite(led3, 0);
  }
  if (deviceStatus0 == 1 && deviceStatus1 == 1) {
    digitalWrite(led3, 1);
  }
  if (deviceStatus0 == 1 && deviceStatus1 == 0) {
    digitalWrite(led3, 1);
  }
  if (deviceStatus0 == 0 && deviceStatus1 == 1) {
    digitalWrite(led3, 1);
  }

}

Please don't use the extra cast, that makes it seem as if something needs to be fixed. If there was really something that needed to be fixed, then the code would be wrong.

if ((unsigned long)(millis() - timeoff) > delayOff)  // confusing
if ((millis() - timeoff) > delayOff)                 // okay
if (millis() - timeoff > delayOff)                   // okay
if (millis() - timeoff >= delayOff)                  // this is what I use

The millis-timer should be activated (or call it "started" or "triggered") when a certain condition is met. Then the millis-timer should run on its own in the main level of the loop().

void loop()
{
  if (a certain condition)
  {
    activate the millis-timer
  }

  run millis-timer (only if it was activated)
}

You can try my Fun with millis examples directly in the Wokwi simulator. Have a look at millis_single_delay.ino

According to the reference, the digitalWrite() second parameter is HIGH or LOW, not 1 or 0.

I have made some changes but the timers are still not consistence. I just don't know where the glitch is in the code

#define led1 7
#define led2 6
#define led3 5

int deviceStatus0;
int deviceStatus1;
unsigned long delayOn0 = 5000;
unsigned long delayOn1 = 5000;
unsigned long delayOff = 5000;
unsigned long timeNow0 = 0;
unsigned long timeNow1 = 0;
unsigned long timeoff = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
  
  int analogValue1 = analogRead(A0);
  int analogValue2 = analogRead(A1);

  if (analogValue1 < 512)
    {  
    if (millis() - timeNow0 >= delayOn0) {
      timeNow0 = millis();
      digitalWrite(led1, HIGH); //led1 will delay 5 seconds before coming on
      deviceStatus0 = 1;
    }}
  if (analogValue1 > 512)
  {
    digitalWrite(led1, LOW); //led1 will go fff without a delay
    deviceStatus0 = 0;
  }
  if (analogValue2 < 512)
    
    { 
    if (millis() - timeNow1 >= delayOn1) {
      timeNow1 = millis();
      digitalWrite(led2, HIGH); //led2 will delay 5 seconds before coming on
      deviceStatus1 = 1;
    }}

  if (analogValue2 > 512)
    {
    if (millis() - timeoff >= delayOff) {
      timeoff = millis();
      digitalWrite(led2, LOW); //led2 will delay 5 seconds before going off
      deviceStatus1 = 0;
    }}


  if (deviceStatus0 == 0 && deviceStatus1 == 0) {
    digitalWrite(led3, 0);
  }
  if (deviceStatus0 == 1 && deviceStatus1 == 1) {
    digitalWrite(led3, 1);
  }
  if (deviceStatus0 == 1 && deviceStatus1 == 0) {
    digitalWrite(led3, 1);
  }
  if (deviceStatus0 == 0 && deviceStatus1 == 1) {
    digitalWrite(led3, 1);
  }

}

Start a millis-timer and let the millis-timer run in the main level in the loop().

You have this:

void loop()
{
  if (analogValue1 < 512)
  {  
    do something with millis
  }
}

But you need to do this:

void loop()
{
  if (analogValue1 < 512)
  {  
    start/activate millis-timer
  }

  run millis timer (only if it was activated)
}

Check out my tutorial on How to write Timers and Delays in Arduino which include a milisDelay class that keeps track of if the timer is running or not.
Also look at my tutorial on Multi-tasking in Arduino which can help with organizing your code into separate tasks controlled by timers.

After applying the millisDelay, It does the same thing, Please can you correct this in my code. Does it means that all these Millis of a thing are just designed for blinking LEDs? Every example I see is for the LED blinking.

I was working with PIC with CCS C compiler and I Use these types of delays in several places in the While Loop using timer0 and they all work as proposed but since I started working with Arduino I have not successfully applied this type of delay. I will post a snippet of the timer0 delay code i made using that platform to know if someone here can guide me how to use Arduino timer to do the same.

Here my modifications using millisDelay library in Safestring;

#include <millisDelay.h>

#define led1 7
#define led2 6
#define led3 5

int deviceStatus0;
int deviceStatus1;

millisDelay ledDelay1;
millisDelay ledDelay2;
millisDelay ledDelay3;
void setup() {
  // initialize the digital pin as an output.
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  digitalWrite(led1, LOW); // turn led1 oFF
  digitalWrite(led2, LOW); // turn led2 oFF
  digitalWrite(led3, LOW); // turn led3 oFF
  
  ledDelay1.start(5000);
  ledDelay2.start(5000);
  ledDelay3.start(5000);
}
void loop() {

  int analogValue1 = analogRead(A0);
  int analogValue2 = analogRead(A1);

//**********************************************************************
  if (analogValue1 < 512)

    if (ledDelay1.justFinished()){   
      digitalWrite(led1, HIGH); //led1 will delay 5 seconds before coming on
      deviceStatus0 = 1;
    }

//*******************************************************************
  if (analogValue1 > 512)
  {
    digitalWrite(led1, LOW); //led1 will go fff without a delay
    deviceStatus0 = 0;
  }

//*****************************************************************+  
  if (analogValue2 < 512)
  
  
    if (ledDelay2.justFinished()) {
      digitalWrite(led2, HIGH); //led2 will delay 5 seconds before coming on
      deviceStatus1 = 1;
    }

//*********************************************************************

  if (analogValue2 > 512)

      
    if (ledDelay3.justFinished()) {
      digitalWrite(led2, LOW); //led2 will delay 5 seconds before going off
      deviceStatus1 = 0;
    }



  if (deviceStatus0 == 0 && deviceStatus1 == 0) {
    digitalWrite(led3, LOW);
  }
  if (deviceStatus0 == 1 && deviceStatus1 == 1) {
    digitalWrite(led3, HIGH);
  }
  if (deviceStatus0 == 1 && deviceStatus1 == 0) {
    digitalWrite(led3, HIGH);
  }
  if (deviceStatus0 == 0 && deviceStatus1 == 1) {
    digitalWrite(led3, HIGH);
  }

}

This particular function:

  ledDelay1.start(5000);
  ledDelay2.start(5000);
  ledDelay3.start(5000);

I wondered why it will appear only in the setup, I thought it will appear somewhere in the "if" statement in the loop. Though I have manipulated it many places in the Loop but still, all to no avail.

Like this maybe ?

if (ledDelay1.justFinished())

But it is like that in my code:

//**********************************************************************
  if (analogValue1 < 512)

    if (ledDelay1.justFinished()){   
      digitalWrite(led1, HIGH); //led1 will delay 5 seconds before coming on
      deviceStatus0 = 1;
    }

//*******************************************************************

That was my point. The check does appear in your code but you start() the delay in setup.

Don't you want to start the delay when the input condition is met, not in setup()

I have modified it in many ways and it is still not working. I don't even know if millis() is designed for this type of delay

millis() is perfect for what you say you want to do but personally I would ditch the use of the library and do it in your own code so that you have full control over how it works

See Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

1 Like

Hello
I guess you need a time handler providing the follwing functions timerEvent(); , startTimer(); and eventuell a function stopTimer();

Please can write a small sample code here on how to implement it.

Some like a library and some like to use millis() directly.
What do you prefer ?

@drmpf has his "BasicSingleShotDelay.ino" which is the same as my "millis_single_delay.ino". Then drmpf went further and shows on his site the same thing with his library. You can test my sketch in the Wokwi simulator: https://wokwi.com/arduino/projects/299333522927125002.

I will like to use millis() directly so that I will learn and understand how it works

1 Like

As I said before, start a millis-timer and let it run on its own. The millis-timer should run in the main level of the loop().

So you have two parts, one part starts/enables/activates the millis-timer.
The other part is the millis-timer.

The easiest way to control a millis-timer is with a boolean variable.
@drmpf has: bool delayRunning = false;
and I have: bool enabled = false;

I am studying this now. Overall, I am new to coding and all I have done in coding I did with PIC and CCS C for PIC. I just decided to do some certain things in Arduino and everything seems already made. In PIC every setup is made right there in the code which also make it harder and complex. But here in Arduino I found out that many functions are already written somewhere in the IDE which makes it easier to use but no matter how easy it is, the easiest thing one can't solve is harder than the hardest thing one knows how to do. I am going through the link in post #17 and I am noticing something there right now.

I'm giving up, no matter what I do and how I do it, the best I could get never gets better than what I already got. If I apply the delay on only on pin, it works.

Does this help?

// Runs on an UNO

// A basic timer that runs when enable is true, else is reset.

// Demonstrates:
// millis() timer operation
// sensing/indicating timer completion
// doing more than one thing at a time

// THIS Version puts the starting display in loop() for variable passing example


uint32_t const timer1Preset = 1500; // 1.5 seconds
uint32_t timer1PreviousMillis;
uint32_t timer1CurrentMillis;
bool timer1TimedOut;
bool firstPass;

const byte enablePin = A3; // A0-A5 can be used as digital inputs
//
//-----------------------------
//
void setup() {
  Serial.begin(115200);
  pinMode(enablePin, INPUT_PULLUP); // INPUT_PULLUP avoids the need for a discrete resistor.
  pinMode(LED_BUILTIN, OUTPUT);
  firstPass = true;
}

void loop() {
  if (firstPass) {
    Serial.print("\n\nTimer  Timer\n");
    Serial.println(" Acc   Done");
    displayFunction(timer1CurrentMillis - timer1PreviousMillis, timer1TimedOut);
    delay(6000); // Pause for user to see column headings
    firstPass = false;
  }
  bool buttonPressed = (bool) !digitalRead(enablePin); // check button state before proceeding
 
  timer1CurrentMillis = millis(); // Take a snapshot of millis() to use for processing.

  if (buttonPressed) { // If input is grounded, enable timer to run.
    // Set the timer's completion status
    if (timer1CurrentMillis - timer1PreviousMillis >= timer1Preset) {
      timer1TimedOut = true;
    }
  }
  else {  // If timer not enabled it is reset
    timer1PreviousMillis = timer1CurrentMillis; // Reset the timer.
    timer1TimedOut = false;
  }
  //
  // End of timer1 update activities
  //
  digitalWrite(LED_BUILTIN, timer1TimedOut);  // Send timer1's completion status to the onboard LED

  displayFunction(timer1CurrentMillis - timer1PreviousMillis, timer1TimedOut);
} // end of loop

//--------------------------------------------

void displayFunction(uint32_t timer1, bool timedOut) {

  // Display runtime values passed from caller
  Serial.print(timer1);
  Serial.print("\t");
  Serial.print(timedOut);
  Serial.println();
}

I will check this out