(Extra Info Debouncing)

Herhaling: denderen van een signaal (debouncen)

Het sluiten van een schakelaar kan een denderend signaal veroorzaken. Het denderen is het meerdere malen kortstondig contact maken en verbreken van het contact. Dit wordt veroorzaakt door het “veren” van het metaal gedeelte van de schakelaar of knop.

In een combinatorische schakeling gaan we dit probleem niet opmerken, maar bij het gebruik in een sequentiële schakeling wel. Als de knop gebruikt wordt als kloksignaal kunnen de aangesloten ICs ook op de flanken van het denderend signaal reageren waardoor meerdere klokpulsen gedetecteerd worden.

Het denderen van een knop kan verholpen worden met zowel een analoge, digitale als een software oplossing; in het Engels spreekt men van een “debouncer”. In dit labo zal enkel een software oplossing gebruikt worden.

Softwarematige oplossing

In de Arduino IDE is een standaardoplossing voorzien om dit probleem aan te pakken. Deze oplossing kan je terugvinden onder “Bestand > Voorbeelden > 0.2Digital > Debounce” en is makkelijk te integreren in een eigen programma. Je kan de tutorial die bij deze code hoort ook terugvinden op deze locatie.

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 0;    // the number of the pushbutton pin
const int ledPin = 13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  // set initial LED state
  digitalWrite(ledPin, ledState);
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // set the LED:
  digitalWrite(ledPin, ledState);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

Debounce voor ESP32

De code hierboven geeft het Debounce-voorbeeld. Hierin is ledState de huidige toestand van een LED die je probeert aan te sturen, is buttonState de stabiele toestand die je op dat moment toegekend hebt aan de knop, en lastButtonState de vorige gelezen toestand van de knop.

Het principe van het programma is om met lastDebounceTime bij te houden wanneer de toestand van de knop het laatst veranderde. Als uitgangspunt dient dan dat als er genoeg tijd verlopen is sinds de vorige verandering, de huidige toestand van de knop stabiel is. Die verlopen tijd wordt aangeduid met debounceDelay met een standaardwaarde van 50ms.

Iedere loop() van het programma begint dus op dezelfde manier, met het lezen van de toestand van de knop. Als die toestand verschilt van de vorige toestand van de knop, meten we het huidige tijdstip met millis() en wijzen we het toe aan lastDebounceTime.

Daarna kijken we hoeveel tijd er verlopen sinds de laatste verandering (lastDebounceTime). Als er een tijd groter dan debounceDelay verlopen is, kunnen we er dus vanuit gaan dat de huidige knoptoestand stabiel is. De knop is ingedrukt of in rust, maar dendert niet meer. Er kan dan gekeken worden of de uiteindelijke stabiele waarde verschilt van de laatste stabiele waarde (buttonState). In het voorbeeld wordt dan de toestand van de LED omgedraaid (van 0 naar 1 of omgekeerd) als de knop ingedrukt is.

Ten slotte wordt de laatst gelezen toestand van de knop geschreven naar lastButtonState.