Debouncing klawiszy w Nettigo Keypad (i nie tylko)

Biblioteka do Nettigo Keypada została uaktualniona o domyślne wsparcie dla debouncingu. O co chodzi? Jeżeli naciskasz klawisz, może pojawić się zjawisko migotania podczas włączania i wyłączania przycisku. Wynika to właściwości styku mikroprzełącznika – jest to mechaniczne zetknięcie/rozłączenie styków, więc może być tak że pojawi się szereg impulsów podczas jednego przełączenia.

Gdy Arduino często sprawdza stan klawisza takie migotanie może zostać odczytane jako wielokrotne naciśnięcia i zwolnienia danego przycisku, mimo że został naciśnięty tylko raz.

Jak temu zapobiegać?

Potrzebny jest tak zwany debouncing. Można po odczycie stanu klawisza poczekać chwilę używając delay. Proste i skuteczne.

Pseudokod realizujący to wygląda tak:

obecny_stan_klawisza = odczytaj_klawisz();
if (obecny_stan_klawisza != poprzedni_stan) {
  poprzedni_stan = obecny_stan_klawisza;
  zrob_cos_po_zmianie_stanu();
  delay(50);
}

Taki kod po wykryciu zmiany stanu klawisza zapisuje jego nową wartość , wykonuje co trzeba po naciśnięciu/zwolnieniu klawisza i czeka 50 milisekund, zanim podejmie dalsze wykonywanie programu. Jeżeli więcej nic specjalnie szkic nie ma do roboty to zapobiegnie to odczytaniu migotania w następnym przebiegu loop.

Takie rozwiązanie, choć proste ma jednak jedną niezaprzeczalną wadę – Arduino nic nie może innego robić w czasie gdy czeka korzystając z funkcji delay. Nie zawsze jest to dopuszczalne. Jeżeli nasz szkic robi coś co wymaga szybkiej pracy, lub ścisłych zależności czasowych (generowanie obrazu, programowe implementacje różnych protokołów) takie rozwiązanie jest wykluczone.

Co zostaje? Trzeba zignorować wszystkie zmiany stanu klawisza w krótkim czasie po zaobserwowaniu jego wciśnięcia. Zapamiętujemy czas wciśnięcia klawisza i jeżeli zmiany stanu następują w krótkim czasie po tym – są ignorowane. Znowu – pseudokod:

obecny_stan_klawisza = odczytaj_klawisz();
if (obecny_stan_klawisza != poprzedni_stan && millis() - czas_ostatniego_wcisniecia > timeout) {
  poprzedni_stan = obecny_stan_klawisza;
  czas_ostatniego_wcisniecia = millis()
  zrob_cos_po_zmianie_stanu();
}

Oczywiście, na starcie szkicu musimy ustawić wartość czas_ostatniego_wcisniecia i timeout – zostawione bez nadanej wartość mogą stwarzać problemy. Czas jaki trzeba czekać ignorując zmiany stanu zależy od przełącznika. W wypadku mikroprzełączników 50 ms wystarcza w zupełności.

Dla wejść cyfrowych są gotowe biblioteki do obsługi debouncingu np Bounce, jednak dla naszego keypada ona się nie nadaje.

Dlatego biblioteka do Nettigo Keypada ma od wersji 0.3 domyślnie debouncowane klawisze. Domyślnie timeout jest ustawiony na 50 ms. Można go odczytać/zmienić przez funkcje getDebounceDelay i setDebounceDelay.