Analogový joystick

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.

IMGP2309bKvů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

IMGP2313b

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.

IMGP2324b

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