LED and Relay to drive for time millis() then flash before timer runs out

Hi

The project I am working on has hit a road block.

I am trying to have a Nano control a relay (via a push button) to engage USB power for a period of time. I have also included an LED for indication when the relay is energized.
I have included code that resets the timer if you push the button again.

What I want to do is have the LED flash for 5 seconds before cutting out the relay. Unless you push the button and reset the timer again and the LED remain solid.

I can get the push button to engage the relay (Digital Pin 9) for 10 seconds (just a test time, I would like 30 mins when finished) and the LED to come on. And have successfully integrated the time reset if the push button is depressed again.
have included a debounce code for the button

Just can not get the flash to work just before cut off.

Any help greatly appreciated.

const int buttonPin = 10; //button input
const int relayPin =  9; // relay output
const int LED_OUT = 12; // LED indicator output
int sensorState = LOW;
unsigned long startTime;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
int oldState;
int buttonState;
int lastButtonState = LOW;
//
void setup()
{
  pinMode(relayPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(LED_OUT, OUTPUT);
}
//
void loop()
{
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        sensorState = ! sensorState;
      }
    }
  }
  sensorState = digitalRead(buttonPin); //if button high, turn on relay and LED
  if (sensorState == HIGH)
  {
    if (oldState == LOW)
    {
      digitalWrite(relayPin, HIGH);
      startTime = millis();
      digitalWrite(LED_OUT, HIGH);
    }
  }
  oldState = sensorState;

  if (millis() - startTime >= 10000UL) //when time has passed 10 secs cut off relay and LED
  {
    digitalWrite(relayPin, LOW);
    digitalWrite(LED_OUT, LOW);
  }
else sensorState = LOW;
}


Hello
In short words:

  1. Button pressed and released -> LED On and Relais On
  2. Button pressed and released -> LED blinking and Relais On
  3. either after a time X the LED Off and Relais Off
  4. or Button pressed and released -> LED Off and Relais Off
  5. same player shoot again :slight_smile:

I gues the sketch needs three timers and little bit processing on a button object at least .

Yeah it was a little hard to put it in to words:

  1. Button pressed and released -> LED On and Relay On for time period (X secs)
  2. Timer reaches 5 secs before X finishes -> LED Flashes (indicating relay soon be to switched off)
  3. Button pressed and released -> Resets timer. LED returns solid and relay remains on. X starts again.
  4. time X expires -> the LED Off and Relays Off
  5. same player shoot again :slight_smile:

I may end up adding a second button to cancel all and revert back to initial state. One button to start timer/led/relay/reset timer and another button to turn off all if desired and start again

Finite state machine!

Ah this makes sense!

Will look in to this tomorrow and report any success

And take a look to OOP for using structs´s and array´s too.
That will reduce the coding work essential.

  if (millis() - startTime >= 10000UL) //when time has passed 10 secs cut off relay and LED
  {
    digitalWrite(relayPin, LOW);
    digitalWrite(LED_OUT, LOW);
  }
  else if (millis() - startTime >= 10000UL - 5000UL) //less than 5s to go, flash led
  {
    if (bitRead(millis(), 8))
      digitalWrite(LED_OUT, HIGH);
    else
      digitalWrite(LED_OUT, LOW);
  }

(Untested!)

Just uploaded and tested and was successful! YAY

I will look in to finite state coding tomorrow to see if that is a cleaner way to do it, however the addition of the code above has worked!

Many thanks!!

Finite state machines are very powerful and easy to use, but it takes a bit of getting used to. However, once you 'get' it, it's an incredibly useful tool to keep around in your box.

Hello
Yes, that´s true. Especcially when addtion I/O Pin´s with functions/methodes should be added to the functionality of the sketch.

Okay so I have rewritten the sketch hoping to get some results but have gotten a little stuck.
I have now modelled it off a finite state machine with the order of operation as such:
*for coding simplicity, I have negated the neopixel for an LED to make it easier to write for now. Hoping to include it after I have the sketch nailed.
**The timings are arbutary: they will in future be 30 minutes on and a 30 second flash.

