Flight Timer - time and memories

Hardware:

  • Arduino Pro Mini
  • button
  • SSD1306 128x32 using U8x8lib from U8g2lib

Functions:

  • One button press starts the Timer and the elapsed time is displayed. Another button press stops timer, displays final flight time until button is pressed again for a new run. Longest flight value is displayed simultaneously

Questions:

How can I display time as Min"Sec or Min.Sec (for example 0.59 to 1.00 to 1.59 etc) instead of milliseconds without using much more storage?

Can you spot other redundancies that might be taking space?

/*Single button stopwatch with button deboucing. First click: start stopwatch;
  Second click: stop and display final time and longest session time on SSD1306
  using u8g2 U8x8 lib*/

#include <U8x8lib.h>
/* Constructor */
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

#define KeyH 2 //H key on my Arduino Uno Clone used for developing connected to D2
int KeyHstate;
int lastKeyHstate = 0;

unsigned long onTime;
unsigned long clickTime = 0;
unsigned long flightTimer = 0;
unsigned long finalflightTime = 0;
unsigned long topflightTime = 0;

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

int buttonPushCounter = 0;

void setup() {

  //  Serial.begin(9600);

  pinMode(KeyH, INPUT); //board has a pull down resistor, normally LOW or 0

  u8x8.begin();
  u8x8.setFlipMode(1);

}

void loop() {

  int buttonReading = digitalRead(KeyH);

  onTime = millis();

  //Display
  u8x8.setFont(u8x8_font_victoriamedium8_r);

  u8x8.drawString(2, 0, "Top");
  u8x8.setCursor(2, 2);
  u8x8.print(topflightTime);

  u8x8.drawString(9, 0, "Timer");
  u8x8.setCursor(9, 2);
  u8x8.print(flightTimer);

  //Debounce button and retrieve times
  if (buttonReading != lastKeyHstate) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (buttonReading != KeyHstate) {
      KeyHstate = buttonReading;

      if (KeyHstate == HIGH) {
        buttonPushCounter++;
        clickTime = onTime;
      }
    }
  }

  lastKeyHstate = buttonReading;

  if (buttonPushCounter % 2 == 0) {
    flightTimer = finalflightTime; //to display ZERO while stopped
  } else {
    flightTimer = (millis() - clickTime) / 1000; //elapsed flight time
    finalflightTime = flightTimer;
  }

  if (finalflightTime >= topflightTime) {
    topflightTime = finalflightTime;
  }

  //  Serial.print("buttonReading: ");
  //  Serial.print(buttonReading);
  //  Serial.print("\t");
  //
  //  Serial.print("onTime: ");
  //  Serial.print(onTime);
  //  Serial.print("\t");
  //
  //  Serial.print("clickTime: ");
  //  Serial.print(clickTime);
  //  Serial.print("\t");
  //
  //  Serial.print("flightTimer: ");
  //  Serial.print(flightTimer);
  //  Serial.print("\t");
  //
  //  Serial.print("pushes: ");
  //  Serial.print(buttonPushCounter);
  //  Serial.println("\t");


}

How can I display time as Min"Sec or Min.Sec (for example 0.59 to 1.00 to 1.59 etc) instead of milliseconds without using much more storage?

Simple math.

Why do you set onTime to millis() on every pass through loop()?

Why is there so much code between reading the switch state and using the data? How many variables do you need to determine is the current state of the switch is, or is not, the same as the previous state? The morons that posted the debounce code that you copied were full of crap.

Debouncing means using, or not, the current value of the switch, depending on how soon this change happened after the previous change. To decide that, you need to know:
1)that a change occurred - that involves TWO variables - for the current state and the previous state
2)when this change happened and when the previous change happened.

It does NOT involve three variables to hold state and two to hold time.

"Crap"!? "F**king"!? Do you think if I was able to see what might be so obvious to you in this case I would be asking for help?

FranciscoB:
"Crap"? "F**king"? Do you think if I was able to see what is so obvious to you in this case I would be asking for help?

Did you want us to point out errors that you do know about already? Why would you be mad that someone pointed out mistakes that you didn't know about? Isn't that what you came here for?

Wouldn't you rather focus on fixing your code rather than talking offense at PaulS?

PaulS:
That f**king debounce code that you copied is crap.

There really is no need for that kind of language.
Please restate and edit your post

AWOL:
There really is no need for that kind of language.
Please restate and edit your post

OKAY. I put the blame on the idiot that posted the code, not the code itself.

But the poster here didn't/couldn't know that the code they'd used was rubbish, so the comment about its quality went over their head.

AWOL:
But the poster here didn't/couldn't know that the code they'd used was rubbish, so the comment about its quality went over their head.

Fair point. I'll keep that in mind the next time someone uses that example, trying to expand it, and failing miserably. Which won't be long.

PaulS:
Simple math.

Why do you set onTime to millis() on every pass through loop()?

Why is there so much code between reading the switch state and using the data? How many variables do you need to determine is the current state of the switch is, or is not, the same as the previous state? The morons that posted the debounce code that you copied were full of crap.

Debouncing means using, or not, the current value of the switch, depending on how soon this change happened after the previous change. To decide that, you need to know:
1)that a change occurred - that involves TWO variables - for the current state and the previous state
2)when this change happened and when the previous change happened.

It does NOT involve three variables to hold state and two to hold time.

I just noticed you thoroughly edited your first post. It’s now constructive and in a positive note, more like what someone would expect finding in the official forum for the Arduino.

Now it actually helped me make some progress, after finding this site:

http://www.gammon.com.au/switches

/*Single button stopwatch with button deboucing. First click: start stopwatch;
  Second click: stop and display final time and longest session time on SSD1306
  using u8g2 U8x8 lib*/

