issues using millis() for delay

I am trying to create a program to automate a dust collector.
I am very new to the coding and i can get it to work although i want the system to run on after switching off and i just don’t seem to be able to get it to work as it should do

This is my best attempt but if someone to could point me in the places that i’m going wrong i would be very grateful.

#include <Servo.h>;

// switch
const int m_saw = 2;
 int m_sawswitch;
// servo pin
const int servoPin = 9;
// relay pin
const int fanrelay = 13;
Servo gate1;
//timeer
int previoustime = 0;
unsigned long waittime = 2000;
int systemrunning = false;
int m_sawswitchstate;
 int previousbutton = LOW;
int currentbutton;
int debouncetime = 100;
int presstime = 0;

void setup()
{ // servol
 gate1.attach (servoPin);
 
 // Set up the pushbutton pins to be an input:
 pinMode(m_saw, INPUT);
 pinMode(fanrelay, OUTPUT);
 int m_sawswitchstate; 
 digitalWrite(fanrelay, LOW);
 gate1.write(0);
 Serial.begin(9600);
}
void loop()
{  
 unsigned long currenttime = millis(); 
 currentbutton = digitalRead(m_saw);
 
 if(currentbutton != previousbutton){
   presstime = millis();
   if (currentbutton == HIGH ){
     if (m_sawswitch == LOW){
       m_sawswitch = HIGH;
       }
       else{
         m_sawswitch = LOW;
       }
      
   }
 }
 
 if ((currentbutton == HIGH) && (previousbutton == LOW) && ( millis()-presstime > debouncetime)){

   m_sawswitch = HIGH;

 }
   Serial.println ( currentbutton);
   Serial.println ( previousbutton);
   Serial.println ( m_sawswitch);  
 
   
   
 
 

    //switch fan on and open servo gate
  if(m_sawswitch == HIGH){
    if(systemrunning == false)
    gate1.write(90);
    digitalWrite(fanrelay, HIGH);
    systemrunning = true;
    Serial.println( "Running");
  } 
     // tells its counting
  if((m_sawswitch == LOW) && (systemrunning == true)){
   Serial.println ( "Stopping");
  } 
    // switch off fan and close servo gate after set timer
 
 if(m_sawswitch == LOW){
   previoustime = millis();
  if (millis() - previoustime > waittime)
   if(systemrunning == true)
   gate1.write(0);
   digitalWrite(fanrelay, LOW);
   systemrunning = false;
   Serial.println( "Stopped");
   m_sawswitchstate = currenttime;
   
  
 }
   previousbutton = currentbutton;
 }

dust_collection_2.ino (2.05 KB)

Could you edit your post to put your code in code tags?

i want the system to run on after switching off

What does this mean?

sorry done the edit hope that helps.

So once the button is presses i want it to count down for a set time and the switch off the relay and close the servo.

i can get this to work with a slide switch but as soon as i add the push button it stops working.

The end plan is to press the button to switch on the relay and open the servo. Then press again to start the timer then to switch off the relay and close the servo.

i plan to add more servos eventually but once ive got this working im guesung that would be easy to amend.

It is not good to mix unsigned long value with two signed integers to do your time calculations.

Time variables should be unsigned integers whether bytes, words or unsigned longs. They should all be the same type.

YOU being new, make them ALL unsigned long, you only need 2 per “timer”.

If you worry about wasting RAM, change those ints you use to hold values < 256 into type byte variables and save 1 byte each.

Thank you for that advice with the unsigned longs.

I have changed them all but I still have the same problem where it doesn’t wait the desired time before switching off the relay and moving the servo.

Is there something else that I am missing??

dazbullen2010:
sorry done the edit hope that helps.

So once the button is presses i want it to count down for a set time and the switch off the relay and close the servo.

i can get this to work with a slide switch but as soon as i add the push button it stops working.

The end plan is to press the button to switch on the relay and open the servo. Then press again to start the timer then to switch off the relay and close the servo.

i plan to add more servos eventually but once ive got this working im guesung that would be easy to amend.

I am guessing the slide switch holds either an open or closed position and the push button switch is a momentary contact switch? You can get a push button that is not a momentary contact kind or rewrite the code to use a momentary button press.

And about that use long thing, keep in mind which processor you are using and how many bits the processor is doing. With an Uno, an 8 bit machine, unsigned long (UL) or even a ULL (unsigned long long) is needed. Using a Due a unsigned int will do.

Yes the slide switch is on or off. I have the code written a different way so that it works with that either high or low input.

