On relay with a specific amount of time

Hello guys, I am glad that you are visiting my topic and help me find a solution for these.
I am trying to turn on a relay in 30 second with pressing the button once. After 30 sec, I want the relay automatically off. I am using millis() function to set the time, it's ok but the problem is when I set the time for the interval, which is for instance about 5 sec, I need to keep pressing the button for 5 sec and then the program will be executed. All I want to do is pressing the button once and the program will be executed.
I really appreciate for all your help. Below is my code! Thank you so much guys!
P.s: I am new to arduino, please instruct and teach me if I do wrong code. Thank you y'all!

/*
  Blink without Delay

  Turns on and off a light emitting diode (LED) connected to a digital pin,
  without using the delay() function. This means that other code can run at the
  same time without being interrupted by the LED code.

  The circuit:
  - Use the onboard LED.
  - Note: Most Arduinos have an on-board LED you can control. On the UNO, MEGA
    and ZERO it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN
    is set to the correct LED pin independent of which board is used.
    If you want to know what pin the on-board LED is connected to on your
    Arduino model, check the Technical Specs of your board at:
    https://www.arduino.cc/en/Main/Products

  created 2005
  by David A. Mellis
  modified 8 Feb 2010
  by Paul Stoffregen
  modified 11 Nov 2013
  by Scott Fitzgerald
  modified 9 Jan 2017
  by Arturo Guadalupi

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
*/

// constants won't change. Used here to set a pin number:
const int ledPin = LED_BUILTIN;  // the number of the LED pin
const int button = 2;

// Variables will change:
int ledState = LOW;  // ledState used to set the LED
int buttonstate = 0;
int lastbuttonstate = 0;
int lastledstate = 0;
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;  // will store last time LED was updated

// constants won't change:
const long interval = 5000;  // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
  pinMode(button, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  buttonstate = digitalRead(button);
  if (buttonstate == LOW)
  {
    digitalWrite(button,HIGH);
    Serial.println("Button is pressed");
    delay(50);
  }
  else 
  {
    //digitalWrite(button,LOW);
    Serial.println("Button is not pressed yet");
    Serial.println(lastbuttonstate); // read the current state of button 
    delay(50);
  }
  lastbuttonstate = buttonstate;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW && buttonstate == LOW) {
      ledState = HIGH;
    } 
    else 
    {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
    Serial.println(lastledstate);
    delay(50);
  }
  lastledstate = ledState;
}

Welcome to the forum

You need to detect when the button becomes pressed rather than when it is pressed
See the StateChangeDetection example in the IDE

You do have a lastbuttonstate variable which would enable you to do that but you don't use it

1 Like

Can you show me how the lastbuttonstate variable work? I still can't get it because I don't have much experiences in coding.

Did you look at the example that I linked to ?

Basically, every time that you read the state of the input you compare it with what it was last time that you read it. So, before reading it again you save the last button state in a variable with a meaningful name

If the current button state does not equal the last button state then the state has changed. In your sketch if the state is now LOW then the button has become pressed

1 Like

I already used that example too. I will try to figure it out.

Consider the wording of "becomes pressed" and "was pressed" meaning the same.

"was pressed" is in the past, so you keep track of the time the event occurred. "is pressed" is the present, and does not need to be recorded unless you want to know if the button "was pressed."

The timing in "blink without delay" is like a timed auto race where you have a start time and lap (split, interval) times. Every debounce is waiting for a particular lap/split/interval time.

1 Like

The below code does what you want:

/*
 * Created by ArduinoGetStarted.com
 *
 * This example code is in the public domain
 *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-button-pump
 */

#include <ezButton.h> // include ezButton library
#include <ezOutput.h> // include ezOutput library

ezOutput pump(A5);    // create ezOutput object attached to pin A5
ezButton button(12);  // create ezButton object attached to pin 12

void setup() {
  Serial.begin(9600);
  button.setDebounceTime(50); // set debounce time to 50 milliseconds
  pump.low(); // turn pump off
}

void loop() {
  pump.loop();   // MUST call the loop() function first
  button.loop(); // MUST call the loop() function first

  if (button.isPressed()) {
    Serial.println("Pump is started");
    pump.low();
    pump.pulse(30000); // turn on for 30000 milliseconds ~ 30 seconds
    // after 10 seconds, pump will be turned off by pump.loop() function
  }
}

You can see detailed instruction on Arduino and button controls pump via relay tutorial

1 Like

Thank you so much!

Untested:

const int ledPin = LED_BUILTIN;  // the number of the LED pin
const int button = 2;

