Push button on = light only on for 5 seconds Millis

Hello,

I am trying to control some LED lights in my garden, I am wanting the lights to come on when its dark for a few hours then go off around midnight (after say 3 hours)

so in short:
if darksensor is on = led lights on
if darksensor is on and its been 3 hours = LED light off
if darksensor is off = LED light off

my trial code is below, but it is doing the oposite , while the button is pressed the led is on, when i release the PB the led stays on for 5 seconds , im wanting it to stay on only for 5 seconds while the pb is pressed then turn off . It has to be millis as i have several other things going on also

  // Task 2 : Glow LED2 when BTN is pressed
  if (digitalRead(BTN)){ 
    if(currentTime - prevTime_T4 >= interval_T4) {
   
    digitalWrite(LED2, LOW);
     prevTime_T4 = currentTime;
  }
  }
    else {
            digitalWrite(LED2, HIGH);
            }

Use a Flag to enable/disable code sections.

When events are met, Set the Flag, start a TIMER.

When the Flag is set, check to see if the TIMER has expired.

Welcome to the forum.

Having something active during 3 hours is no problem, millis() can go up to 30 days.
A millis-timer runs on its own in the loop(). You need to code to start the millis-timer and code for the millis-timer itself.

Use a flag as LarryD wrote. I call that variable "enable" here: millis_single_delay.ino

What if a cat walks by the light sensor and the sensor thinks it is dark for a few seconds ?
Is there a button as well ? or does the button simulate the light sensor ?
I assume that "PB", and "pb" and "BTN" and "button" are all the same thing :grimacing:

Only part of it. Please post the entire sketch you are talking about. It may be that you are closer than you think. Hard to tell from a few lines isolated.

a7

1 Like

Hello all, and thank you very much for your input, I have tried what you recomended and although the code is cleaner , it is still doing the same. When I press the BTN it brings the LED on, BUT the LED stays on while the BTN is pressed, I am wanting the LED to turn off after 5 seconds , even if the BTN is being pressed at the same time

#define LED1 13
#define LED2 12
#define LED3 11

#define BTN 4

// set LED states
int LED1_state = LOW;
int brightness = 0;

// previous time for the tasks depending upon time.
unsigned long prevTime_T1 = millis(); 
unsigned long prevTime_T4 = millis(); 

// time intervals for the tasks
long interval_T1 = 1000; // blink every 1 second
long interval_T4 = 5000; // print brightness of LED3 every 5 seconds
bool enabled = false;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(BTN, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  unsigned long currentTime = millis();
 
  // Task 1 : Blink LED1 (T1)
  if (currentTime - prevTime_T1 > interval_T1) {
    LED1_state = !LED1_state;
    digitalWrite(LED1, LED1_state);

    prevTime_T1 = currentTime;
  }

  // Task 2 : Glow LED2 when BTN is pressed
if( digitalRead(BTN) == LOW)  // low is active
  {
    digitalWrite(LED2, HIGH);  // turn on led
    prevTime_T4 = currentTime;
    enabled = true;        // turn on software timer
  }
   
  if( enabled)      // software timer is active ?
  {
    if(currentTime - prevTime_T4 >= interval_T4)
    {
      digitalWrite(LED2, LOW);  // turn off led
      enabled = false;     // stop software timer
    }


  }

Tell us who created this programme.

I did based on different sources I have come along

look this over

#define LED1 13
#define LED2 12
#define LED3 11

#define BTN 4

byte btnLst;

unsigned long msecPeriod;
unsigned long msecLst;

// -----------------------------------------------------------------------------
enum { Off = HIGH, On = LOW };
void
turnLeds (byte val)
{
    digitalWrite (LED1, val);
    digitalWrite (LED2, val);
    digitalWrite (LED3, val);
}

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();

    // timer
    if (msecPeriod && msec - msecLst >= msecPeriod) {
        msecPeriod = 0;
        turnLeds (Off);
    }

    // chek for trigger
    byte btn = digitalRead (BTN);
    if (btnLst != btn)  {
        btnLst = btn;
        delay (20);     // debounce for mechanical device

        if (LOW == btn)  {
            msecPeriod = 5000;
            msecLst    = msec;
            turnLeds (On);
        }
    }
}

