Autor projektu, początkowo chciał skonstruować prosty panel z jednym przyciskiem z programowalnymi funkcjami, aby móc sterować swoim laptopem bez konieczności podchodzenia do samej maszyny. Potem natrafił na zbiór przycisków wykonanych w takim stylu, że kojarzony jest ze starymi maszynami do gier. To sprawiło, że zmienił plany i zdecydował się na konstrukcje panelu z wieloma przyciskami, z których każdy z nich może pełnić rolę programowalnego skrótu klawiszowego, lub wręcz sekwencji klawiszy.
Projekt zawiera moduł Adafruit Trinket M0 i symuluje działanie klawiatury. Autor dużo uwagi przyłożył do konstrukcji obudowy, jednak w artykule skupimy się na elektronice i oprogramowaniu urządzenia. Obudowę urządzenia można zbudować na wiele sposobów, zależnie od tego, jakie posiadamy narzędzia. Autor na stronie z projektem prezentuje dwa różne podejścia do konstrukcji obudowy i udostępnia wszystkie potrzebne pliki projektowe, nawet projekt gotowy do druku 3D. Można oczywiście zmienić obudowę zupełnie, czy zastosować inne przyciski, aby stworzyć dopasowany do swoich wymagań panel skrótów klawiszowych.
Potrzebne elementy
Do zbudowania obudowy, takiej jak prezentuje autor potrzebne będą następujące elementy:
- pleksi o grubości 3 mm,
- klej do pleksi,
- pięć przycisków w stylu starych automatów do gier,
- gumowe nóżki (podstawki) urządzenia.
Jeśli zdecydujemy się na wydrukowanie zaprojektowanej przez autora obudowy, musimy się zaopatrzyć tylko w klej cyjanoakrylowy.
Do budowy elektroniki potrzebne będą następujące komponenty:
- moduł Adafruit Trinket M0,
- zworki kablowe,
- goldpiny do wlutowania w moduł z mikrokontrolerem.
Połączenia elektryczne
Zamiast łączyć przyciski z modułem mikrokontrolera na stałe, autor przylutował do niego goldpiny, aby podłączenia przycisków do układu wykonać przy pomocy typowych przewodów połączeniowych. Analogicznie, po stronie przycisków, także znajdują się goldpiny. Piny do modułu Trinket wlutowane są do góry nogami, aby można było przykleić moduł w obudowie z wykorzystaniem taśmy dwustronnej.
Schemat połączeń elektrycznych w systemie został pokazany na rysunku 1. Jedna strona przycisków jest podłączona do masy modułu Trinket. Z kolei druga nóżka podłączona jest do wejścia cyfrowego. Przyciski łączone są po kolei do pinów z wejściami 0, 1, 2, 3 oraz 4 w systemie. Dzięki temu przyciski są w pełni niezależne i każdy z nich może obsługiwać zupełnie osobną i niezależną funkcję. Po podłączeniu zworek kablowych, wystarczy tylko wkleić moduł z mikrokontrolerem gdzieś w obudowie w taki sposób, aby zapewnić dostęp do portu USB z zewnątrz. Zamiast przyklejania modułu na taśmę dwustronną, można oczywiście zamontować moduł w inny sposób, np. z pomocą uchwytu wydrukowanego na drukarce 3D itp.
Oprogramowanie
Kluczowym elementem systemu jest oczywiście oprogramowanie. System nie będzie działał, jeśli nie zaprogramujemy go odpowiednim skryptem. Na listingu 1 został pokazany szkic Arduino, który zastosowano do uruchomienia opisywanego modułu.
#include "Keyboard.h"
//char ctrlKey = KEY_LEFT_GUI; // zakomentuj dla Win
char ctrlKey = KEY_LEFT_CTRL; // zakomentuj dla OSX
char altKey = KEY_LEFT_ALT; // zakomentuj dla OSX
int buttonNum[5] = {3, 4, 2, 0, 1};
int buttSelect = 0;
int buttFlag = 0;
void setup() {
Serial.begin(115200);
for (int x = 0; x < 5; x++) {
pinMode(buttonNum[x], INPUT_PULLUP);
attachInterrupt(buttonNum[x], buttPressed, LOW);
}
Keyboard.begin();
}
void loop() {
while (buttFlag == 0) {
delay(10);
}
Serial.print("Button ");
Serial.print(buttSelect);
Serial.println(" pressed.");
switch (buttSelect) { // Uruchammianie komend
case 0:
Command0();
break;
case 1:
Command1();
break;
case 2:
Command2();
break;
case 3:
Command0();
break;
case 4:
Command1();
delay(1000);
Command2();
break;
default:
break;
}
int pressed = digitalRead(buttSelect);
while (pressed == 0) {
pressed = digitalRead(buttSelect);
}
buttFlag = 0;
}
void buttPressed() {
buttFlag = 1;
for (int x = 0; x < 5; x++) {
int butt = digitalRead(x);
if (butt == LOW) {
buttSelect = x;
break;
}
}
}
// Poniżej zdefiniować można własne komendy
void Command0() {
Serial.println("Pressing CTRL+U");
Keyboard.press(ctrlKey);
Keyboard.press(‘u’);
delay(100);
Keyboard.releaseAll();
delay(500);
}
void Command1() {
Serial.println("Pressing CTRL+ALT+N");
Keyboard.press(ctrlKey);
Keyboard.press(altKey);
Keyboard.press(‘n’);
delay(100);
Keyboard.releaseAll();
delay(500);
}
void Command2() {
Keyboard.println("HelloWorld");
}
void Command3() {}
void Command4() {}
Kod źródłowy do Arduino, obsługujący panel z klawiszami, jest bardzo prosty. Zastosowana została biblioteka keyboard.h, która realizuje kompletną emulację klawiatury PC. W zależności od systemu operacyjnego, z jakim ma współpracować klawiatura – OS X czy Windows/Linux, należy wybrać odpowiednie klawisze specjalne. W pierwszej sekcji kodu – setup(), konfigurowane są wszystkie wejścia cyfrowe (piny zdefiniowane w tablicy buttonNum. Dla każdego pinu załączane jest wewnętrzne podciąganie do plusa zasilania, dzięki czemu nie musimy tego robić fizycznie w systemie, co znacznie upraszcza jego konstrukcję. Podciaganie dołączone jest do wartości logicznej 1 więc naciśnięcie przycisku oznacza wystąpienie zbocza opadającego – w ten sposób właśnie skonfigurowane są przerwania, za pomocą funkcji attachInterrupt. Wystąpienie stanu niskiego (LOW) na jednym z pinów z tablicy buttonNum spowoduje uruchomienie funkcji buttPressed. Finalnie w sekcji tej uruchamiana jest klawiatura za pomocą metody Keyboard.begin(). Funkcja buttPressed jest bardzo prosta. Po jej wywołaniu ustawia ona flagę naciśnięcia przycisku buttFlag, a następnie odczytuje wartości logiczne z pinów buttonNum, ustawiając numer naciśniętego przycisku w zmiennej buttSelect.
Główna pętla programu – loop(), oczekuje na naciśnięcie przycisku. W momencie, gdy flaga buttFlag zostanie ustawiona, skrypt uruchamia za pomocą switch(buttSelect) jedną z funkcji, które zapisane są poniżej. Dla przycisków 0, 1 i 2 jest to, odpowiednio Command0(), Command1() oraz Command0(). Dla przycisku czwartego ponownie Command0(), a dla piątego bardziej złożona kombinacja – najpierw Command1(), a po sekundzie (delay(1000)) Command2(). Wszystkie te funkcje zdefiniowane są poniżej.
Autor w przykładowym programie zdefiniował tylko trzy pierwsze funkcje. Pierwsza i druga z nich naciskają kombinację klawiszy, odpowiednio CTRL+u i CTRL+n. Naciśnięcie klawisza realizuje się metodą Keyboard.press(‘klawisz’), a ich puszczenie powoduje metoda Keyboard.releaseAll(). Trzecia komenda wykorzystuje metodę Keyboard.println(‘tekst’), która pozwala wpisać z klawiatury cały ciąg znaków.
Komendy można w dowolny sposób konfigurować i łączyć ze sobą w sekwencje, aby dopasować do konkretnych potrzeb użytkownika. Wystarczy zapisać swoje własne skróty klawiszowe i sekwencje we wszystkich pięciu komendach i uzupełnić w głównej pętli programu wywołanie poszczególnych funkcji CommandX().
Jedyne co zostało do zrobienia, to skompilowanie i wgranie szkicu do mikrokontrolera i podłączenie układu do komputera. Powinien on zostać automatycznie wykryty, jako klawiatura i tak właśnie działać. Po naciśnięciu dowolnego z przycisków komputer powinien zareagować zgodnie z zaprogramowaną funkcją.
Nikodem Czechowski, EP