Adding a delay to turn off pins after a certain amount of time in a debounce function

I am trying to add a delay to turn off pins. If the previous state was low, I want pins to go high automatic but if button state was high on next press, I want to delay the output pins from going low. This is standard debounce.

 int Read_4 = digitalRead(Mold_Sys_Button);
  if (Read_4 != lastButtonState_4)
  {
    lastDebounce_4 = millis();
    }
  if((millis() - lastDebounce_4) > debounceDelay_4){
    if(Read_4 != Button_State_4)
    {
      Button_State_4 = Read_4;
        if(Button_State_4 == HIGH)
        {
         Button_State_4 = !Button_State_4; 
        }
    }
  
  }
  digitalWrite(Millshop_Blower_Relay, HIGH);
  digitalWrite(Millshop_Al_Relay, HIGH);
  digitalWrite(Transfer_Blower_Relay, HIGH);
  digitalWrite(Coarse_Powder_Al, HIGH);
  digitalWrite(Coarse_Top_Al, HIGH);

Your topic was MOVED to its current forum category as it is more suitable than the original as it is not an Introductory Tutotorial

it is not really clear to me what you want to do:

debouncing is finished withing 20 to 50 milliseconds

0:00,000 io-state is low because button is unpressed
0:00,001 io-state is HIGH because button is pressed
0:00,021 normal debounce has finished
0:00,021 switch another IO-pin HIGH?

0:02,000 button is unpressed
0:02,001 button is pressed
0:02,021 normal debounce has finished as something (what is it ?) was switched HIGH
0:02,022 start a delay of 10 seconds
0:12,022 the 10 second delay is over
0:12,023 switch another IO-pin (which one?) LOW

please describe in normal words what is the final purpose of this and give an overview about your project.

best regards Stefan

1 Like

Hello
A mixture of the delay() function and the usage of millis() is a bad practice.

Not sure if you are familiar with ladder logic? So in a PLC, I would add a timer on delay or a timer off delay to the same button. Timer on would wait "X" amount of time after button press before making output HIGH. (Turning on the output) Timer off would keep the output high for "X" amount of time after button press. (Turning off the out put).

So long story short, I am controlling a series of motors. These motors mimic a dust collection system composed of a series of paddle motors and vacuum motors. Turning them on requires no delay provided the shut down sequence was correct. Turning them off however, once the operator says shut them down I need the paddle wheel to run a little longer than the off button press and the vacuum motor to run longer than the paddle. This ensures that the tubes that carry the saw dust empty out properly and do not clog upon start up.

I hope that helps, and thank you for the response.

Hi @vledbetter1990 ,

OK I understand. You have just posted a code-snippet with debounce and some digitalWrite
If you post your complete sketch with this method

There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

It will be much easier to modify your existing logic / existing code than guessing from scratch how your code might work

I assume that you have some flag-variables that can be used for machine is running or not running
best regards Stefan

Sure thing, warning, so far I am at 200+ lines. But most of it is a repetition of the same code.

[code]
#include "Nextion.h"

//Inputs
const int Air_Pressure_OK = 22;
const int E_Stop_Button = 23;
const int Coarse_Sys_Button = 24;
const int Mill_Sys_Button = 25;
const int Mold_Sys_Button = 26;
const int Auger_Switch = 27;
const int Coarse_Half_Limit = 28;
const int Coarse_Full_Limit = 29;
const int Powder_Full_Limit = 30;

//Outputs
const int Alarm_Strobe = 42;
const int Pulsers_On_LED = 43;
const int Coarse_Blower_Relay = 44;
const int Coarse_Al_Relay = 45;              //Al is air lock//
const int Transfer_Blower_Relay = 46;
const int Millshop_Blower_Relay = 47;
const int Millshop_Al_Relay = 48;
const int Molder_Blower_Relay = 49;
const int Molder_Al_Relay = 50;
const int Coarse_Powder_Al = 51;
const int Coarse_Top_Al = 52;
const int Auger_Relay = 53;

//Analog In
const int Current_Sensor_Read = A15;

//Pin State
int E_Stop_State = HIGH;
int Button_State_1;
int lastButtonState_1;
int Coarse_State = LOW;
int Button_State_2;
int lastButtonState_2;
int Mill_State = LOW;
int Button_State_3;
int lastButtonState_3;
int Mold_State = LOW;
int Button_State_4;
int lastButtonState_4;