// -----------------------------------------------------------------------------
void setup () {
    // put your setup code here, to run once:
    Serial.begin (9600);

    pinMode (LED1, OUTPUT);
    pinMode (LED2, OUTPUT);
    pinMode (LED3, OUTPUT);
    turnLeds (Off);

    pinMode (BTN, INPUT_PULLUP);
    btnLst = digitalRead (BTN);
}

It's right in your code. When the button is pressed.

So you need to learn about and employ "state change detection".

There's an example in the IDE

 Examples/02.Digital/StateChangeDetection

The basic idea of it is to do something when the button goes from not pressed to pressed, or as we say here when it becomes pressed, rather than to do that same something beside the button is (maybe still) pressed.

So you launch the thing only when you first hit the button.

HTH

a7

I understand the button is simulating the day/night sensor, and pressed = LOW means dark = start led for specified time.
Your description does not tell anything about other leds, but it is slways good to create non-blocking expandable code.

#define LED1 13

#define BTN 4
#define BTN_MODE INPUT_PULLUP
#define ACTIVE LOW

unsigned long startTime_T1;  // frozen while dark, to measure duration

// time interval for the task
const unsigned long interval_T1 = 5000; // led duration, if button is still pressed

void setup() {
  Serial.begin(9600);
  pinMode(LED1, OUTPUT);
  pinMode(BTN, BTN_MODE);
}

void loop() {
  // Task : When BTN is pressed glow LED1 for some time
  if( digitalRead(BTN) == ACTIVE)  {
    bool state = millis() - startTime_T1 < interval_T1;
    digitalWrite(LED1, state );  // eventually turn on led
  } else { 
    startTime_T1 = millis(();  // prepare to be ready when BTN ACTIVE
    digitalWrite(LED1, LOW );  // certainly turn off led
  }
  // other tasks are possible here...
}   

After fixing this syntax error, I find:

The LED is on when you press the button. If you get off the button in less than 5 seconds, the LED goes out. If you stay on the button, the LED shuts off after 5 seconds.

If you've let the time run out, you'll get a brief flash of the LED when you let go the button. Switch bounces get caught.

That may be a solution.

If you employ debouncing, as did @gcjr in #8 above, you get one five second burst of light for every press of the button. Presses during the five second period re-initialise the timer; the LED will extinguish 5 seconds after the last time the button was seen going down.

"state change detection", which in the example includes "poor man's debouncing" viz:

    // Delay a little bit to avoid bouncing
    delay(50);

and would behave the same. @gcjr's code has a state change detector right there:

    if (btnLst != btn)  {

HTH

a7

The button simulates the dark period. If you release the button too early, the led shuts off immediately. That's intended.

That's a flaw indeed. Interesting, that such a short bouncing time creates a visible flash.

I see. THX.

I think, however, that may not be the best choice. If an LDR is used to detect the dark period, it would benefit from a harder test.

At the fall of dusk (!), there will likely be a longish period of reporting dark and not dark alternately.

Maybe: turn on the LED at any indication of darkness, for a predetermined short time without regard to the new reading or even taking one, then decide on a reading whether to renew the possible transition process to darkness. After a long enough period of finding darkness every so often, then conclude it is dark and turn the LED on for the long desired on period.

At least then false dusks and transitional oscillations would not mean annoying or undesired rapid frequent turnings in and off.

If the LDR is in a closet, it's a way to go. But for "dawn to dusk because the planet" is turning kinda stuff the OP is suggested to consider using an RTC and algorithm to "know" that's it's nighty night for realz.

a7

Morning this works a treat the only problem I dont understand the code fully, more reading and homework for me

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