Jeden pin – wiele przycisków

Czasem robiąc bardziej rozbudowany projekt na moim Arduino Uno zdarzyło mi się, że brakło pinów cyfrowych. W dzisiejszym artykule zaprezentuję ciekawy sposób na zredukowanie liczby pinów wykorzystywanych przez przyciski.

Jak wiadomo najłatwiejszą i chyba najpewniejszą metodą podłączania przycisków jest ta, gdzie każdy przycisk podłączony jest do osobnego pinu wejścia/wyjścia. Niekiedy jednak zdarza się, że aby wszystkie funkcjonalności naszego urządzenia mogły być zaimplementowane musimy oszczędzać cenne piny cyfrowe. Możemy np. podłączyć 16 przycisków używając tylko 8 pinów krzyżując ze sobą wiersze z kolumnami. Inną ciekawą opcją wykorzystującą tylko jeden pin analogowy jest stworzenie dzielnika napięcia.

Zasada działania + schemat

Nasze Uno posiada aż 6 pinów analogowych zdolnych zmierzyć napięcie z zakresu 0-5V z 10 bitową dokładnością (co przekłada się na wartości od 0 do 1023). Z prawa Ohma wiemy też, że możliwe jest stworzenie dzielnika napięcia i to 5V, którym zasilamy nasze Arduino możemy podzielić np. na 1, 2, 3 , 4 i 5 V. Wystarczą nam do tego zwykłe rezystory (ja użyłem takich o wartości 1,1k) połączone szeregowo. Do jednego końca podłączamy +5V, a do drugiego masę. W ten sposób na każdym łączeniu uzyskamy inny potencjał, który możemy odczytać za pomocą pinu analogowego Arduino.

Aby wybrane napięcie było przekazywane na port analogowy Arduino wystarczy jedną nóżką przełącznika podłączyć się do nóżki rezystora, a drugą wprost do pinu analogowego.  Dodatkowo podłączymy też podciągnięcie pinu analogowego do masy, aby zawsze był tam jakiś konkretny stan (nawet w przypadku, kiedy nie jest wciśnięty żaden przycisk).

Myślę, że dużo z tego co napisałem powyżej rozjaśni schemat, który zamieszczam:

Obsługa przycisków

Cała magia polega na odczytaniu odpowiedniej wartości na porcie analogowym. Jako pierwszy szkic wgrałem do Arduino program, który w głównej pętli co 100 ms wypisuje na port szeregowy linię z wartością odczytaną przez przetwornik ADC.

Następnie uruchomiłem kreślarkę wbudowaną w Arduino IDE i odczytałem wartości dla każdego z przycisków.

Teraz znając już te wartości możemy zadeklarować sobie kilka przydatnych stałych:

#define BTN_PIN A0

#define BTN1    255
#define BTN2    340
#define BTN3    512
#define BTN4    1023

Są to wartości obliczone przez przetwornik analogowo-cyfrowy.

Do tego napisałem sobie pomocniczą funkcję, która zwróci prawdę lub fałsz w zależności od tego, czy przycisk jest wciśnięty:

bool isAnalogBtnPressed(int analogVal, int btnValue) {
  return abs(btnValue - analogVal) <= 20;
}

Przyjmuje ona 2 parametry: analogVal, czyli wartość odczytaną za pomocą funkcji analogRead oraz btnValue, czyli wartość dla aktualnie sprawdzanego przycisku.

Jak widać za pomocą funkcji abs() sprawdzamy jak daleko na osi leży rzeczywisty odczyt z ADC od tego, który powinien reprezentować przycisk. Jeżeli odległość ta jest nie większa niż 20 to funkcja zwróci prawdę. Ustaliliśmy sobie tutaj pewien próg błędu z uwagi na to, że pomiar z ADC nie zawsze będzie idealny.

Teraz możemy napisać główną pętle programu, która wypisze na port szeregowy stosowny komunikat, jeżeli wciśniemy jakiś przycisk.

void loop() {
  int btnData = analogRead(BTN_PIN);
  if(isAnalogBtnPressed(btnData, BTN1)) {
    Serial.println("Wcisnieto przycisk 1");
  } else if(isAnalogBtnPressed(btnData, BTN2)) {
    Serial.println("Wcisnieto przycisk 2");
  }  else if(isAnalogBtnPressed(btnData, BTN3)) {
    Serial.println("Wcisnieto przycisk 3");
  }  else if(isAnalogBtnPressed(btnData, BTN4)) {
    Serial.println("Wcisnieto przycisk 4");
  }

  delay(100);
}

nie zapomnijmy także o odpowiedniej konfiguracji w funkcji setup():

void setup() {
  pinMode(BTN_PIN, INPUT);
  Serial.begin(9600);
}

I to już wszystko :) Dzięki takiemu prostemu zabiegowi zredukowaliśmy liczbę pinów z 4 do 1, a przecież nic nie stoi na przeszkodzie, żeby dołożyć tam jeszcze więcej przycisków. Wykorzystując ten sposób należy pamiętać, że nie będziemy mogli wcisnąć więcej niż jednego przycisku na raz. W takim przypadku priorytetem będzie wartość napięcia po wciśnięciu przyciku. Jeżeli wciśniemy na raz przycisk, pod któym mamy 4 V oraz taki pod któym są 2 V, to arduino odczyta ten z wyższym napięciem (czyli wygra mniejsza rezystancja).

5 myśli nt. „Jeden pin – wiele przycisków

  1. Michal

    Czy odczyt bedzie zawsze identyczny czy moze jednak powinnismy zrobic zakresy a nie stałe wartości?

    Odpowiedz
    1. Kamil Autor wpisu

      Powinny być zakresy i są :) Zobacz, że funkcja isAnalogBtnPressed() zwraca prawdę tylko, jeżeli zmierzona wartość jest w zakresie +/-20 dla danego przycisku. W ten sposób jest tutaj zaimplementowany ten przedział.

      Odpowiedz
  2. Michael

    Sorry, I don’t speak Polish. I read the article via Google Translater, so I try it in English. I understand the principle, but as stated in the picture, it will not work. You have arranged the wires to the buttons by two points too far to the left.

    Odpowiedz
    1. Kamil Autor wpisu

      Indeed there was a mistake in schematics. I have corrected it, thank you for your help :)

      Odpowiedz
  3. Michael

    Fine. I just forgot to tell you earlier what a great blog You operate. I would be glad if I had this endurance and passion. I’m impressed.

    Odpowiedz

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *