Overview

This project reads values from a Joystick and displays the readings on an LCD screen with an I2C backpack. The sketch captures and prints the following parameters:-

  • Select pin status (pressed/not pressed)
  • Direction the joystick has been pushed:
    • North
    • South
    • East
    • West
    • North West
    • North East
    • South West
    • South East

Components

Component NamePurpose
Arduino NanoThe microcontroller.
Dual axis joystickThe Joystick module
I2C LCD 20X4The LCD display

Circuit Diagram

nano_potentiometer_LED_fritzing

Assembly

Dual-axis Joystick Pin Connections

Nano PinJoystick Pin
A0vertical pin
A1horizontal pin
D12select pin
5VVCC
GndGnd

I2C LCD Pin Connections

Nano PinI2C LCD Pin
A4SDA
A5SCL
5VVCC
GNDGND

Code

/*
  Project: Joystick input with output as LCD with I2C Backpack
  Project Description:
  This sketch writes data from the joystick input to an LCD display module.
  This sketch is for a 20x4 screen.
 
  Author: STEMVentor Educonsulting
  
  This code is copyrighted. Please do not reuse or share for any purpose other than for learning with subscribed STEMVentor programs.
  This code is for educational purposes only and is not for production use.
*/
 
// LIBRARIES
#include <Wire.h> // Used for communicating with I2C devices
 
// Install the LiquidCrystal I2C by Frank de Brabander from the IDE library manager. 
#include <LiquidCrystal_I2C.h>
 
 
// PIN DEFINITIONS 
 
// For Arduino Nano
// #define VertPin A1
// #define HorzPin A0
// #define SelPin  12
 
// For ESP32
#define VertPin 12
#define HorzPin 13
#define SelPin  14
 
// GLOBAL VARIABLES
// Define the display size
const byte Rows = 4;
const byte Cols = 20;
 
// Since range of analog values read by Arduino Nano is between 0-1024 and analog values read by ESP32 is 0-4096. 
// For Arduino Nano
// const int NorthThreshold = 750;
// const int SouthThreshold = 250;
// const int WestThreshold =  750;
// const int EastThreshold = 250;
 
// For ESP32 
const int NorthThreshold = 3200;
const int SouthThreshold = 1200;
const int WestThreshold =  3200;
const int EastThreshold = 1200;
 
// used for display string on lcd
 
/* INITIALIZE OBJECTS */
LiquidCrystal_I2C lcd(0x27, Cols, Rows);
 
/* LOCAL FUNCTIONS */
 
// Read sensor value
void readJoystickValue()
{
  bool center = 1; // Default value set to 1 to assume the joystick is in center 
  joystickPosition.remove(0); // Empty the string
  int vert = analogRead(VertPin); // Read the vertical pin value
  int horz = analogRead(HorzPin); // Read the horizontal pin value
  bool selPressed = digitalRead(SelPin) ; // Read the sel pin value
 
  // Serial print the values
  Serial.println(vert);
  Serial.println(horz);
  Serial.println(selPressed);
 
  // Position identification logic (Can be altered)
  // Three checks -> vertical line, horizontal line, and whether the button is pressed or not
  if (selPressed == 0){
    joystickPosition +=  "P"; // Pressed
  }
  else if (selPressed == 1 ){
    joystickPosition += "NP"; // Not pressed
  }
  
  if (vert > NorthThreshold){
    joystickPosition += " North"; // Pushed towards north
    center = 0;
  }
  else if (vert < SouthThreshold){
    joystickPosition += " South"; // Pushed towards south
    center = 0;
  }
 
  if (horz > WestThreshold){
    joystickPosition += " West"; // Pushed towards west
    center = 0;
  }
  else if (horz < EastThreshold){
    joystickPosition += " East"; // Pushed towards east
    center = 0;
  }
 
  if (center == 1 ){
    joystickPosition += " Center"; // Is in center
  }
}
 
/*
  Function to print to LCD on a single row.
  Takes the row number and the text to display on that row (max 20 chars, rest will be truncated).
  The entire display is cleared if the clearAll flag is true, else only the row is cleared (the default).
 */
void printToLCDByRow(int row, String text, bool clearAll = false)
{
  const char* twentySpaces = "                    ";
 
  if(clearAll){ 
    lcd.clear(); // Clears the entire display
  } 
 
  lcd.setCursor(0, row-1);
  lcd.print(twentySpaces); // Clears the row
  lcd.setCursor(0, row-1); // Cursor has to be set again after printing spaces
  lcd.print(text);
}
 
/*
 Function to print to LCD across rows with each row having 20 chars.
 Messages can be a maximum of 20x4 chars, rest will be truncated.
 The entire display is cleared before printing the text.
 */
void printToLCD(String text)
{
  lcd.clear(); // Clears the entire display
 
  byte charsRemaining = text.length();
  byte charFrom = 0;
  byte charTo = charsRemaining < Cols ? text.length() : charFrom + Cols;
  byte row = 1;
 
  while(charsRemaining > 0){
    String line = text.substring(charFrom, charTo);
    printToLCDByRow(row, line);
 
    charsRemaining = text.length() - charTo;
    charFrom = charTo;
    charTo = charsRemaining < Cols ? text.length() : charFrom + Cols;
    row++;
  }
 
  Serial.println("Data string has been displayed on LCD");
}
 
void lcdSetup() // Function to LCD setup
{
  // Initializing wire
  Wire.begin();
  // Initialize the LCD.
  lcd.init();
  // Turn on the backlight and print a message.
  lcd.backlight();
  // Use the function to display text on each line individually.
  printToLCDByRow(1, "I2C LCD Ready!", true);
  printToLCDByRow(2, "Enter some text.", false);
  printToLCDByRow(3, "Max 80 characters.", false);
  printToLCDByRow(4, "For a 20x4 LCD.", false);
}
 
void joystickSetup()
{
  // Joystick pins
  pinMode(VertPin, INPUT);
  pinMode(HorzPin, INPUT);
  // for ESP32
  pinMode(SelPin, INPUT_PULLUP);
  // for Arduino Nano
  pinMode(SelPin, INPUT);
}
 
/* SETUP CODE: runs once when the board starts up or resets */ 
void setup() {
  // Start the serial communication with baud rate suitable for your components.
  Serial.begin(9600);
  lcdSetup();
  joystickSetup();
  Serial.println("The board is ready!");
  printToLCDByRow(1, "Joystick Position:", true);
}
 
/* MAIN LOOP: runs repeatedly at a very high frequency (1000s of times a second) */
void loop() {
  delay(1000);
  readJoystickValue();
  printToLCDByRow(2, joystickPosition, false);
}