Pushbutton not working as expected

I made a sketch which worked perfect. However, i decided i want a pushbutton to switch two functions. This kinda works. However it seems that the push is not always registered. Another thing i noticed is when i keep the button pressed it keeps toggling the functions. I would expect it to toggle when i release the button. Can someone point me in the right direction?

#include <TM1637Display.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
#include <Timezone.h>
#define CLK 2
#define DIO 3
#define rxPin 5
#define txPin 6
#define BUTTON_PIN 7
#define LED_PIN LED_BUILTIN

// Change these two rules corresponding to your timezone, see https://github.com/JChristensen/Timezone
//Central European Time (Frankfurt, Paris)  120 = +2 hours in daylight saving time (summer).
// Central European Time
TimeChangeRule CEST = { "CEST", Last, Sun, Mar, 2, 120 };  // Central European Summer Time
TimeChangeRule CET = { "CET ", Last, Sun, Oct, 3, 60 };    // Central European Standard Time
Timezone CE(CEST, CET);
TimeChangeRule *tcr;

SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
TM1637Display display = TM1637Display(CLK, DIO);
const uint8_t SEG_GPS[] = {
  SEG_D,                                  // _
  SEG_A | SEG_C | SEG_D | SEG_E | SEG_F,  // G
  SEG_A | SEG_B | SEG_E | SEG_F | SEG_G,  // P
  SEG_A | SEG_C | SEG_D | SEG_F | SEG_G   // S
};
const uint8_t SEG_TEST[] = {
  SEG_F | SEG_G | SEG_E | SEG_D,          // _
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,  // G
  SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,  // P
  SEG_F | SEG_G | SEG_E | SEG_D,          // S
};

TinyGPSPlus gps;
int ldrpin = 0;
int value = 0;
//int button = 7;
int status = false;
int led = 13;


void setup() {
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
 
  pinMode(LED_PIN, OUTPUT);
  mySerial.begin(9600);
  //mySerial.begin(57600);
  display.setBrightness(7);
  display.setSegments(SEG_GPS);
  setTime(00, 00, 00, 01, 01, 1970);
}

void loop() {

  value = analogRead(ldrpin);
  value = constrain(value, 500, 1500);
  value = map(value, 500, 1500, 1, 7);
  display.setBrightness(value);
  //updateTime();
 
  // run over and over
  //while (mySerial.available() > 0)
    //if (gps.encode(mySerial.read())){
    //   setDisplay();



    static byte toggle_sw_memmory = 0;

  // Check for keypress
  if (!digitalRead(BUTTON_PIN)) {  // Pulled up so zero = pushed.

    delay(200);
  }

  if (!digitalRead(BUTTON_PIN)) {  // if it is still pushed after a delay.
    toggle_sw_memmory = !toggle_sw_memmory;
  }

  if (toggle_sw_memmory) {
    digitalWrite(LED_PIN, HIGH);
    while (mySerial.available() > 0)
    if (gps.encode(mySerial.read())){
    //   setDisplay();
    setDisplayTime();}
  }
   if (!toggle_sw_memmory){
    digitalWrite(LED_PIN, LOW);
    while (mySerial.available() > 0)
    if (gps.encode(mySerial.read())){
    //   setDisplay();
    setDisplay();}
  }
}


void updateTime(void) {
  if (gps.time.isValid() && gps.date.isValid()) {
    setTime(gps.time.hour(), gps.time.minute(), gps.time.second(), gps.date.day(), gps.date.month(), gps.date.year());
  }
}


