How to get an LED to stay on for 5 seconds after a sensor has stopped being set off?

Good evening,

Juist need a little pointer to help with this personal project I'm working on.

I have a 2 TOF sensors, 2 RGB LED's and a small speaker. I have it currently setup in a way that the speaker gives off a tone and an LED Flashes (either red or green) when the sensor reading is below a certain value.

When the sensor is not being set off the LED's stay a blue colour. I would like the LED that was flashing to stay on for 5 seconds with either a green or red colour and then after that return to a solid blue colour.

Below is my code so far:

/*
Code for the yes/no device.
The Tone pin that will be used is Digital pin 3
RGB LEDs are also controlled once the sensor has been triggered
RGB Pins on LED1:
G=D11
R=D12
B=D13
Red colour is RGB(255, 0, 0) or #ff0000
Red colour is RGB(0, 255, 0) or #00ff00
Static orange colour for when sensor has not been set off RGB(255, 128, 0) or #ff8000
*/

#include <Wire.h>
#include <VL53L1X.h>

int redPinNo = 8;
int greenPinNo = 9;
int bluePinNo = 10;

int redPinYes = 12;
int greenPinYes = 11;
int bluePinYes = 13;

// The number of sensors in your system.
const uint8_t sensorCount = 2;

// The Arduino pin connected to the XSHUT pin of each sensor.
const uint8_t xshutPins[sensorCount] = { 6, 7 };

VL53L1X sensors[sensorCount];

void setup()
{
  
  pinMode(redPinNo, OUTPUT);
  pinMode(greenPinNo, OUTPUT);
  pinMode(bluePinNo, OUTPUT);

  pinMode(redPinYes, OUTPUT);
  pinMode(greenPinYes, OUTPUT);
  pinMode(bluePinYes, OUTPUT);

  while (!Serial) {}
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(400000); // use 400 kHz I2C

  // Disable/reset all sensors by driving their XSHUT pins low.
  for (uint8_t i = 0; i < sensorCount; i++)
  {
    pinMode(xshutPins[i], OUTPUT);
    digitalWrite(xshutPins[i], LOW);
  }

  // Enable, initialize, and start each sensor, one by one.
  for (uint8_t i = 0; i < sensorCount; i++)
  {
    // Stop driving this sensor's XSHUT low. This should allow the carrier
    // board to pull it high. (We do NOT want to drive XSHUT high since it is
    // not level shifted.) Then wait a bit for the sensor to start up.
    pinMode(xshutPins[i], INPUT);
    delay(10);

    sensors[i].setTimeout(500);
    if (!sensors[i].init())
    {
      Serial.print("Failed to detect and initialize sensor ");
      Serial.println(i);
      while (1);
    }

    // Each sensor must have its address changed to a unique value other than
    // the default of 0x29 (except for the last one, which could be left at
    // the default). To make it simple, we'll just count up from 0x2A.
    sensors[i].setAddress(0x2A + i);

    sensors[i].startContinuous(50);
  }
}

void loop()
{
  int MaxDistanceValue = 1000;
  int DistanceNo = sensors[0].read();
  int DistanceYes = sensors[1].read();

  //for (uint8_t i = 0; i < sensorCount; i++)
  //for (uint8_t i = 0; i < 1; i++)
  //{
//    Serial.print(sensors[i].read());
  
    //Serial.print((String)"NO side sensor "+sensors[0].read());
    //Serial.println();
    //Serial.print((String)"YES side sensor "+sensors[1].read());
    //Serial.println();

    Serial.print((String)"NO side sensor "+DistanceNo);
    Serial.println();
    Serial.print((String)"YES side sensor "+DistanceYes);
    Serial.println();
    
    
    if (DistanceNo<MaxDistanceValue*0.1) {
      tone(3, 147, 50 );
    }

    else if (DistanceNo<MaxDistanceValue*0.2) {
      tone(3, 139, 50 );
    }

    else if (DistanceNo<MaxDistanceValue*0.4) {
      tone(3, 131, 50 );
    }

    else if (DistanceNo<MaxDistanceValue*0.6) {
      tone(3, 123, 50 );
    }

    else if (DistanceNo<MaxDistanceValue*0.8) {
      tone(3, 117, 50 );
    }

    else if (DistanceNo<MaxDistanceValue*1) {
      tone(3, 110, 50 );
    }

    //else {
    //  noTone(3);
    //}

    if (DistanceNo<MaxDistanceValue*1) {
      analogWrite(redPinNo, 255);
      analogWrite(greenPinNo, 0);
      analogWrite(bluePinNo, 0);
      delay(50);
      analogWrite(redPinNo, 0);
      analogWrite(greenPinNo, 0);
      analogWrite(bluePinNo, 0);
    }

     else {
      analogWrite(redPinNo, 0);
      analogWrite(greenPinNo, 0);
      analogWrite(bluePinNo, 255);
    }

    //delay(50);

    if (DistanceYes<MaxDistanceValue*0.1) {
      tone(3, 1976, 50 );
    }

    else if (DistanceYes<MaxDistanceValue*0.2) {
      tone(3, 1865, 50 );
    }

    else if (DistanceYes<MaxDistanceValue*0.4) {
      tone(3, 1760, 50 );
    }

    else if (DistanceYes<MaxDistanceValue*0.6) {
      tone(3, 1661, 50 );
    }

    else if (DistanceYes<MaxDistanceValue*0.8) {
      tone(3, 1568, 50 );
    }

    else if (DistanceYes<MaxDistanceValue*1) {
      tone(3, 1480, 50 );
    }

    //else {
    //  noTone(3);
    //}

    if (DistanceYes<MaxDistanceValue*1) {
      analogWrite(redPinYes, 0);
      analogWrite(greenPinYes, 255);
      analogWrite(bluePinYes, 0);
      delay(50);
      analogWrite(redPinYes, 0);
      analogWrite(greenPinYes, 0);
      analogWrite(bluePinYes, 0);
    }

     else {
      analogWrite(redPinYes, 0);
      analogWrite(greenPinYes, 0);
      analogWrite(bluePinYes, 255);
    }    

//    if (sensors[i].timeoutOccurred()) { Serial.print(" TIMEOUT"); }
//    Serial.print('\t');
  //}
//  Serial.println();
}

