OneButton library & Millis 1 shot timer

Hi, I’m trying to create a 1 shot timer controlled by a switch. The actual programme is using the oneButton Library to control the switches, as there will be several of them. this Library puts each switch event into its own void function, as below. This works great for each switch. For PWM & on off control.

However I can’t get a millis timer working. The standard delay() timer works fine. But the millis timer starts, but won’t stop. hence the question below.

I can get the LED to turn off with a long switch press, but that isn’t stopping the timer.
The outputs drive some FET transistors hence why they are called FET1, etc
The device I am using is a nano

I’m sure its something simple, but I have been playing with this for a couple of days, on and off & can’t get it to work.

Thanks

timer_not_working.ino (2.69 KB)

Nothing sets "delayRunning = false".

But that wouldn't matter because immediately before the timer check you have you have...

// start delay
delayStart = millis();
delayRunning = true;

// check if delay has timed out
if (delayRunning && ((millis() - delayStart) >= DELAY_TIME)) {
  delayRunning = false; // finished delay – single shot, once only
  digitalWrite(FET1, LOW); // turn led off
}
}

Since you always set "delayRunning = true" right before the timer check, it's always going to be true.

Also, since you have also set delayStart = millis()" right before the timer check, this condition can never be true "(millis() - delayStart) >= DELAY_TIME". So the IF can never execute.

In short your whole "delayRunning" and timer logic is completely pointless in this sketch.

I think you need to explain exactly what the buttons are meant to do, and what the purpose of the timer is.

If your intention is that FET1 should turn off after DELAY_TIME your code to do that is in the wrong place.

Function switch1click() only executes when the button is pressed. As such doing any millis() checking in that function will not work for the purposes of a delay.

Move the millis() timing code into loop…

void loop()
{
  unsigned long currentMills = millis(); // get the time at the start of this loop()

  // check if delay has timed out
  if (delayRunning && currentMills - delayStart >= DELAY_TIME) {
    delayRunning = false; // finished delay – single shot, once only
    digitalWrite(FET1, LOW); // turn led off
  }

  switch1.tick(); // keep watching all the push buttons for presses
  switch2.tick(); // keep watching all the push buttons for presses

}

Now that “if” will be checked continuously while the Arduino is running and execute when the timer expires.

Also function switch1longPressStop should probably set delayRunning = false.

That makes sense, the switch function is only going to run once. FET1 only needs to be on for the delay time, then switched off.
However, how do I start the millis timer from within the void switch1click() function?

I tried setting delayRunning = true; after switching the FET1 on, but that doesn’t work, (FET doesn’t switch on) or am I missing something here?

Thanks

stephen

timer_not_working2.ino (2.76 KB)

OK, for the benefit of anyone else that maybe having the same problem, this works, however the timing isn’t 10 seconds, as set in the DELAY_TIME parameter, its more like 5 or 6 seconds. No idea why.

A couple of milliseconds either way, yes. 4 seconds out?

stephen

timer_not_working2.ino (2.96 KB)

You “start” the timer by recording the millis() value at the time you want to “start” it.
Then, to work out if the timer has been hit you do the “if” comparison:
TimeNow - TimeStarted >= SOME_TIMEOUT

This calculates the elapsed time since you started (TimeNow - TimeStarted) and compares against SOME_TIMEOUT value to see if that number of milliseconds have passed yet.

#include <OneButton.h>

OneButton switch1(1, true); // Setup a new OneButton on pin 1
OneButton switch2(0, true); // Setup a new OneButton on pin 0

unsigned long DELAY_TIME = 10000; // 10 sec
unsigned long startTime = 0; // the time the delay started
bool delayRunning = false; // true if still waiting for delay to finish

// Set FET output pins
int FET1 = 3;
int FET2 = 5;

// setup code here, to run once:
void setup() {

  pinMode(FET1, OUTPUT); //Set FET pins as outputs
  pinMode(FET2, OUTPUT);

  // link all the OneButton functions

  switch1.attachClick(switch1click);                  //Fires as soon as a single click is detected.
  // button1.attachDoubleClick(doubleclick1); //Fires as soon as a double click is detected.
  // button1.attachLongPressStart(longPressStart1); //Fires as soon as the button is held down for 1 second.
  switch1.attachLongPressStop(switch1longPressStop); //Fires when the button is released after a long hold.
  // HALL1.attachDuringLongPress(HALL1longPress); //Fires periodically as long as the button is held down,function will be called often.

  // switch2.attachClick(switch2click); //Fires as soon as a single click is detected.
  // button1.attachDoubleClick(doubleclick1); //Fires as soon as a double click is detected.
  // button1.attachLongPressStart(longPressStart1); //Fires as soon as the button is held down for 1 second.
  // switch2.attachLongPressStop(switch2longPressStop); //Fires when the button is released after a long hold.
  // button1.attachDuringLongPress(longPress1); //Fires periodically as long as the button is held down,function will be called often.

}
// setup
// main code here, to run repeatedly:
void loop()
{
  unsigned long currentMills = millis(); // get the time at the start of this loop()
  switch1.tick(); // keep watching all the push buttons for presses
  switch2.tick(); // keep watching all the push buttons for presses

  if (delayRunning == true && currentMills - startTime >= DELAY_TIME)      // check if delay has timed out
  {
    delayRunning = false;                          // finished delay - single shot, once only
    digitalWrite(FET1, LOW);                      // turn led off
  }
}
//== switch1click Function Start ==//
//Fires as soon as a single click is detected on switch 1

void switch1click() {
  //== switchClick Function Start ==//
  //Fires as soon as a single click is detected on switch 1
  digitalWrite(FET1, HIGH);      // turn led on
  delayRunning = true;           // start delay - single shot, once only
  startTime = millis();
}

//== switch1click Function End ==//

//== switch1longPressStop Start==//
//Fires when switch 1 is released after a long hold.
void switch1longPressStop()
{
  delayRunning = false;         // finished delay - single shot, once only (make sure if needed)
  digitalWrite(FET1, LOW);        //switch off timed LED (make sure if needed)

}
//== switch1longPressStop End ==//

// End

Thanks, the mud is getting clearer now!

Thanks again
stephen