void setDisplay() {
  if (gps.speed.isValid()) {
    double speed = gps.speed.kmph();
    if (speed > 10) {
      display.showNumberDec(speed, false, 4, 0);
      return;
    }
  }

  if (gps.time.isValid()) {
    time_t utc = now();
    time_t local = CE.toLocal(utc, &tcr);
    int minutes = gps.time.minute();
    display.showNumberDec(minutes, true, 2, 2);
    int hours = gps.time.hour();
    updateTime();
    hours = hours + 1;
    //hours = hours+1;
    if (hours > 24)
      hours = hours - 24;
    // if-else to blink te colon
    int seconds = gps.time.second();
    if ((seconds % 2) == 0) {
      display.showNumberDecEx(hour(local), 0b01000000, true, 2, 0);
    } else {
      display.showNumberDecEx(hour(local), 0, true, 2, 0);
    }
  }
}

void setDisplayTime() {
  if (gps.time.isValid()) {
    time_t utc = now();
    time_t local = CE.toLocal(utc, &tcr);
    int minutes = gps.time.minute();
    display.showNumberDec(minutes, true, 2, 2);
    int hours = gps.time.hour();
    updateTime();
    hours = hours + 1;
    //hours = hours+1;
    if (hours > 24)
      hours = hours - 24;
    // if-else to blink te colon
    int seconds = gps.time.second();
    if ((seconds % 2) == 0) {
      display.showNumberDecEx(hour(local), 0b01000000, true, 2, 0);
    } else {
      display.showNumberDecEx(hour(local), 0, true, 2, 0);
    }
  }
}

Your question is not related to installation & troubleshooting. There are warnings about posting your project questions in this section of the forum, please don't ignore those warnings again. I will move your topic to an appropriate section.

You're watching the STATE, not the edge!

Once detected, wait until release before initiating the next action.

1 Like

See my state change detection for active low inputs tutorial to see how to detect the edge and wire the switch.

1 Like

Apologies for posting in the wrong section.

What is the difference between state and edge? According to this tutorial its the same: https://docs.arduino.cc/built-in-examples/digital/StateChangeDetection
I also used the internal pullup, but that gave the same result.

State means you read it, it's active, you perform the action over and over until released. Edge detection means you only react on a change, so you only execute once
A jog switch, for example, moves the motor until released. An elevator button is pushed once, and remains active until cleared.

ok, i thought i was doing that with

toggle_sw_memmory

I will get back to the drawing board and see if i can figure this out.

You're flipping it every time instead of watching for the edge.
Watch for lastvalue != newvalue AND lastvalue = true to detect the falling edge. Only then set lastvalue = newvalue

State is a steady level, like HIGH or LOW.

Edge is transition or change, LOW to HIGH (positive edge) or HIGH to LOW (negative edge).

or

   Watch for lastvalue != newvalue AND lastvalue == true

or

Watch for lastvalue != newvalue AND lastvalue 

I know it wasn't code code, but I saw != and thought maybe to save a cycle by using == to match.

a7

I prefer inequalities in case of a float ...
It was explicit TRUE to emphasize to the student the STATE being watched. Change to FALSE to watch the other edge, to me clearer than ! true

2 Likes

1st edge in diagram is falling, other edge is rising. overlay timing marks each time loop() executes. Falling edge is button press. Execute once and wait for rising edge (button release) to rearm for next time.

Thank you all very much. With your help and a complete rewrite i managed to get it working.

#include <SoftwareSerial.h>
#include <TinyGPS++.h>
#include <Timezone.h>
#define CLK 2
#define DIO 3
#define rxPin 5
#define txPin 6
#define BUTTON_PIN 7
#define LED_PIN LED_BUILTIN

// Change these two rules corresponding to your timezone, see https://github.com/JChristensen/Timezone
//Central European Time (Frankfurt, Paris)  120 = +2 hours in daylight saving time (summer).
// Central European Time
TimeChangeRule CEST = { "CEST", Last, Sun, Mar, 2, 120 };  // Central European Summer Time
TimeChangeRule CET = { "CET ", Last, Sun, Oct, 3, 60 };    // Central European Standard Time
Timezone CE(CEST, CET);
TimeChangeRule *tcr;

SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
TM1637Display display = TM1637Display(CLK, DIO);
const uint8_t SEG_GPS[] = {
  SEG_D,                                  // _
  SEG_A | SEG_C | SEG_D | SEG_E | SEG_F,  // G
  SEG_A | SEG_B | SEG_E | SEG_F | SEG_G,  // P
  SEG_A | SEG_C | SEG_D | SEG_F | SEG_G   // S
};
const uint8_t SEG_TEST[] = {
  SEG_F | SEG_G | SEG_E | SEG_D,          // _
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,  // G
  SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,  // P
  SEG_F | SEG_G | SEG_E | SEG_D,          // S
};

TinyGPSPlus gps;
int ldrpin = 0;
int value = 0;

// Variables will change:
int buttonPushCounter = 0;  // counter for the number of button presses
int buttonState = 0;        // current state of the button
int lastButtonState = 0;    // previous state of the button



void setup() {
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  pinMode(LED_PIN, OUTPUT);
  mySerial.begin(9600);
  //mySerial.begin(57600);
  display.setBrightness(7);
  display.setSegments(SEG_GPS);
  setTime(00, 00, 00, 01, 01, 1970);
}

void loop() {

  value = analogRead(ldrpin);
  value = constrain(value, 500, 1500);
  value = map(value, 500, 1500, 1, 7);
  display.setBrightness(value);
  updateTime();
  // read the pushbutton input pin:
  buttonState = digitalRead(BUTTON_PIN);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;


  // turns on the LED every two button pushes by checking the modulo of the
  // button push counter. the modulo function gives you the remainder of the
  // division of two numbers:
  if (buttonPushCounter % 2 == 0) {
    digitalWrite(LED_PIN, HIGH);
    while (mySerial.available() > 0)
      if (gps.encode(mySerial.read())) {
        setDisplayTime();
      }

  } else {
    digitalWrite(LED_PIN, LOW);
    while (mySerial.available() > 0)
      if (gps.encode(mySerial.read())) {
        setDisplay();
      }
  }
}
void updateTime(void) {
  if (gps.time.isValid() && gps.date.isValid()) {
    setTime(gps.time.hour(), gps.time.minute(), gps.time.second(), gps.date.day(), gps.date.month(), gps.date.year());
  }
}

void setDisplay() {
  if (gps.speed.isValid()) {
    double speed = gps.speed.kmph();
    if (speed > 10) {
      display.showNumberDec(speed, false, 4, 0);
      return;
    }
  }

  if (gps.time.isValid()) {
    time_t utc = now();
    time_t local = CE.toLocal(utc, &tcr);
    int minutes = gps.time.minute();
    display.showNumberDec(minutes, true, 2, 2);
    int hours = gps.time.hour();
    updateTime();
    hours = hours + 1;
    //hours = hours+1;
    if (hours > 24)
      hours = hours - 24;
    // if-else to blink te colon
    int seconds = gps.time.second();
    if ((seconds % 2) == 0) {
      display.showNumberDecEx(hour(local), 0b01000000, true, 2, 0);
    } else {
      display.showNumberDecEx(hour(local), 0, true, 2, 0);
    }
  }
}
void setDisplayTime() {


  if (gps.time.isValid()) {
    time_t utc = now();
    time_t local = CE.toLocal(utc, &tcr);
    int minutes = gps.time.minute();
    display.showNumberDec(minutes, true, 2, 2);
    int hours = gps.time.hour();
    updateTime();
    hours = hours + 1;
    //hours = hours+1;
    if (hours > 24)
      hours = hours - 24;
    // if-else to blink te colon
    int seconds = gps.time.second();
    if ((seconds % 2) == 0) {
      display.showNumberDecEx(hour(local), 0b01000000, true, 2, 0);
    } else {
      display.showNumberDecEx(hour(local), 0, true, 2, 0);
    }
  }
}

void setDisplaySpeed() {
  if (gps.speed.isValid()) {
    double speed = gps.speed.kmph();
    display.showNumberDec(speed, false, 4, 0);
  }
}

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