Malý dvouosý analogový joystick se hodí k ovládání pohybu ve dvou směrech současně, navíc poskytuje možnost sepnout v kterékoli poloze tlačítko stiskem hmatníku.
Modul joysticku má rozměr DPS 35×27 mm, výška včetně odnímatelného hmatníku je 38 mm. Tlačítko spíná vývod SW proti zemi, na desce je na horní straně místo pro pull-up rezistor R5, který ale není osazen. Potenciometry mají 10 kΩ a speciálně zkrácenou dráhu, takže při výchylce jen kolem 60° (od kraje do kraje) spolehlivě přejedou celý rozsah a dávají na výstupy VRx a VRy napětí od 0 do +5 V.
Kvůli jednoduché mechanické konstrukci má ovládání kolem neutrálu v jedné z os malou vůli a při stisku tlačítka se také nepatrně pohne poloha obou snímaných analogových os. Při okrajích rozsahu jsou širší oblasti, v nichž se už výstupní napětí nemění a je na jedné nebo druhé mezi. Lineární změna napětí zabírá úhel výchylky kolem 30° (±15°). Tyto typy joysticků se používají do RC souprav levných modelů a hraček
K vyzkoušení můžeme použít následující program pro Arduino, který na displeji 20×4 zobrazuje dva progressbary a vychází z programu zveřejněného zde. Na displeji se zobrazuje výsledek AD převodu jak číselně, tak graficky. Jeko referenční napětí je použito napájení společné pro mikrokontrolér i joystick. V pravém horním rohu se zobrazuje buď tečka, nebo plné pole – podle stisku tlačítka.
// test joysticku na displeji 20x4, progressbary na prvnich dvou radcich v rozsahu ADC prevodu 0 - 1023 #include <Wire.h> #include <LiquidCrystal_I2C.h> // nastavena adresa 0x3F a poradi pinu displeje na prevodniku: en,rw,rs,d4,d5,d6,d7,bl,blpol LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); int joy_x, joy_y, joy_z; void setup() { // Graficke znaky 6 a 7 volne pro jine pouziti byte g0[8] = {B00000, B00000, B00000, B10101, B10000, B10000, B10000, B10101}; //0 |__ byte g1[8] = {B00000, B00000, B00000, B10101, B10100, B10100, B10100, B10101}; //1 ||_ byte g2[8] = {B00000, B00000, B00000, B10101, B10101, B10101, B10101, B10101}; //2 ||| byte g3[8] = {B00000, B00000, B00000, B10101, B00000, B00000, B00000, B10101}; //3 ___ byte g4[8] = {B00000, B00000, B00000, B10101, B00001, B00001, B00001, B10101}; //4 __| byte g5[8] = {B00000, B00000, B00000, B10101, B10001, B10001, B10001, B10101}; //5 |_| lcd.begin(20, 4); // zavedeni grafiky do RAM displeje 20x4 lcd.createChar(0, g0); lcd.createChar(1, g1); lcd.createChar(2, g2); lcd.createChar(3, g3); lcd.createChar(4, g4); lcd.createChar(5, g5); pinMode(7, INPUT_PULLUP); } class ProgressBar { private: int line; unsigned int currentProgress = 0; // Jaky stav je prave ted unsigned long lastUpdate = 0; // Cas zmeny int smer = 0; public: // Inicializace nastavi progress a cas na nuly, vykresli prazdny progress bar na 3. radku ProgressBar(int where) { line = where; smer = 0; currentProgress = 0; lastUpdate = 0; lcd.setCursor(0, line); lcd.write((byte)0); // posilame byte 0 for (int i = 1; i < 19; i++) { lcd.write(3); } lcd.write(4); } // Posle progress baru pozadavek na zmenu. Posune se max o 1 "carku" bliz k pozadovane hodnote. // Prubeh trva zhruba stejne dlouho pri jakemkoliv scenari. // Pokud je moc "brzo" - nic nevykresli, pokud chci zobrazit uz zobrazovany stav - nic neprekresluje. // @param progress - pozadovany cil 0-60 (na 20 znacich) respektive zobrazi 59 ruznych hodnot. void updateProgress(int progress) { unsigned long currentMillis = millis(); if (currentMillis - lastUpdate < 2) { // 2 ms = refresh rate, kdy NEJDRIV se muze menit delay(1); return; } lastUpdate = currentMillis; progress = min(progress, 59); progress = max(progress, 1); //60 znakovy bar, namapujem na 59 hodnot if (currentProgress == progress) { delay(1); return; } else if (currentProgress < progress) { if (smer < 0 && currentProgress % 3 == 2) { lcd.setCursor(currentProgress / 3, line); //presun na spravne souradnice lcd.write(2); currentProgress++; smer = 1; return; } currentProgress++; lcd.setCursor(currentProgress / 3, line); //presun na spravne souradnice smer = 1; if (currentProgress < 57) { lcd.write(currentProgress % 3); //vypise 1, 2 nebo 3 "carky" do znaku } else if (currentProgress == 57) { lcd.write(5); // predposledni znak } else if (currentProgress == 58) { lcd.write(2); //posledni znak } } else { if (smer > 0 && currentProgress % 3 == 0) { lcd.setCursor(currentProgress / 3, line); //presun na spravne souradnice lcd.write(3); currentProgress--; smer = -1; return; } currentProgress--; lcd.setCursor(currentProgress / 3, line); //presun na spravne souradnice smer = -1; if (currentProgress < 57) { switch (currentProgress % 3) { case 0: lcd.write(3); break; case 1: lcd.write((byte)0); break; case 2: lcd.write(1); break; } } else if (currentProgress == 57) { lcd.write(4); // predposledni znak } else if (currentProgress == 58) { lcd.write(5); //posledni znak } } } }; // test joysticku, na prvnim radku osa x (ADC A0), na druhem osa y (ADC A1) void loop() { ProgressBar bar1(1); // definice dvou progressbaru ProgressBar bar2(3); while (1) { // nekonecny cyklus joy_x = analogRead(A0); // nacteni napeti X joy_y = analogRead(A1); // nacteni napeti Y lcd.setCursor(0, 0); // popis a hodnota X lcd.print("osa X: "); lcd.print(joy_x); lcd.print(" "); lcd.setCursor(15, 0); // zobrazeni stisku tlacitka lcd.print("TL: "); if (digitalRead(7) == LOW) { lcd.write((byte)255); } else { lcd.write(B10100101); } bar1.updateProgress(map(joy_x, 0, 1023, 0, 60)); // prvni progressbar lcd.setCursor(0, 2); // popis a hodnota Y lcd.print("osa Y: "); lcd.print(joy_y); lcd.print(" "); bar2.updateProgress(map(joy_y, 0, 1023, 0, 60)); // druhy progressbar } }