Debouncing a rising edge detector

Hi!

I bought my first arduino uno today and have been slowly learning throughout the day. Made a working digit counter but noticed it was skipping sometimes, then I learned about debouncing and implemented this into my sketch but it seems to make it worse. Now sometimes when i push the button it doesnt respond.

Sketch without debounce:

int lastState = LOW;
int count = 0;
int A = 3;
int B = 4;
int C = 5;
int D = 6;
int E = 8;
int F = 9;
int G = 10;
int Button = 2;
int buttonState = LOW;


void setup() {
  // put your setup code here, to run once:
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(Button, INPUT);
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
}

//void loop() {
//  // put your main code here, to run repeatedly:
//}

void loop() {
buttonState=digitalRead(Button);
  if (buttonState == HIGH) {
    if (buttonState != lastState) {
      count++;
      if (count == 10) {
        count = 0;
      }
      if (count != 1 && count != 2 && count != 3 && count != 7) {
        digitalWrite(A, HIGH);
      } else {
        digitalWrite(A, LOW);
      }

      if (count != 1 && count != 4) {
        digitalWrite(B, HIGH);
      } else {
        digitalWrite(B, LOW);
      }

      if (count != 5 && count != 6) {
        digitalWrite(C, HIGH);
      } else {
        digitalWrite(C, LOW);
      }
      if (count != 1 && count != 0 && count != 7) {
        digitalWrite(D, HIGH);
      } else {
        digitalWrite(D, LOW);
      }

      if (count == 2 || count == 6 || count == 8 || count == 0) {
        digitalWrite(E, HIGH);
      } else {
        digitalWrite(E, LOW);
      }

      if (count != 1 && count != 4 && count != 7) {
        digitalWrite(F, HIGH);
      } else {
        digitalWrite(F, LOW);
      }

      if (count != 2) {
        digitalWrite(G, HIGH);
      } else {
        digitalWrite(G, LOW);
      }

      delay(20);
      lastState = digitalRead(Button);
    } else {
      delay(20);
      lastState = digitalRead(Button);
    }
  }
}

Sketch with debounce:

int lastState = LOW;
int count = 0;
int A = 3;
int B = 4;
int C = 5;
int D = 6;
int E = 8;
int F = 9;
int G = 10;
int Button = 2;
int buttonState = LOW;
int lastButtonState = LOW;
int reading=LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void setup() {
  // put your setup code here, to run once:
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(Button, INPUT);
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
}

//void loop() {
//  // put your main code here, to run repeatedly:
//}

void loop() {

reading = digitalRead(Button);

  if (reading != lastButtonState)  {
    lastDebounceTime = millis();
  }
  if ((millis()-lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;




    if (buttonState == HIGH) {
      if (buttonState != lastState) {
        count++;
        if (count == 10) {
          count = 0;
        }
        if (count != 1 && count != 2 && count != 3 && count != 7) {
          digitalWrite(A, HIGH);
        } else {
          digitalWrite(A, LOW);
        }

        if (count != 1 && count != 4) {
          digitalWrite(B, HIGH);
        } else {
          digitalWrite(B, LOW);
        }

        if (count != 5 && count != 6) {
          digitalWrite(C, HIGH);
        } else {
          digitalWrite(C, LOW);
        }
        if (count != 1 && count != 0 && count != 7) {
          digitalWrite(D, HIGH);
        } else {
          digitalWrite(D, LOW);
        }

        if (count == 2 || count == 6 || count == 8 || count == 0) {
          digitalWrite(E, HIGH);
        } else {
          digitalWrite(E, LOW);
        }

        if (count != 1 && count != 4 && count != 7) {
          digitalWrite(F, HIGH);
        } else {
          digitalWrite(F, LOW);
        }

        if (count != 2) {
          digitalWrite(G, HIGH);
        } else {
          digitalWrite(G, LOW);
        }

        delay(20);
        lastState = digitalRead(Button);
      } else {
        delay(20);
        lastState = digitalRead(Button);
      }
}







      }
    }
lastButtonState = reading;
}

Is there a problem with debouncing and rising edge detectors?

Thanks in advance,
Moshtaraq

Download and look at the Bounce or Bounce2 library. They have already implemented robust debounce algorithms.

Also, you have your button as in input. Do you have an external pullup attached? It is more common to connect one side of the button to ground and the other to you digital pin and then use the internal pullup. This reverses the logic (HIGH = no button press, LOW = button press)

Even though the button libraries can save some effort, it is nevertheless a good learning experience to get it right yourself.
You should remove the two delay() statements from the loop.
You are maintaining two different state histories , laststate and lastbuttonstate. Another approach is simply to accept any difference between the current state and that read from the button but only if more than X mS has elapsed since the last valid change. That means, on accepting a change of state, you set a timer so you check that future changes of state which come too soon are ignored.

6v6gt:
Even though the button libraries can save some effort, it is nevertheless a good learning experience to get it right yourself…

Amen to that.

blh64:
Download and look at the Bounce or Bounce2 library. They have already implemented robust debounce algorithms.

Also, you have your button as in input. Do you have an external pullup attached? It is more common to connect one side of the button to ground and the other to you digital pin and then use the internal pullup. This reverses the logic (HIGH = no button press, LOW = button press)

I have a pull down resistor on the button, I read about the internal resistor after i made the post and it's something I will look into. Just don't want to forget to set it up and burn something though..... I'll give the library's a try but i really want to know and understand how something like a debounce is implemented.

The debounce example in the IDE can show you how it’s done.

The basics is that you read an input, check if it changed compared to the previous reading and remember the time (millis()) if the reading changed. If millis() minus remembered time is longer than a given interval (e.g. 20 ms), the state of the input did not change in that interval and the input is stable.

6v6gt:
Even though the button libraries can save some effort, it is nevertheless a good learning experience to get it right yourself.
You should remove the two delay() statements from the loop.
You are maintaining two different state histories , laststate and lastbuttonstate. Another approach is simply to accept any difference between the current state and that read from the button but only if more than X mS has elapsed since the last valid change. That means, on accepting a change of state, you set a timer so you check that future changes of state which come too soon are ignored.

I deleted the delay()'s and eliminated the double states. I think it's working properly, are there changes I can make to make it more elegant?

int lastState = LOW;
int buttonState = LOW;
int count = 0;
int A = 3;
int B = 4;
int C = 5;
int D = 6;
int E = 8;
int F = 9;
int G = 10;
int Button = 2;
unsigned long lastDebounceTime = 0;
int debounceDelay = 25;
int reading=LOW;

void setup() {
  // put your setup code here, to run once:
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(Button, INPUT);
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  Serial.begin(9600);
}

void loop() {
  reading = digitalRead(Button);
  if (reading != lastState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {

        count++;
        Serial.print("millis");
        Serial.print("\t");
        Serial.print(millis());
        Serial.print("\n");
        Serial.print("lastDebounceTime");
        Serial.print("\t");
        Serial.print(lastDebounceTime);
        Serial.print("\n");

        if (count == 10) {
          count = 0;
        }
        Serial.print("count");
        Serial.print("\t");
        Serial.print(count);
        Serial.print("\n");
        if (count != 1 && count != 2 && count != 3 && count != 7) {
          digitalWrite(A, HIGH);
        } else {
          digitalWrite(A, LOW);
        }

        if (count != 1 && count != 4) {
          digitalWrite(B, HIGH);
        } else {
          digitalWrite(B, LOW);
        }

        if (count != 5 && count != 6) {
          digitalWrite(C, HIGH);
        } else {
          digitalWrite(C, LOW);
        }
        if (count != 1 && count != 0 && count != 7) {
          digitalWrite(D, HIGH);
        } else {
          digitalWrite(D, LOW);
        }

        if (count == 2 || count == 6 || count == 8 || count == 0) {
          digitalWrite(E, HIGH);
        } else {
          digitalWrite(E, LOW);
        }

        if (count != 1 && count != 4 && count != 7) {
          digitalWrite(F, HIGH);
        } else {
          digitalWrite(F, LOW);
        }

        if (count != 2) {
          digitalWrite(G, HIGH);
        } else {
          digitalWrite(G, LOW);
        }
      }
    }
  }
  lastState = reading;
}

sterretje:
The debounce example in the IDE can show you how it's done.

The basics is that you read an input, check if it changed compared to the previous reading and remember the time (millis()) if the reading changed. If millis() minus remembered time is longer than a given interval (e.g. 20 ms), the state of the input did not change in that interval and the input is stable.

I saw that on the website also, but was confused as to where to put my actual code for changing LED's/Displays. Now that i understand it, is it worth trying to make this into a function e.g. debounceInput(pin) or something like that? or just use the library (which i still haven't looked at btw)

It definitely is useful to put it in a function.

If you have multiple buttons, consider using an array of structs. A struct can combine all needed variables (time, pin number, state, ...) for one button into a new type.

sterretje:
It definitely is useful to put it in a function.

If you have multiple buttons, consider using an array of structs. A struct can combine all needed variables (time, pin number, state, ...) for one button into a new type.

Those are a lot of big words I need to look into! Thanks for giving me a direction!

Moshtaraq:
Now sometimes when i push the button it doesnt respond.

void loop() {

reading = digitalRead(Button);

if (reading != lastButtonState)  {
    lastDebounceTime = millis();
  }

if ((millis()-lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

// working code goes here

}
    }
lastButtonState = reading;
}

Yeah, it's a little subtle. You unconditionally set lastButtonState equal to reading even if that change of reading was ignored due to debounce. So if you release the button and then press and hold it again within 50ms, which I suppose is possible, the press will get ignored by the debounce, but once the debounce timer expires the fact that the button is down will be ignored, because the code will be like "yeah, the button is down, but it was down last time I checked so nothing new has happened".

To fix, move lastButtonState = reading; inside the debounce if().