I have no experience with FSM but I feel this is the way to go. My code is:

int LED = 12; //LED is on Pin 12
int Relay = 2; // Relay is on Pin 2
int Button = 3; // Button is on Pin 3
int ButtonState; //used for debounce
int LastButtonState = LOW;
int previousState = 0;
unsigned long debounceDelay = 50;
unsigned long debounceTime = 0;



void setup() {
  pinMode(Relay, OUTPUT);
  pinMode(LED, OUTPUT);
  pinMode(Button, INPUT);
}

void loop() {

   int state = 1; // initial state is 1, the "idle" state.
   unsigned long timecurrent;  // To store the "current" time in for delays.

  if (state == 2) { //Button is pressed, turn on LED and relay and begin timer.
    digitalWrite (Relay, HIGH);
    digitalWrite (LED, HIGH);
   
  }

  if (state == 3) { //5 seconds before timer elapsed: Relay remains on, LED to flash
    digitalWrite (Relay, HIGH);
    digitalWrite(LED, HIGH);
    delay (500);
    digitalWrite(LED, LOW);
  }

  if (state == 4) { //After timer has elapsed 10 seconds turn off all.
    digitalWrite (Relay, LOW);
    digitalWrite (LED, LOW);


    switch (state)   {
      case 1:
        //Holding inital state.
        break;

      case 2:
        // Button read and debounce
        int ButtonInput = digitalRead(Button);
        if (ButtonInput = ! LastButtonState) {
          debounceTime = millis();
        
        if ((millis() - debounceTime) > debounceDelay) {
          if (ButtonInput !=  ButtonState) {
            ButtonState = ButtonInput;
            if (ButtonState == HIGH) {
              state = 3;
            }
          }
        }
        }
    break;

  case 3:
    // 5 seconds before the 10 second timer has elapsed: relay to remain on and LED to flash.
    if (millis() - timecurrent >= 10000UL - 5000ul) {
      state = 4;
      timecurrent = millis(); // remember the current time
    }

    break;

  case 4:
  // After 10 seconds: turn off all.
    if (millis() - timecurrent > 10000ul) {
      state = 5;
      timecurrent = millis();  // Remember the current time
    }
    break;
  }
}
}

However nothing happens. Not sure if it is because I have not separated the Switch Case as it's own void function and called back to it in the loop, but I tried and had it not defined in the scope:

void loop() {
  
StateMachine();
   int state = 1; // initial state is 1, the "idle" state.
   unsigned long timecurrent;  // To store the "current" time in for delays.

  if (state == 2) { //Button is pressed, turn on LED and relay and begin timer.
    digitalWrite (Relay, HIGH);
    digitalWrite (LED, HIGH);
   
  }

  if (state == 3) { //5 seconds before timer elapsed: Relay remains on, LED to flash
    digitalWrite (Relay, HIGH);
    digitalWrite(LED, HIGH);
    delay (500);
    digitalWrite(LED, LOW);
  }

  if (state == 4) { //After timer has elapsed 10 seconds turn off all.
    digitalWrite (Relay, LOW);
    digitalWrite (LED, LOW);

void StateMachine(){
    switch (state)   {
      case 1:
//blah blah blah the same onwards

Any help appreciated! Linking this to a recent post as FSM mentioned here is where I started.

You need to pay more attention to where you put { and }. They are not for decoration, they are crucially important.

Get into the habit of using Tools->Auto Format in the IDE. This will correct your indentation, making it easier to spot where { or } are in the wrong places. With correct indentation, all the lines of code that run together will be at the same indentation. So if you see code lines you expect to run together and they are not at the same indentation, you spotted a mistake.

Question: why do you have if statements to make certain lines of code only run for a certain state, then use a switch-case to do the same thing? You don't need both!

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