//Times
unsigned long lastDebounce_1 = 0;
unsigned long debounceDelay_1 = 50;
unsigned long lastDebounce_2 = 0;
unsigned long debounceDelay_2 = 50;
unsigned long lastDebounce_3 = 0;
unsigned long debounceDelay_3 = 50;
unsigned long lastDebounce_4 = 0;
unsigned long debounceDelay_4 = 50;


void setup()
{
  Serial1.begin(9600);

  //Set Pin IO
  pinMode(Air_Pressure_OK, INPUT);
  pinMode(E_Stop_Button, INPUT);   //Button State 1
  pinMode(Coarse_Sys_Button, INPUT);  //Button State 2
  pinMode(Mill_Sys_Button, INPUT);   // Button State 3
  pinMode(Mold_Sys_Button, INPUT);   // Button State 4
  pinMode(Auger_Switch, INPUT);
  pinMode(Coarse_Half_Limit, INPUT);
  pinMode(Coarse_Full_Limit, INPUT);
  pinMode(Powder_Full_Limit, INPUT);

  pinMode(Alarm_Strobe, OUTPUT);
  pinMode(Pulsers_On_LED, OUTPUT);
  pinMode(Coarse_Blower_Relay, OUTPUT);
  pinMode(Coarse_Al_Relay, OUTPUT);
  pinMode(Transfer_Blower_Relay, OUTPUT);
  pinMode(Millshop_Blower_Relay, OUTPUT);
  pinMode(Millshop_Al_Relay, OUTPUT);
  pinMode(Molder_Blower_Relay, OUTPUT);
  pinMode(Molder_Al_Relay, OUTPUT);
  pinMode(Coarse_Powder_Al, OUTPUT);
  pinMode(Coarse_Top_Al, OUTPUT);
  pinMode(Auger_Relay, OUTPUT);

  //Set Pin Status
  digitalWrite(E_Stop_Button, E_Stop_State);
  digitalWrite(Coarse_Sys_Button, Coarse_State);
  digitalWrite(Mill_Sys_Button, Mill_State);
  digitalWrite(Mold_Sys_Button, Mold_State);
  digitalWrite(Air_Pressure_OK, LOW);
  digitalWrite(Auger_Switch, LOW);
  digitalWrite(Coarse_Half_Limit, LOW);
  digitalWrite(Coarse_Full_Limit, LOW);
  digitalWrite(Powder_Full_Limit, LOW);

  digitalWrite(Alarm_Strobe, LOW);
  digitalWrite(Pulsers_On_LED, LOW);
  digitalWrite(Coarse_Blower_Relay, LOW);
  digitalWrite(Coarse_Al_Relay, LOW);
  digitalWrite(Transfer_Blower_Relay, LOW);
  digitalWrite(Millshop_Blower_Relay, LOW);
  digitalWrite(Millshop_Al_Relay, LOW);
  digitalWrite(Molder_Blower_Relay, LOW);
  digitalWrite(Molder_Al_Relay, LOW);
  digitalWrite(Coarse_Powder_Al, LOW);
  digitalWrite(Coarse_Top_Al, LOW);
  digitalWrite(Auger_Relay, LOW);
}
void(*resetFunc)(void) = 0;
void loop()
{
  int Read_1 = digitalRead(E_Stop_Button);
  if (Read_1 != lastButtonState_1)
  {
    lastDebounce_1 = millis();
  }
  if ((millis() - lastDebounce_1) > debounceDelay_1) {
    if (Read_1 != Button_State_1)
    {
      Button_State_1 = Read_1;
      if (Button_State_1 == LOW)
      {
        Button_State_1 = !Button_State_1;
      }
    }

  }
  resetFunc();

  int Read_2 = digitalRead(Coarse_Sys_Button);
  if (Read_2 != lastButtonState_1)
  {
    lastDebounce_2 = millis();
  }
  if ((millis() - lastDebounce_2) > debounceDelay_2) {
    if (Read_2 != Button_State_2)
    {
      Button_State_2 = Read_2;
      if (Button_State_2 == HIGH)
      {
        Button_State_2 = !Button_State_2;
      }
    }

  }
  digitalWrite(Coarse_Blower_Relay, HIGH);
  digitalWrite(Coarse_Al_Relay, HIGH);
  digitalWrite(Transfer_Blower_Relay, HIGH);
  digitalWrite(Coarse_Powder_Al, HIGH);
  digitalWrite(Coarse_Top_Al, HIGH);

  int Read_3 = digitalRead(Mill_Sys_Button);
  if (Read_3 != lastButtonState_1)
  {
    lastDebounce_3 = millis();
  }
  if ((millis() - lastDebounce_3) > debounceDelay_3) {
    if (Read_3 != Button_State_3)
    {
      Button_State_3 = Read_3;
      if (Button_State_3 == HIGH)
      {
        Button_State_3 = !Button_State_3;
      }
    }

  }
  digitalWrite(Millshop_Blower_Relay, HIGH);
  digitalWrite(Millshop_Al_Relay, HIGH);
  digitalWrite(Transfer_Blower_Relay, HIGH);
  digitalWrite(Coarse_Powder_Al, HIGH);
  digitalWrite(Coarse_Top_Al, HIGH);

  int Read_4 = digitalRead(Mold_Sys_Button);
  if (Read_4 != lastButtonState_4)
  {
    lastDebounce_4 = millis();
  }
  if ((millis() - lastDebounce_4) > debounceDelay_4) {
    if (Read_4 != Button_State_4)
    {
      Button_State_4 = Read_4;
      if (Button_State_4 == HIGH)
      {
        Button_State_4 = !Button_State_4;
      }
    }

  }
  digitalWrite(Millshop_Blower_Relay, HIGH);
  digitalWrite(Millshop_Al_Relay, HIGH);
  digitalWrite(Transfer_Blower_Relay, HIGH);
  digitalWrite(Coarse_Powder_Al, HIGH);
  digitalWrite(Coarse_Top_Al, HIGH);

  if ((Coarse_Half_Limit or Auger_Switch) == HIGH)
  {
    digitalWrite(Auger_Relay, HIGH);
  }

  if ((Coarse_Half_Limit && Coarse_Full_Limit or Powder_Full_Limit) == HIGH)
  {
    digitalWrite(Alarm_Strobe, HIGH);
  }
  if (Air_Pressure_OK == HIGH)
  {
    digitalWrite(Pulsers_On_LED, HIGH);
  }
}
[/code]

Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'

