A click that counts once
The switch under the stick is two metal contacts, and they chatter for a moment as they meet and as they part. A loop that counts every HIGH, or every change, counts one press as several. Count the change from LOW to HIGH, then look away for 20 ms.
Contacts bounce
When you press the stick, two pieces of metal inside the switch meet. They do not meet once: they touch, spring apart and touch again several times in the first few milliseconds before they settle, and the same happens when they part. The pull-down and the SW light see every one of those, and so does a loop fast enough to look.
Press it once and count. Counting every change from LOW to HIGH finds a click for each chatter, on the way down and on the way up. Counting the first change and then not looking for 20 ms finds one. The trace is a picture of the behaviour: this switch's bounce is not published.
Count the change, then wait
Two rules, and each fixes a different mistake. Count the change, not the level, or holding the stick down counts every time round the loop. And after a change, leave the pin alone for a short time, longer than the chatter and shorter than a person can click again:
const unsigned long DEBOUNCE_MS = 20;
int lastSw = LOW;
unsigned long quietUntil = 0;
void checkClick() {
unsigned long now = millis();
if (now < quietUntil) return; // still settling
int sw = digitalRead(SW_PIN);
if (sw != lastSw) {
if (sw == HIGH) Serial.println("click");
lastSw = sw;
quietUntil = now + DEBOUNCE_MS;
}
}Call checkClick() from loop() as often as you like. It prints once per
press, and the release is caught by the same wait without counting. Eight
directions uses
exactly these lines.
Why not a delay
A delay(20) after each change does the same for the click, but it stops
everything else too, and a joystick sketch is usually reading the stick at
the same time. Comparing against millis() lets the loop keep reading X and
Y while SW settles.
When it does not work
The chatter on this switch lasted longer than the wait. Make DEBOUNCE_MS 30 or 50. A person cannot click the stick more than a few times a second, so even 50 ms loses nothing.
The sketch is counting the level, HIGH, instead of the change from LOW to HIGH. Keep the last reading and count only when it was LOW and is now HIGH.
The second press came inside the wait. Shorten DEBOUNCE_MS towards 10 ms; below that, the chatter starts to leak through again.
Edit this page — content/books/dual-axis-joystick/a-click-that-counts-once.mdx
Questions about this product
See what other owners have asked, and read their solutions.
Dual Axis Joystick
Loading discussions…
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.