Latching button code

I'm trying to make a display alternate between two numbers when a momentary button is pressed. Any obvious(!) flaws in this code?

#include <Arduino.h>
#include <TM1637Display.h>
#define CLK_PIN 11
#define DIO_PIN 10
TM1637Display display(CLK_PIN, DIO_PIN);

int goButt = 2;
int goState;
int currentState = 0;

void setup() {
  display.setBrightness(3);  // Set the brightness of the display (0-7)
  display.clear();           // Clear the display
  pinMode(goButt, INPUT);
  display.setBrightness(5);
}

void loop() {
  goState = digitalRead(goButt);
  if (goState != currentState && currentState == HIGH) {
      display.showNumberDecEx(1, true);
      goState = LOW;
    }  
  else {
    display.showNumberDecEx(301, true);
  }
}  // end loop

Have you got a pulldown resistor holding the input pin LOW when the button is not pressed or is it floating at an unknown voltage, maybe HIGH, maybe LOW, maybe changing ?

I note that the value of currentState is never changed in the code so will never be HIGH

No debouncing, and your logic is ok, but a bit unorthodox.

Thanks, that solved the problem! However, having expanded the code to display the stopwatch, it is not latching, it only switches the display if I keep the switch closed. Your input is much appreciated, it's a slow learning process!

// stopwatch for set times
#include <Arduino.h>
#include <TM1637Display.h>

#define CLK_PIN 11
#define DIO_PIN 10
TM1637Display display(CLK_PIN, DIO_PIN);
unsigned long startTime;
unsigned long currentTime;
unsigned long elapsedTime;
int countTime = 2700;  // 45 minutes in seconds
int timeFactor = 1;
int currentState = 0;
int goButt = 2;
int goState = 0;

void setup() {
  display.setBrightness(3);  // Set the brightness of the display (0-7)
  display.clear();           // Clear the display
  startTime = millis();      // Record the starting time
  pinMode(goButt, INPUT);
  pinMode(timeButt, INPUT);
  display.setBrightness(5);
  digitalWrite(goButt, HIGH);
}

void loop() {
  if (goState != currentState && currentState == HIGH) { // no button press
    display.showNumberDecEx(0, 0b01000000, true);
    goState = LOW;
  } else { // if button pressed
    currentTime = millis();                          // Get the current time
    elapsedTime = (currentTime - startTime) / 1000;  // Calculate elapsed time in seconds
    if (elapsedTime <= countTime) {
      unsigned long remainingTime = countTime - elapsedTime;
      unsigned int minutes = remainingTime / 60;
      unsigned int seconds = remainingTime % 60;
      display.showNumberDecEx(minutes * 100 + seconds, 0b01000000, true);  // Display remaining time in Minutes:Seconds format

      if (remainingTime == 0) {  // Start blinking when countdown reaches 00:00
        while (true) {
          display.showNumberDecEx(0, 0b01000000, true);  // Display "00:00"
          delay(500);
          display.clear();  // Clear the display
          delay(500);
        }         // end flash end
      }           // remainingTime == 0
    }             // end elapsed time
    delay(1000);  // Wait for 1 second
  }
  currentState = digitalRead(goButt);  
}  // end loop

Take a look at the StateChangeDetection example in the IDE

In your sketch goState is only ever LOW so you can never detect whether its state differs from the current state of the pin which would indicate that the state of the pin has changed

How is the goButt pin wired ?

I suggest that you use INPUT_PULLUP in its pinMode() to activate the built in pullup resistor and remove the digitalWrite() that sets its state HIGH

Wire the input to go LOW when the button is pressed and make any necessary changes to the program logic to match

If I were you I would have the code detect when the button becomes pressed and when it does, change the state of a boolean variable. Then, depending on the state of the boolean run the required code

Debouncing the input will probably be necessary

1 Like

changing the momentary to a SPST seems to work.

It will work only because the input is mechanically locked on or off. If that suits your project then you have a solution, albeit not the one that you originally asked for

at this stage, a solution is the main thing - I'm still learning....

Your code seems to have a few issues. To make the display alternate between two numbers when a momentary button is pressed, you can try the following changes:

  1. Initialization: You should initialize currentState to the initial state of the button to avoid the initial display showing the second number. You can do this in the setup function.

  2. Debouncing: For a momentary button, you might want to add some debouncing logic to avoid false readings when the button is pressed. You can achieve this by adding a small delay after reading the button state.

Here's an updated version of your code with these changes:

#include <Arduino.h>
#include <TM1637Display.h>

#define CLK_PIN 11
#define DIO_PIN 10
TM1637Display display(CLK_PIN, DIO_PIN);

int goButt = 2;
int currentState = LOW;
int lastState = LOW;

void setup() {
  display.setBrightness(3);  // Set the brightness of the display (0-7)
  display.clear();           // Clear the display
  pinMode(goButt, INPUT);
  display.setBrightness(5);
}

void loop() {
  currentState = digitalRead(goButt);

  // Check if the button state has changed
  if (currentState != lastState) {
    delay(50);  // Debounce
    currentState = digitalRead(goButt);  // Read the button again

    if (currentState == HIGH) {
      // Button is pressed, alternate between numbers
      if (display.getColon()) {
        display.showNumberDecEx(1, 0b01000000);  // Display 1 without colon
      } else {
        display.showNumberDecEx(301, 0b01000000);  // Display 301 without colon
      }
    }
  }

  lastState = currentState;
}

This code will toggle between the two numbers when the button is pressed, and it includes a debounce delay to ensure reliable button press detection.

Also Here are some optimizations for your code:

  1. Optimize #include directives: Only include necessary libraries. If you're not using some functions or classes from libraries, exclude them.

  2. Use const for pin definitions: Declare the pin numbers as const to improve code readability and prevent accidental changes.

  3. Avoid setting brightness multiple times: You set the display brightness twice in the setup() function. You can remove the first call to setBrightness() since you set it to 5 at the end.

  4. Use millis() for debouncing: Instead of using delay(50) for debouncing, use millis() to create a non-blocking delay. This way, your loop can continue to run without interruption.

  5. Use a function for button press handling: Create a separate function to handle button presses for better code organization and readability.

Here's the optimized code:

#include <Arduino.h>
#include <TM1637Display.h>

#define CLK_PIN 11
#define DIO_PIN 10
TM1637Display display(CLK_PIN, DIO_PIN);

const int goButt = 2;
int currentState = LOW;
int lastState = LOW;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;

void setup() {
  display.clear();
  pinMode(goButt, INPUT);
  display.setBrightness(5);
}

void handleButtonPress() {
  if (currentState == HIGH) {
    if (display.getColon()) {
      display.showNumberDecEx(1, 0b01000000);  // Display 1 without colon
    } else {
      display.showNumberDecEx(301, 0b01000000);  // Display 301 without colon
    }
  }
}

void loop() {
  currentState = digitalRead(goButt);

  if (currentState != lastState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    handleButtonPress();
  }

  lastState = currentState;
}

This code is more organized and avoids blocking delays, which allows your loop to run smoothly.

Thanks for this, will try it & try to understand it!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.