Use code tags (the </> icon above the compose window) to make it easier to read and copy for examination

OK thank you very much for uploading your code as a code-section.

Your title says
Adding a delay to turn off pins after a certain amount of time in a debounce function

A debounce-function is to debounce but not to do a retarded switching off of IO-pins

It is good to see your code. Though it is not clear to me what you want to do

You described the desired function as

In this description you use other words than the variable-names in your code.
I'm unsure which variablename is what

what input pin is changing its state whenoperator is doing

[quote="vledbetter1990, post:5, topic:1004215"]
once the operator says shut them down
[/quote] ???

Which output-pin is related to

???

and how many seconds is "a little longer"???

Which output-pin is

???

and how many seconds is "run longer than the paddle"?

best regards Stefan

These are the pins in each section I am turning off or on. If the state of the pins is off, I want the effected pins to turn on automatically. But if the state of the pins is HIGH when the button is pressed again, I want them to delay going low. IE

Millshop_Al_Relay will stay HIGH for 5 more seconds, and Transfer_Blower_Relay will stay high an additional 10 seconds, etc.

Eventually the delay times are going to be attached to an adjustable programmed slider in a Nextion HMI so the actual values are not crucial as they will be adjustable later on.

Thank you again for all your help.

@vledbetter1990

it seems that you want to proceed in a slow speed in supertiny steps

What is the constants name in your code that represents

??

How about drawing a timing diagram that shows
the time-relations between

  • button changes from "switched on to switched off
  • output-pin Millshop_Blower_Relay
  • output pin Millshop_Al_Relay
  • output pin Transfer_Blower_Relay
  • outputpin Coarse_Powder_Al
  • outputpin Coarse_Top_Al
    ?

You are working on an informatic project. And what is most needed in an informatic project
is sufficient detailed and sufficient precise information

