#include <LiquidCrystal.h>

#define JOY_HORZ A0
#define JOY_VERT A1
#define JOY_SEL 2


class Joystick
{
  public:
  Joystick(int pinHorz, int pinVert, int pinSel, LiquidCrystal *lcd)
  {
    _pinSel = pinSel;
    _pinVert = pinVert;
    _pinHorz = pinHorz;    
    _deadZone = 100;
    _selState = 0;
    _lcd = lcd;
    _row = 0;
    _column = 0;
    _lcd->home();
    pinMode(_pinSel, INPUT);
    pinMode(_pinVert, INPUT);
    pinMode(_pinHorz, INPUT);
  }
  ~Joystick() = default;

  void process()
  {
    int y = analogRead(_pinVert);
    int x = analogRead(_pinHorz);
    int push = debounce();
    
    if(x > 512 + _deadZone)//влево
    {
      if(_column > 0)
      {
        --_column;
      }
      _lcd->setCursor(_column, _row);
    }
    else if(x < 512 - _deadZone)//вправо
    {
      if(_column < _kColumnsCount - 1)
      {
        ++_column;
      }
      _lcd->setCursor(_column, _row);      
    }

    if(y > 512 + _deadZone)//вверх
    {
      if(_letters[_column][_row] == 0)
      {
        _letters[_column][_row] = 'A';
      }
      else if(_letters[_column][_row] == 'Z')
      {
        _letters[_column][_row] = 'A';
      }
      else
      {
        ++_letters[_column][_row];
      }
      _lcd->write(_letters[_column][_row]);
      _lcd->setCursor(_column, _row);
    }
    else if(y < 512 - _deadZone)//вниз
    {
      if(_letters[_column][_row] == 'A' || _letters[_column][_row] == 0)
      {
        _letters[_column][_row] = 'Z';
      }
      else
      {
        --_letters[_column][_row];
      }
      _lcd->write(_letters[_column][_row]);
      _lcd->setCursor(_column, _row);
    }

    if(push != _selState)
    {
      if(_row == 0)
      {
        _row = 1;
      }
      else
      {
        _row = 0;
      }
      _lcd->setCursor(_column, _row);
      _selState = push;
    } 
  }

  private:
  int _pinSel;  
  int _pinHorz;
  int _pinVert;  
  int _selState;  
  int _deadZone;

  int _row;
  int _column;
  const int _kColumnsCount = 16;
  const int _kRowsCount = 2;
  char _letters[16][2]{};
  LiquidCrystal *_lcd;

  int debounce ()
  {
    int current = digitalRead(_pinSel);
    if(_selState != current)
    {
      delay(5);
      current = digitalRead(_pinSel);
    }
    return current;
  }
};

LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
Joystick joystick(JOY_HORZ, JOY_VERT, JOY_SEL, &lcd);

void setup() 
{
  analogReference(DEFAULT);
  lcd.begin(16, 2, LCD_5x8DOTS);
  lcd.cursor();
}

void loop() 
{
  joystick.process();
  
  delay(100);
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
joystick1:VCC
joystick1:VERT
joystick1:HORZ
joystick1:SEL
joystick1:GND
lcd1:VSS
lcd1:VDD
lcd1:V0
lcd1:RS
lcd1:RW
lcd1:E
lcd1:D0
lcd1:D1
lcd1:D2
lcd1:D3
lcd1:D4
lcd1:D5
lcd1:D6
lcd1:D7
lcd1:A
lcd1:K
r1:1
r1:2