# Time counting using millis

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()
{
while (a < 1000 && b < 1000)
{
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
}
if (a > 1000)
digitalWrite(2, HIGH);
else
digitalWrite(2, LOW);
if (b > 1000)
digitalWrite(3, HIGH);
else
digitalWrite(3, LOW);
}
``````
• Did 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. Nov 13 '19 at 22:45
• Bilnks are in 1sec interval, I have already tested that, everything works, I'm just stuck with that timing. Nov 13 '19 at 22:48
• What type of light are you blinking to activate the photoresistors? Nov 13 '19 at 23:06

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 sensors
• `SHORT_DARK`: neither sensor sees light, both LEDs are off
• `LONG_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{
}
}
``````

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
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);
}
}
``````
• Re “`if (lastLight < millis() - 3000)`”: here you have a millis-rollover bug. It can be somehow mitigated by `if (millis() - lastLight > 3000)`, but it will still fail if it stays dark for longer than the rollover period. Adding `lastLight = millis() - 9000` within the if, or some kind of state variable, can fix that. Nov 14 '19 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. Nov 15 '19 at 14:32
• `abs()` won't help, but you have to make `lastLight` an `unsigned 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 to `lastLight`, and this code will turn the LEDs off. That won't happen if you repeatedly change `lastLight` to stay a few seconds behind `millis()`. Nov 15 '19 at 16:02