Countdown timer that subtracts time when button NOT pressed

Hey there,

Total beginner here looking to make a timer that counts down from 45 mins, in addition to this a button has to be pressed at all times. If the button is not pressed at any point then the clock "penalizes" by taking 5 minutes off the time. It's essentially for an escape room where one participant has to have a finger on the button at all times else they get penalized, and the countdown is their timer in the room.

I have an Arduino Uno/Mega, 4 digit 7 segment display, push buttons, and piezo.

I've been trying to wrap my head around things like BlinkWithoutDelay but honestly I haven't the slightest clue where to start.

Any help would be appreciated.

aarg:
https://www.youtube.com/watch?v=3VZgaJBrZD8

Hey thanks for that video. I played around with that particular code a bit and got the hang of it, but I just don't know how to incorporate what I want to do into it. I just feel like maybe this code is where I would start from?

Thanks tho

I'd start small and build it up.
Get your countdown timer working. Basically, you get the time when this countdown begins and then subtract that from the current time.

You also need to define a few things

  1. How does this countdown start? The first time the button is pressed?
  2. What happens when someone let's go of the button? 5 minutes is deducted from the countdown but then what? Does it keep counting down even though the button isn't pressed? That would mean once you let go of the button, there is no incentive to push it again. Does it stop counting down? That would benefit the escape room people as time would be frozen.

I would start with the StateChangeDetection example (File->examples->02.Digital->StateChangeDetection) to figure out how to know when your button changes from ON to OFF and OFF to ON.
NOTE: The example sets the button as INPUT which means you need to have an external pull down resistor. If you want to avoid that, configure the button as INPUT_PULLUP, wire one side of the button to ground and the other to the pin. This will change the logic such that HIGH means no button press and LOW is a button press.

After you get that working, figure out how to track elapsed time.

this is complicated as a first project if you are unfamiliar with the Arduino environment. May be start playing around with the basic examples and put that aside for a bit ?

blh64:
I'd start small and build it up.
Get your countdown timer working. Basically, you get the time when this countdown begins and then subtract that from the current time.

You also need to define a few things

  1. How does this countdown start? The first time the button is pressed?
  2. What happens when someone let's go of the button? 5 minutes is deducted from the countdown but then what? Does it keep counting down even though the button isn't pressed? That would mean once you let go of the button, there is no incentive to push it again. Does it stop counting down? That would benefit the escape room people as time would be frozen.

I would start with the StateChangeDetection example (File->examples->02.Digital->StateChangeDetection) to figure out how to know when your button changes from ON to OFF and OFF to ON.
NOTE: The example sets the button as INPUT which means you need to have an external pull down resistor. If you want to avoid that, configure the button as INPUT_PULLUP, wire one side of the button to ground and the other to the pin. This will change the logic such that HIGH means no button press and LOW is a button press.

After you get that working, figure out how to track elapsed time.

Wow that's insightful. Point #2 is clearly something I overlooked. I'll have to figure that part out first, but I will play around with what you suggested. Thanks very much!

I had this code lying around, is that of any interest?

for point #2 above, you have an extra penalty every 30 seconds :slight_smile:

const byte buttonPin = 2;
const uint32_t debounceDuration = 20; // 20ms

const uint32_t oneSecond = 1000UL;              // 1000 ms
const uint32_t oneMinute = oneSecond * 60;      // 60s = 1 minute

const uint32_t gameDuration = oneMinute * 45;   // 45 minutes
const uint32_t penaltyDuration = oneMinute * 5; // -5 minutes
const uint32_t repeatPenalty = oneSecond * 30;  // every 30 seconds a new penalty is applied if button is not held up

uint32_t remainingTime, gameStartTime, penaltyStartTime;

enum : byte {BUTTON_PRESSED, BUTTON_RELEASED} gameState;

void timeIsUP()
{
  Serial.println(F("TIME'S UP"));
  while (true); // infinite loop here
}

void applyPenalty()
{
  Serial.println(F("Penalty ! Press Button to restart"));
  if (remainingTime <= penaltyDuration) timeIsUP(); // game over
  remainingTime -= penaltyDuration;
  penaltyStartTime = millis(); // note when it was released
}

void checkStatus()
{
  switch (gameState) {
    case BUTTON_PRESSED:
      if (digitalRead(buttonPin) == HIGH) {        // button has been released --> penalty
        delay(debounceDuration); // poor's man debounce
        digitalWrite(LED_BUILTIN, LOW); // turn LED OFF
        applyPenalty();
        gameState = BUTTON_RELEASED;
      }
      break;

    case BUTTON_RELEASED:
      if (digitalRead(buttonPin) == LOW) { // did the user press the button again ?
        digitalWrite(LED_BUILTIN, HIGH);// turn LED ON
        gameState = BUTTON_PRESSED; // restart the game
        delay(debounceDuration); // poor's man debounce
      } else {
        if (millis() - penaltyStartTime >= repeatPenalty) applyPenalty(); // new penalty
      }
      break;
  }
}

void printRemainingTime()
{
  uint32_t h = remainingTime / 3600000UL;
  uint32_t m = (remainingTime / 60000UL) - h * 60;
  uint32_t s = (remainingTime / 1000UL) - h * 3600 - m * 60;
  Serial.print(h);
  Serial.write(':');
  if (m < 10) Serial.write('0');
  Serial.print(m);
  Serial.write(':');
  if (s < 10) Serial.write('0');
  Serial.println(s);
}

void countDown()
{
  static uint32_t lastPrintTime = millis();
  uint32_t currentTime = millis();
  if (currentTime - lastPrintTime >= 1000) { // print every second or so
    if (currentTime - lastPrintTime >= remainingTime) timeIsUP();
    remainingTime -= (currentTime - lastPrintTime);
    lastPrintTime = currentTime;
    printRemainingTime();
  }
}


void setup() {

  pinMode(buttonPin, INPUT_PULLUP); // wire as pin D2 --- button --- GND
  pinMode(LED_BUILTIN, OUTPUT); // built in LED on most arduino there is one
  digitalWrite(LED_BUILTIN, LOW); // LED OFF

  Serial.begin(115200);
  Serial.println(F("Press Button to start countdown"));

  // wait until button is pressed to start
  while (digitalRead(buttonPin) == HIGH) ; // do nothing until button is pressed
  delay(debounceDuration); // poor's man debounce

  digitalWrite(LED_BUILTIN, HIGH);// turn LED ON
  remainingTime = gameDuration; // 45 minutes
  printRemainingTime();
  gameStartTime = millis();
  gameState = BUTTON_PRESSED;
}


void loop()
{
  checkStatus();
  countDown();
}

wire your button pin pin D2 (pin 2 <--> button <---> GND)
and open the Serial Console at 115200 bauds