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).
Czy odczyt bedzie zawsze identyczny czy moze jednak powinnismy zrobic zakresy a nie stałe wartości?
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ł.
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.
Indeed there was a mistake in schematics. I have corrected it, thank you for your help :)
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.