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
}
}



