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);
}
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.
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
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.
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
}
}
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.
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...
}
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:
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.