#include <U8x8lib.h>

U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

#define KeyH 2 //H key on my Arduino Uno Clone connected to D2

byte oldKeyHstate = LOW;

unsigned long clickTime = 0;
unsigned long flightTimer = 0;
unsigned long finalflightTime = 0;
unsigned long topflightTime = 0;

const unsigned long debounceTime = 50;  // milliseconds
unsigned long switchPressTime;  // when the switch last changed state

byte buttonPushCounter = 0;

byte flightTimer_minutes = 0;
byte flightTimer_seconds = 0;

void setup() {
  //  Serial.begin(9600);
  pinMode(KeyH, INPUT); //board has a pull down resistor, normally LOW or 0

  u8x8.begin();
  u8x8.setFlipMode(1);
}

void loop() {

  u8x8.setFont(u8x8_font_victoriamedium8_r);

  u8x8.drawString(0, 0, "TOP");
  u8x8.setCursor(0, 3);
  //u8x8.print(topflightTime);

  u8x8.drawString(4, 0, "TIMER");
  u8x8.drawString(10, 0, "FINAL");

  byte KeyHstate = digitalRead(KeyH);

  if (KeyHstate != oldKeyHstate) {
    if ((millis() - switchPressTime) > debounceTime) {
      switchPressTime = millis ();
      oldKeyHstate = KeyHstate;
      if (KeyHstate == HIGH) {
        buttonPushCounter++;
        clickTime = millis();
      }
    }
  }

  if (buttonPushCounter % 2 == 0) {
    u8x8.setCursor(10, 3);
    u8x8.print(finalflightTime);
  } else {
    flightTimer = (millis() - clickTime); //elapsed flight time
    finalflightTime = flightTimer;

    u8x8.setCursor(4, 3);
    u8x8.print(flightTimer);
  }
  if (finalflightTime >= topflightTime) {
    topflightTime = finalflightTime;

  }

  //  Serial.print("clickTime: ");
  //  Serial.print(clickTime);
  //  Serial.print("\t");
  //  //  Serial.print("flightTimer: ");
  //  Serial.print(flightTimer);
  //  Serial.print("\t");
  //  //  Serial.print("pushes: ");
  //  Serial.print(buttonPushCounter);
  //  Serial.println("\t");


}

Just when I was starting to like you, you ruin it again by calling a beginner an idiot in the official Arduino forum for copy-pasting working code found in a tutorial from the Arduino site.

I did NOT. I called to person that wrote that code, and posted it, an idiot. The code that you copied is crap.

It's not your fault that it is crap, or that you didn't know it was crap. It's the fault of the person that wrote the code, and that of the Arduino team that doesn't bother with posting better code.

PaulS:
OKAY. I put the blame on the idiot that posted the code, not the code itself.

I misunderstood this post. For that reason I'm sorry and I've edit out my reaction.

Problem solved, thanks to the extra-motivation gathered from the lack of help in this thread but mostly to the developer of u8g2lib, who in 3 short paragraphs showed me the correct though process.

/*Single button stopwatch with button deboucing. First click: start stopwatch;
  Second click: stop and display final time and longest session time on SSD1306
  using u8g2 U8x8 lib*/

#include <U8x8lib.h>

U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

#define Button 2 //H key on my Arduino Uno Clone connected to D2

byte oldButtonstate = LOW;

unsigned long clickTime = 0;
unsigned long Timer = 0;
unsigned long oldTime = 0;
unsigned long topTime = 0;

unsigned long Timer_sec = 0;
unsigned long Timer_min = 0;

unsigned long topTime_sec = 0;
unsigned long topTime_min = 0;

const unsigned long debounceTime = 50;  // milliseconds
unsigned long switchPressTime;  // when the switch last changed state

byte buttonPushCounter = 0;

void setup() {

  pinMode(Button, INPUT); //board has a pull down resistor, normally LOW or 0

  u8x8.begin();
  u8x8.setFlipMode(1);
}

void loop() {

  u8x8.setFont(u8x8_font_victoriamedium8_r);

  u8x8.drawString(1, 3, "BEST"); // topTime

  u8x8.setCursor(8, 3);
  u8x8.print(u8x8_u8toa(topTime_min, 2));
  u8x8.print(":");
  u8x8.print(u8x8_u8toa(topTime_sec, 2));

  u8x8.drawString(1, 0, "TIME");
  u8x8.drawString(1, 1, "LAST");

  byte Buttonstate = digitalRead(Button);

  if (Buttonstate != oldButtonstate) {
    if ((millis() - switchPressTime) > debounceTime) {
      switchPressTime = millis ();
      oldButtonstate = Buttonstate;
      if (Buttonstate == HIGH) {
        buttonPushCounter++;
        clickTime = millis();
      }
    }
  }

  if (buttonPushCounter % 2 == 0) {
    u8x8.setCursor(8, 1);
    u8x8.print(u8x8_u8toa(Timer_min, 2));
    u8x8.print(":");
    u8x8.print(u8x8_u8toa(Timer_sec, 2));
  } else {
    Timer = (millis() - clickTime); //elapsed flight time

    Timer_sec = (Timer) / 1000;
    Timer_min = (Timer_sec) / 60;
    Timer_sec = Timer_sec % 60;

    u8x8.setCursor(8, 0);
    u8x8.print(u8x8_u8toa(Timer_min, 2));
    u8x8.print(":");
    u8x8.print(u8x8_u8toa(Timer_sec, 2));
   

    oldTime = Timer;
  }
  if (oldTime >= topTime) {
    topTime = oldTime;

    topTime_sec = (topTime) / 1000;
    topTime_min = (topTime_sec) / 60;
    topTime_sec = topTime_sec % 60;
  }
}