Button counter/stopwatch?

hi everyone, I found this very cool project in a hostel in Leeds UK.
does anyone know anything about this? if who made it is here? codes or instructions?

Looks fun.

Hello gpoppis

It appears to be a non-mechanical, useless box.

Nice job.

The guy from the reception during several night shifts.
Ask him.
He knows how to handle the rollover of millis, how to debounce a button and how to store values in EEPROM.
He found out the voltage drop when daisy chaining the LED modules, therefore solved it by providing separate VCC.
But he might have a problem with colors, as he is using a black dupont wire for VCC on the first Module.
SCNR.

1 Like

Only four days since last button press... forty-five more before rollover. Hostels are never empty and kids can't stop touching things.

Up on the top right, the days & all add up to 140% of a millis rollover:

(70*86400+0*3600+3*60+52)*1000/2^32 = 1.408214

I don't see any hint of an RTC, so it might have the 0.5% accuracy of the Uno's ceramic oscillator.

I think I'd "handle rollover" by counting seconds into a uint32_t. And use a controller with crystal accuracy.

I'd start with multiple LCDs as in

Add a button and use:

A bit like this:

code
// https://wokwi.com/projects/405684473173069825
// for https://forum.arduino.cc/t/button-counter-stopwatch/1289236/6
// based on 
// https://wokwi.com/projects/359393073615174657

#include <Wire.h>
#include <hd44780.h>                       // https://github.com/duinoWitchery/hd44780
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

//hd44780_I2Cexp lcd(0x27); // declare lcd object: auto locate & auto config expander chip
// or autoconfigure:
hd44780_I2Cexp lcd(0x27); // declare lcd object: auto locate & auto config expander chip

// Configure 2nd LDC in Wokwi with i2c-address per https://docs.wokwi.com/parts/wokwi-lcd1602
hd44780_I2Cexp lcdB; // declare lcd object: auto locate & auto config expander chip
hd44780_I2Cexp lcdC; // declare lcd object: auto locate & auto config expander chip
hd44780_I2Cexp lcdD; // declare lcd object: auto locate & auto config expander chip


const byte ButtonPin = A0;
uint32_t seconds = 0; // remember seconds since boot
uint32_t lastChangeMs, lastPressMs = 0; // button timings
uint32_t maxSecBetweenPresses = 0, lastPressSec = 0;
uint32_t count = 0;
bool dirty = false;  // flag for whether the screens need updating

void setup()
{
  Serial.begin(115200);
  pinMode(ButtonPin, INPUT_PULLUP);
  // initialize the LCD
  lcd.begin(16, 2);
  lcdB.begin(16, 2);
  lcdC.begin(16, 2);
  lcdD.begin(20, 4);

  // Turn on the blacklight and print a message.
  lcd.backlight();
  lcd.print("MaxTime btwn Presses");

  lcdB.backlight();
  lcdB.print("Uptime");
  lcdC.backlight();
  lcdC.print("Elapsed Betwn");
  lcdD.backlight();
  lcdD.print("Count:");
}

void loop()
{
  input();
  process();
  output();
}

void input() {
  const uint32_t interval = 1000;
  static uint32_t last = 0;
  static int lastButtonState = digitalRead(ButtonPin);
  int buttonState = digitalRead(ButtonPin);
  uint32_t now = millis();
  if (now - last >= interval) {
    last += interval;
    ++seconds;
    dirty = true;
  }
  if (buttonState != lastButtonState && now - lastChangeMs > 10) {
    lastButtonState = buttonState;
    lastChangeMs = now;
    if (lastButtonState == LOW) {
      lastPressMs = now;
      if (seconds - lastPressSec > maxSecBetweenPresses ) {
        maxSecBetweenPresses = seconds - lastPressSec;
      }
      lastPressSec = seconds;
      ++count;
    }
  }
}

void process() {};

void output() {
  if (dirty) {
    char buff[80];
    uint32_t secs = seconds;
    int days = 0, hours = 0, minutes = 0;
    //Serial.print(seconds); Serial.print("s ");
    dirty = false;
    // total elapsed
    days = seconds / 86400UL;
    hours = (seconds - days * 86400UL) / 3600;
    minutes = (seconds - days * 86400UL - hours * 3600UL) / 60;
    secs = (seconds - days * 86400UL - hours * 3600UL - minutes * 60UL);

    snprintf(buff, 80, "   %02d:%02d:%02d:%02d", days, hours, minutes, secs);
    lcdB.setCursor(0, 1);
    lcdB.print(buff);

    secs = seconds - lastPressSec;
    days = secs / 86400UL;
    secs -= days * 86400UL;
    hours = secs / 3600UL;
    secs -= hours * 3600UL;
    minutes = secs / 60UL;
    secs -= minutes * 60UL;

    snprintf(buff, 80, "   %02d:%02d:%02d:%02d ", days, hours, minutes, secs);
    lcdC.setCursor(0, 1);
    lcdC.print(buff);

    // count
    snprintf(buff, 80, "    %8ld", count);
    lcdD.setCursor(0, 1);
    lcdD.print(buff);

    secs = maxSecBetweenPresses;
    days = secs / 86400UL;
    secs -= days * 86400UL;
    hours = secs / 3600UL;
    secs -= hours * 3600UL;
    minutes = secs / 60UL;
    secs -= minutes * 60UL;

    snprintf(buff, 80, "   %02d:%02d:%02d:%02d", days, hours, minutes, secs);
    lcd.setCursor(0, 1);
    lcd.print(buff);
  }
};

Ah. I see it now. Tnx.