const long interval = 500;  // interval for LED 'ON' (30sec)
      int  timing   =   0;  // 30sec LED (relay) ON time


void setup( ) {
    // set the digital pin as output:
    pinMode( ledPin, OUTPUT );
    pinMode( button, INPUT_PULLUP );
    Serial.begin( 9600 );
}


void loop( ) {
    static unsigned long currMillis;
    static unsigned long prevMillis = 0;

    if( ((currMillis = millis( )) - prevMillis) >= 60 ) {
        prevMillis = currMillis;
        readButton( );
        mngLED( );
    }
}


void readButton( ) {
    static bool pflag = 1;

    if( !timing ) {
        if( !digitalRead( button ) ) {
            Serial.println( "Button is pressed" );
            timing = interval;
            pflag = 1;
        }
    }
    else if( pflag & digitalRead( button ) ) {
        Serial.println( "Button not pressed" );
        pflag = 0;    // print only once per ON/OFF cycle
    }
}


void mngLED( ) {
    // some day I'll grow up
    // to be a relay
    if( timing ) {
        timing--;
        digitalWrite( ledPin, HIGH );
    }
    else
        digitalWrite( ledPin, LOW );
}
1 Like

Looks plausible. Have you used the wokwi simulator? It's easy to pop something like this in there and try it. I would but it don't work so well on the tablet here where I am.

Avoid raising questions around timing by using

      unsigned long timing = 0; 

variables. It probably wouldn't make a difference here, but I'd rather not need to look into and have to think about it at all.

a7

1 Like

Never mind. Sry sry sry. Reading too fast, recognizing patterns that were not there!

I did put your code into the wokwi, but by the time I had it working it had morphed into the way I would have done it, by which point I finally understood how you did it. :expressionless:

You count off 500 increments of 60 milliseconds. I will assume the code works, and the variable types don't matter so much.

Naturally I prefer the way I did it (!), but one advantage mine has is that the timed interval is explicit, expressed directly in milliseconds in a manifest constant.

So sry again. I think maybe a comment and another manifest constant would make it clearer

const int tick = 60;        // milliseconds per unit of timing
const long interval = 500;  // 500 * 60, 30000 milliseconds (30 seconds)

a7

1 Like

I did it guys, thank you so much y'all

Please post your working sketch and mark the post that gave you the solution as the one that solved it

const int PB_1 = 2; // Button1
const int RLY_1 = 13; //relay 1


//VARIABLES
int buttonState1 = 0; 
    // current state of the button
bool relay1 = false;
i
//MILLIS
unsigned long previousMillis1 = 0;
const unsigned long interval1 = 5000;




void setup()
{
  pinMode(PB_1, INPUT);
  digitalWrite(PB_1, HIGH); // pull-up
  pinMode(RLY_1, OUTPUT);
  digitalWrite(RLY_1, LOW);
  Serial.begin(9600);
 }


void loop(){

    // read the pushbutton input pin:
    buttonState1 = digitalRead(PB_1);
    unsigned long currentMillis = millis();

    // if button is pressed, turn relay on (if it wasn't already on), and reset the timer
    if( buttonState1==HIGH ) // no need to check for previous state, in this specific case
    {
        previousMillis1 = currentMillis;
        digitalWrite(RLY_1, HIGH);
        relay1 = true;
    }

     if( relay1 )
    {
        // turn red led on, if close to turning off the relay
        
        // if enough time has elapsed, turn of the relay
        if (currentMillis - previousMillis1 >= interval1) 
        {
            // .. turn of relay
            digitalWrite(RLY_1, LOW);
            relay1 = false;
        }
    } 
    }

Here is the code, I read all of your advices and I really appreciate that

A question for you

How long should the relay stay on if someone holds the button down for 15 seconds ?

hmm, I tried hold the button down for 15 seconds. The relay will on as the time I hold the button down, after that I release the button, the timer start to count and off for 5 seconds.

I am not sure that I follow your description

I would expect the relay to be on whilst you hold the button down then, when it is released, for it to stay on for 5 seconds before turning off. Is that what you are describing ?

NOTE most relay modules are active LOW, ie they turn on when their input goes LOW. Your code sets the RLY_1 pin HIGH when the button is pressed so could actually be turning the relay off at that point.

Is your relay active LOW or active HIGH ?

Your code in post #14 turns the relay on. When the button is pressed for five seconds, the relay is turned off. When the button is released, the relay turns on.

I'm not good at english, sorry about that. It is what exactly I'm describing. I'm using led pin13 instead of the relay. So I will try with the relay and post the result later.

I'm using the relay that can be activated HIGH or LOW depend on the H/L level trigger. I will try it.