best regards Stefan

coarse sys button operates the coarse al, coarse blower, coarse top al, coarse powder al, and the transfer.

mill operates all the same except coarse al and blower are replaced with mill blower and mill al

mold operates all the same except it is molder al and molder blower.

It is desired that the timing relation be adjustable so I cannot really give a definite answer there. They may want both to stay on for 10sec and then both shut off or they may want the blower to only run for five seconds longer and the paddle wheel for 10 seconds after or they may want the opposite or they may want to set the delay to zero for everything. All I was told is they want room to adjust.

The true question is implementing a delay off timer in a debounce function. I am starting to think it may not be possible and I am contemplating trading momentary push buttons for on/ off switches.

Thanks again.

first of all:

the delayed off-switching is possible. You could have it even for 100 buttons with changing the delaytime every hour or depending on brightness-level with mixed in randomness where the randomness-range is determined by the number of bounces the switch has made. This is just a matter of how much time to develop the code you have and if the functionality fits still into the RAM of the microcontroller.

Usually this is not done inside the debounce function. This would be mixing up very different things.

I recommend to have a loop that is running fast (= 100 to 10000 times per second) by concequently avoiding every single delay() and do all the timing based on millis() in a non.blocking manner.

To explain non-blocking timing on your wanted functionality:

Always keep in mind loop() is running fast and iterates mimimum 100 times per second.
You are using variables that work similar to latched switch. If a device is running the variable holds value "true" if the device is not running the variable holds the value false.
If delaying is active a variable delayingActive holds value true

There will be if-conditions that detect if a momentary push-button is pressed.
If the button is pressed check if variable that represents device running is true

as pseudo-code:

if (button is pressed && deviceRunning == true) {
  MomentButtonWasPressed = millis(); // make a snapshot of time 
  delayingActive = true;
}
if (delayingActive == true ) {

  if (millis() - MomentButtonWasPressed >= delayTimeOfDevice1 ) { // check how much time has passed by since button was pressed
    // if more milliseconds have passed by than specified in delayTimeOfDevice1
    digitalWrite(DevicePin, OFF); // switch device off
    deviceRunning = false;
    delayingActive = false;
  }

The if-condition

if (millis() - MomentButtonWasPressed >= delayTimeOfDevice1 ) 

shows the basic pricinciple of non-blocking timing.
It is a very often repeated comparing how much time has passed by since a "startPoint" in time
In your case the "startPoint" is the buttonpress for switching off.

You should write about how much knowledge you have about coding. This enables to adapt the responses to a level that is easy to understand for you.

best regards Stefan

1 Like

This discussion is screaming out for a state machine treatment along the lines of:

image

However one implements it (and that might be with ifs or with switch..case or perhaps other techniques) in my opinion even relatively simple projects benefit from an explicit separation of states.

edit- It allows one to see how the states interact, and to see easily what causes the move from one state to another. As a result, it allows one to separate the states and their management in the code, and to split stuff out of what can otherwise be a very confusing loop(). It allows for the easy deletion of states (maybe there's no need for state:starting) or addition of states (perhaps it needs a state: startup_failed).

2 Likes

Great and smart describtion :+1:

Thank you for the graphic, that is exactly what I am wanting to do. Sadly my background in ladder logic has spoiled me. That world is examine if on or off and delay this output. That simple. And in that world, I would store the state of the output into a memory bit so I could call on it later in the program. Haven't messed around with this type of programming in a while.

Again thank you for the response. It is very helpful.

Pleasure- I did it in draw.io, by the way.

1 Like

Two questions. If I am understanding correctly, if I do not use the debounce function to initiate the output, where do I store the current state of the output to check against? An array? OR am I checking this real time and there is no need to store the status. (In ladder I would store the value of the output in a memory bit, that way I could check the last state even in case of a power failure.)

Second question is, the millis instruction able to have a variable assigned to it, one that I could call out in an HMI to make adjustable?

Thank you for sticking around in the thread.

Hello octopirate
I case you have to need to design a diagram offline yEd is a powerful tool too.
wbr Paul

Thanks- I actually have the desktop version of drawio.

I use it for all sorts of diagrams in my BA work- swimlanes and so on.