I am trying to write a code where photoresistors (a or b) sense blinking of the light, and lights LED (k and d) simultaneosly with that blinking. And I want that when both photoresistors sense dark for more than 3 secs, the LEDs would light up and stay until one of them again gets lighting. But I cannot understand in which part should I put millis time count?
int k = 2;
int d = 3;
int fk = A0;
int fd = A1;
int a = 0;
int b = 0;
void setup() {
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
Serial.begin(9600);
}
void loop()
{
a = analogRead (fk);
b = analogRead (fd);
while (a < 1000 && b < 1000)
{
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
a = analogRead (fk);
b = analogRead (fd);
}
if (a > 1000)
digitalWrite(2, HIGH);
else
digitalWrite(2, LOW);
if (b > 1000)
digitalWrite(3, HIGH);
else
digitalWrite(3, LOW);
}
-
1Did you say photo resistors & blinking lights?? Keep in mind that photo resistors have an odd valance band. Specifically, photo resistors will conduct current when lights go on and will continue to conduct current after lights go off for perhaps a second or more. So if you lights are blinking fast enough, you will never detect the lights going off with photo resistors.st2000– st20002019年11月13日 22:45:19 +00:00Commented Nov 13, 2019 at 22:45
-
Bilnks are in 1sec interval, I have already tested that, everything works, I'm just stuck with that timing.Ieva Kriščiūnaitė– Ieva Kriščiūnaitė2019年11月13日 22:48:23 +00:00Commented Nov 13, 2019 at 22:48
-
What type of light are you blinking to activate the photoresistors?VE7JRO– VE7JRO2019年11月13日 23:06:50 +00:00Commented Nov 13, 2019 at 23:06
3 Answers 3
This is one of those cases where the solution is simply to implement a finite state machine. Consider a state machine with these three states:
LIGH
: light has been detected by at least one of the sensors, the LEDs follow the light sensorsSHORT_DARK
: neither sensor sees light, both LEDs are offLONG_DARK
: it has been at least three seconds since neither sensor saw light, both LEDs are on.
The transitions between those states can be depicted by the following state diagram:
where "darkness detected" means that no sensor sees light, and "light detected" means that at least one sensor sees light.
As a general rule, it is a good practice to always draw a state diagram before you start writing code. Once you are sure your diagram describes the desired behavior, it is almost trivial to translate it into code. Here is how I would code it:
void loop()
{
bool light_k = analogRead(IN_K) >= 1000;
bool light_d = analogRead(IN_D) >= 1000;
static enum { LIGHT, SHORT_DARK, LONG_DARK } state;
static uint32_t darkness_start;
switch (state) {
case LIGHT:
digitalWrite(OUT_K, light_k ? HIGH : LOW);
digitalWrite(OUT_D, light_d ? HIGH : LOW);
if (!light_k && !light_d) {
darkness_start = millis();
state = SHORT_DARK;
}
break;
case SHORT_DARK:
if (light_k || light_d) {
state = LIGHT;
} else if (millis() - darkness_start >= 3000) {
digitalWrite(OUT_K, HIGH);
digitalWrite(OUT_D, HIGH);
state = LONG_DARK;
}
break;
case LONG_DARK:
if (light_k || light_d) {
state = LIGHT;
}
break;
}
}
Millis gives you a measure of time. You can store that measure and compare to it later. I don't know what in your code represents a sense of dark/light in your code (resistors can be used to raise or lower the measured input depending on your circuit) so you will have to work the following in by replacing stuff in <>
unsigned long lastlight;
void loop()
{
if (<isLitSensorA>) lastlight = millis();
if (<isLitSensorB>) lastlight = millis();
if(millis() - lastlight > 3000){ //3 sec since lastlight
<LightsAlwaysOn>
}
else{
<BlinkWithLights>
}
}
Here is a more elegant way to do this. This program doesn't require you to actually count it has been dark, instead it just remembers the time it has last seen the light (how poetic ;). I also added some commentary alongside the code.
// All the variables
int k = 2; // LED 1
int d = 3; // LED 2
int fk = A0; // photoresistor 1
int fd = A1; // photoresistor 2
int lastLight = 0;
// Set up the LEDs
void setup() {
pinMode(k, OUTPUT);
pinMode(d, OUTPUT);
}
void loop()
{
// Check the photoresitors
int a = analogRead (fk);
int b = analogRead (fd);
if (a > 1000 || b > 1000)
{
// Turn LEDs on if one photoresitor senses light
digitalWrite(k, HIGH);
digitalWrite(d, HIGH);
// Also set the last time it was bright to the current time
lastLight = millis();
}
else if (abs(millis() - lastLight) > 3000)
{
// Turn LEDs on if it has been dark for more than 3 seconds (that is 3000 milliseconds)
digitalWrite(k, HIGH);
digitalWrite(d, HIGH);
}
else
{
// Turn LEDs off
digitalWrite(k, LOW);
digitalWrite(d, LOW);
}
}
-
1Re "
if (lastLight < millis() - 3000)
": here you have a millis-rollover bug. It can be somehow mitigated byif (millis() - lastLight > 3000)
, but it will still fail if it stays dark for longer than the rollover period. AddinglastLight = millis() - 9000
within the if, or some kind of state variable, can fix that.Edgar Bonet– Edgar Bonet2019年11月14日 19:13:54 +00:00Commented Nov 14, 2019 at 19:13 -
Good point, I updated the answer to match that. However, using
if (millis() - lastLight > 3000)
will not change that. You can bypass the problem by using the absolute value of the difference (this way the LEDs stay dark even if a rollover occurs). I don't understand your suggestion though for the case that it stays dark for longer than 49.5 days.LukasFun– LukasFun2019年11月15日 14:32:33 +00:00Commented Nov 15, 2019 at 14:32 -
abs()
won't help, but you have to makelastLight
anunsigned long
. See millis() overflow ... a bad thing? and How can I handle the millis() rollover?. If it stays dark for longer than 49.7 days,millis()
will get very close tolastLight
, and this code will turn the LEDs off. That won't happen if you repeatedly changelastLight
to stay a few seconds behindmillis()
.Edgar Bonet– Edgar Bonet2019年11月15日 16:02:40 +00:00Commented Nov 15, 2019 at 16:02