To help visualize what the code does I have just uploaded a 20 second clip to youtube so you can see the behaviour.

Yes/No toy video for reference

If any one is able to help it would be much appreciated. Thank you

I havent looked through your code very finely. But the way I would think is that you would have a condition for the off statement of the sensor. For example if a value of say 5 or less means the sensor is not being set off then you could have an if statement to catch this and then in the body set what colors and length you want in the body of the if statement.

The above approach works for as soon as the sensor goes below the condition for being "off" if you wanted to allow the sensor to go on and of multiple times before this and you know how many times you want it to go on and off before you want to turn on your color LED for 5 seconds you could add a counter.
So every time the sensor activates you will have a variable that you increment by 1. Then say you know you want the sensor to activate 10 times before you switch to a 5 second LED then you would have an if statement that would say

if(counter == 10){
    //set LED high for 5 seconds using either delay or blink without delay depending on application
    
    counter = 0; // to reset the counter so everything is setup for running again
}

Ik this wasnt very concise but I hope this helps.

Dean

@walshy690

you could make an RGB object, bring all logic to that object and let the object decide what has to happen.

hope this helps for understanding:

/*
   https://forum.arduino.cc/t/how-to-get-an-led-to-stay-on-for-5-seconds-after-a-sensor-has-stopped-being-set-off/1142675

   flash a LED for a periode of time and then switch back to a stable state

*/

class RGB {
  public:
    enum Effect {OFF, RED, GREEN, BLUE, FLASH};  // the available states of the RGB LED
  protected:
    const uint8_t redPin;              // GPIO for red
    const uint8_t greenPin;            // GPIO for green
    const uint8_t bluePin;             // GPIO for blue
    uint8_t flashPin;                  // the color/pin to be flashed
    uint32_t previousMillisEffect = 0; // last millis within effect
    uint32_t previousMillisOn = 0;     // last switch on
    Effect effect;                     // the current effect
    bool effectState = LOW;            // the currentState within the effect
  public:
    RGB(uint8_t redPin, uint8_t greenPin, uint8_t bluePin) : redPin(redPin), greenPin(greenPin), bluePin(bluePin) {}

    void begin() {
      pinMode(redPin, OUTPUT);
      pinMode(greenPin, OUTPUT);
      pinMode(bluePin, OUTPUT);
    }

    void off() {
      effect = OFF;
      digitalWrite(redPin, LOW);
      digitalWrite(greenPin, LOW);
      digitalWrite(bluePin, LOW);
    }

    void red() {
      effect = RED;
      digitalWrite(redPin, HIGH);
      digitalWrite(greenPin, LOW);
      digitalWrite(bluePin, LOW);
    }

    void green() {
      effect = GREEN;
      digitalWrite(redPin, LOW);
      digitalWrite(greenPin, HIGH);
      digitalWrite(bluePin, LOW);
    }

    void blue() {
      effect = BLUE;
      digitalWrite(redPin, LOW);
      digitalWrite(greenPin, LOW);
      digitalWrite(bluePin, HIGH);
    }

    void flash(Effect color = RED) {
      off();
      effect = FLASH;
      previousMillisOn = millis();
      switch (color) {
        case RED: flashPin = redPin; break;
        case GREEN: flashPin = greenPin; break;
        case BLUE: flashPin = bluePin; break;
      }
    }

    void update(uint32_t currentMillis = millis()) {
      switch (effect) {
        case FLASH:
          if (currentMillis - previousMillisOn < 3000) {
            if (currentMillis - previousMillisEffect > 300) {
              previousMillisEffect = currentMillis;
              if (effectState) {
                digitalWrite(flashPin, LOW);
                effectState = LOW;
              }
              else {
                digitalWrite(flashPin, HIGH);
                effectState = HIGH;
              }
            }
          }
          else {
            red(); // or any other state after the warning interval runs out
          }
          break;
      }
    }
};

RGB rgbA(8, 9, 10);   // create a RGB object and assign  pins for red, green and blude

void setup() {
  rgbA.begin(); // start the object
  //rgbA.red();
  //rgbA.green();
  //rgbA.blue();

  //rgbA.flash();        // start flashing in red
  rgbA.flash(RGB::BLUE); // start flash in another color
}

void loop() {
  rgbA.update(); // give the object time to update its pins
  // put your main code here, to run repeatedly:
  
}

another RGB LED would just need three additional lines:

  • create the object in global namespace
  • call .begin() in setup()
  • call .update() in loop()

Just as a quick reply to this I ended up shelving this project to concentrate on another one

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