I wanted to use the momentary push button though so I have added the code at the beginning to latch and debounce the button which seems to be working fine but in doing that the time delay now doesn’t work. It just stops as soon as I switch the input to low with the button.

If you held the momentary contact down does it do the thing?

No it doesn’t. I’ve had the serial monitor to watch the switch and you can see that it changes from high to low with no bouncing.
It also prints the step so either running, stopping or stopped. but it just doesnt do Stopping jumps straight from Running to stopped.

but when you use the slide switch it all works as it should? Do give it a try, no code changes.

I did have to change the code a bit.

I added this.

currentbutton = digitalRead(m_saw);

if(currentbutton != previousbutton){
presstime = millis();
if (currentbutton == HIGH ){
if (m_sawswitch == LOW){
m_sawswitch = HIGH;
}
else{
m_sawswitch = LOW;
}

}
}

if ((currentbutton == HIGH) && (previousbutton == LOW) && ( millis()-presstime > debouncetime)){

m_sawswitch = HIGH;

As a latch for the momentary button. With the other type it was just Digital read the switch then digital write output.

If it was good before the debounce thingy but does not work after the addition of the debounce thingy, then the issue is the debounce thingy.

See https://www.arduino.cc/en/Tutorial/Debounce, notice how your debounce code compares to the one from the link?

Have you tried hardware debounce?

Can you please post the latest completed code and explain what it is and is not doing?

The latest code is the one at the beginning.
And the delay that should occur after the button is depressed and the trigger goes low is not working.
The program is supposed to have 3 steps.

  1. Running. Once the button is pressed the trigger goes high triggering the relay and moving a servo.
    2 stopping. Once the button has been pressed this should active a timer and wait a set amount of time.
    3 stopped. This should happen once the time is up and will make the relay switch off and move a servo back.

It’s step 2 that’s not doing as it should it’s jumping from 1 to 3.

pinMode(m_saw, INPUT);

How is this switch wired? Is there an external pull up or pull down resistor? What does it read when pressed?

There is external pull down resistor so it reads HIGH when pressed.

Here is your code with some of the logic and variables simplified. I’ve changed int to bytes where I could

I did not see any need for debounce in my testing given the program flow, but I added short blocking delay for debounce when the button is pressed. This can ether be removed or changed to non blocking.

See if this code doesn’t give you the ON and delayed OFF that you want.

#include <Servo.h>;
//switch
const byte m_saw = 2;
byte m_sawswitch;
// servo pin
const byte servoPin = 9;
// relay pin
const byte fanrelay = 13;
Servo gate1;
unsigned long waittime = 2000;//off delay
boolean systemrunning = false;
byte previousbutton = LOW;
byte currentbutton = LOW;
unsigned long debouncetime = 25;
unsigned long presstime = 0;

void setup()
{ // servol
  gate1.attach (servoPin);

  // Set up the pushbutton pins to be an input:
  pinMode(m_saw, INPUT);//external pulldown
  pinMode(fanrelay, OUTPUT);
  digitalWrite(fanrelay, LOW);
  gate1.write(0);
  Serial.begin(9600);
}
void loop()
{
  unsigned long currenttime = millis();
  //read m_saw button and toggle m_sawswitch on press
  currentbutton = digitalRead(m_saw);
  if (currentbutton == HIGH && previousbutton == LOW) //button was pressed
  {
    delay(debouncetime);
    currentbutton = digitalRead(m_saw);//take a second reading
    if (currentbutton == HIGH) //still HIGH after second reading
    {
      presstime = millis();
      if (m_sawswitch == LOW)
      {
        m_sawswitch = HIGH;
      }
      else
      {
        m_sawswitch = LOW;
      }
    }
  }
  previousbutton = currentbutton;//place here for clarity

  //switch fan on and open servo gate when system is off
  if (m_sawswitch == HIGH) {
    if (systemrunning == false)
    {
      gate1.write(90);
      digitalWrite(fanrelay, HIGH);
      systemrunning = true;
      Serial.println( "Running");
    }
  }

  // tells its counting
  if ((m_sawswitch == LOW) && (systemrunning == true)) {
    Serial.println ("Stopping");
  }

  // switch off fan and close servo gate after set timer
  if (m_sawswitch == LOW && systemrunning == true) {
    //pick up start time from button press routine
    if (millis() - presstime > waittime)
    {
      gate1.write(0);
      digitalWrite(fanrelay, LOW);
      systemrunning = false;
      Serial.println( "Stopped");
    }
  }
}

dazbullen2010:
It also prints the step so either running, stopping or stopped. but it just doesnt do Stopping jumps straight from Running to stopped.

What you need is a finite state machine to break the code into 3 steps and execute each in turn.

Why do this is so that during runtime your inputs are monitored and responded to.

Top-down/beginning/accounting code is "time-deaf" in approach to problems. It utilizes delays/loops to synchronize reads/events in linear and jerky fashion.

Real Time Code reads each input with a function in void loop() that nothing else blocks. Inputs always have a chance to read. The function handles bounce, toggling, whatever, and maintains a constantly updated status for the input.
Consider that Serial works this way, has both input and output buffers.

The state machine is run by a variable that holds which step to run.
A switch-case statement with 3 cases, 1 ea for running, stopping and stopped.

https://www.arduino.cc/reference/en/language/structure/control-structure/switchcase/

cattledog:
Here is your code with some of the logic and variables simplified. I’ve changed int to bytes where I could

I did not see any need for debounce in my testing given the program flow, but I added short blocking delay for debounce when the button is pressed. This can ether be removed or changed to non blocking.

See if this code doesn’t give you the ON and delayed OFF that you want.

#include <Servo.h>;

//switch
const byte m_saw = 2;
byte m_sawswitch;
// servo pin
const byte servoPin = 9;
// relay pin
const byte fanrelay = 13;
Servo gate1;
unsigned long waittime = 2000;//off delay
boolean systemrunning = false;
byte previousbutton = LOW;
byte currentbutton = LOW;
unsigned long debouncetime = 25;
unsigned long presstime = 0;

void setup()
{ // servol
  gate1.attach (servoPin);

// Set up the pushbutton pins to be an input:
  pinMode(m_saw, INPUT);//external pulldown
  pinMode(fanrelay, OUTPUT);
  digitalWrite(fanrelay, LOW);
  gate1.write(0);
  Serial.begin(9600);
}
void loop()
{
  unsigned long currenttime = millis();
  //read m_saw button and toggle m_sawswitch on press
  currentbutton = digitalRead(m_saw);
  if (currentbutton == HIGH && previousbutton == LOW) //button was pressed
  {
    delay(debouncetime);
    currentbutton = digitalRead(m_saw);//take a second reading
    if (currentbutton == HIGH) //still HIGH after second reading
    {
      presstime = millis();
      if (m_sawswitch == LOW)
      {
        m_sawswitch = HIGH;
      }
      else
      {
        m_sawswitch = LOW;
      }
    }
  }
  previousbutton = currentbutton;//place here for clarity

//switch fan on and open servo gate when system is off
  if (m_sawswitch == HIGH) {
    if (systemrunning == false)
    {
      gate1.write(90);
      digitalWrite(fanrelay, HIGH);
      systemrunning = true;
      Serial.println( “Running”);
    }
  }

// tells its counting
  if ((m_sawswitch == LOW) && (systemrunning == true)) {
    Serial.println (“Stopping”);
  }

// switch off fan and close servo gate after set timer
  if (m_sawswitch == LOW && systemrunning == true) {
    //pick up start time from button press routine
    if (millis() - presstime > waittime)
    {
      gate1.write(0);
      digitalWrite(fanrelay, LOW);
      systemrunning = false;
      Serial.println( “Stopped”);
    }
  }
}

This is perfect thank you for your help.

Was there much that was stopping it? i see that you have added some {} in places, is that something that i need to look at in the future?

The only thing that i have noticed is that if you press the switch before its finished stopping it doesnt go back to running it just sits at stopping but stays on.

GoForSmoke:
What you need is a finite state machine to break the code into 3 steps and execute each in turn.

Why do this is so that during runtime your inputs are monitored and responded to.

Top-down/beginning/accounting code is "time-deaf" in approach to problems. It utilizes delays/loops to synchronize reads/events in linear and jerky fashion.

Real Time Code reads each input with a function in void loop() that nothing else blocks. Inputs always have a chance to read. The function handles bounce, toggling, whatever, and maintains a constantly updated status for the input.
Consider that Serial works this way, has both input and output buffers.

The state machine is run by a variable that holds which step to run.
A switch-case statement with 3 cases, 1 ea for running, stopping and stopped.

switch...case - Arduino Reference

https://www.arduino.cc/en/Tutorial/SwitchCase2

I did try to use switch/case and a state machine but i couldnt get my head round how to make it step between the different cases with only the input from the button.

some more research needed on that i think as i am new to this.