1

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);
}
3
  • 1
    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.
    – st2000
    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. Nov 13, 2019 at 22:48
  • What type of light are you blinking to activate the photoresistors?
    – VE7JRO
    Nov 13, 2019 at 23:06

3 Answers 3

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 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:

state transitions

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;
    }
}
2

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>
    }
}
0

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);
  }
}
3
  • 1
    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, 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
    Nov 15, 2019 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, 2019 at 16:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.