Cirkit Designer Logo
Cirkit Designer
Your all-in-one circuit design IDE
Home / 
Project Documentation

Arduino Nano Controlled Joystick and Rotary Encoder Interface with OLED Display and Multi-Color LED Feedback

Image of Arduino Nano Controlled Joystick and Rotary Encoder Interface with OLED Display and Multi-Color LED Feedback

Circuit Documentation

Summary

This circuit is designed to interface an Arduino Nano with various peripherals including a joystick module, a rotary encoder, an OLED display, and multiple LEDs with corresponding resistors. The circuit allows for user interaction through the joystick and rotary encoder, with visual feedback provided by the LEDs and the OLED display. The Arduino Nano serves as the central processing unit, running embedded code to manage input devices and control outputs based on user actions.

Component List

Arduino Nano

  • Microcontroller board based on the ATmega328P
  • It has a variety of digital and analog I/O pins.

I/O Expansion Shield For Arduino Nano

  • An expansion board that facilitates easy connection of peripherals to the Arduino Nano.

Joystick Module

  • An input device with X and Y-axis control and a pushbutton switch (SW).

0.96" OLED

  • A small display screen that uses the I2C protocol for communication.

LEDs (Red, Green, Yellow, Blue)

  • Light Emitting Diodes used for visual indication.

Resistors

  • Four resistors with two different values (220 Ohms and 200 Ohms) used to limit current through the LEDs.

Rotary Encoder

  • An input device that provides rotational position feedback and includes a pushbutton switch (SW).

Wiring Details

Arduino Nano

  • Utilizes various digital and analog pins to interface with the I/O Expansion Shield and indirectly with all other components.

I/O Expansion Shield For Arduino Nano

  • AREF, GND, and power pins are used for reference and power distribution.
  • Digital pins D0-D13 are used to interface with the joystick, rotary encoder, and LEDs.
  • Analog pins A0-A7 are used for the joystick X and Y-axis control.
  • I2C pins (SCL, SDA) are used to communicate with the OLED display.

Joystick Module

  • Connected to the I/O Expansion Shield's analog pins for X and Y-axis control and a digital pin for the pushbutton switch.
  • Powered by the I/O Expansion Shield.

0.96" OLED

  • Communicates with the I/O Expansion Shield via I2C protocol using SCL and SDA lines.
  • Powered by the I/O Expansion Shield.

LEDs (Red, Green, Yellow, Blue)

  • Each LED is connected to a digital pin on the I/O Expansion Shield through a corresponding resistor.
  • The cathodes of all LEDs are connected to a common ground.

Resistors

  • Each resistor is connected in series with an LED to limit the current through the LED.

Rotary Encoder

  • Connected to the I/O Expansion Shield's digital pins for rotation detection and the pushbutton switch.
  • Powered by the I/O Expansion Shield.

Documented Code

#include <U8g2lib.h>

// Rotary Encoder Pins
#define ENCODER_CLK 6
#define ENCODER_DT 7
#define ENCODER_SW 8

// Joystick Pins
#define JOYSTICK_VRX A0
#define JOYSTICK_VRY A1
#define JOYSTICK_SW 4

// LED Pins
#define RED_LED_PIN 5
#define YELLOW_LED_PIN 11
#define BLUE_LED_PIN 12
#define GREEN_LED_PIN 10

// OLED display settings
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

// Variables for rotary encoder
int lastClk = HIGH;
int lastDt = HIGH;
int currentBrightness = 128; // Initial brightness (0-255)
bool isBlinking = false;
bool isLEDOn = true; // Variable to track LED on/off state
unsigned long lastBlinkTime = 0;
const unsigned long blinkInterval = 500; // 500ms interval for blinking

// Array of LED pins
const int ledPins[] = {RED_LED_PIN, YELLOW_LED_PIN, BLUE_LED_PIN, GREEN_LED_PIN};
const char* colorNames[] = {"Red", "Yellow", "Blue", "Green"};

// Dead zone threshold for joystick
const int deadZone = 100;

// Constants for debounce delay and dead zone
const int debounceDelay = 50;
const int joystickDelay = 200;
const int blinkToggleDelay = 500;
const int joystickCenter = 512;

// Variable to keep track of the current LED color
int currentColor = 0; // Initial color (0: Red, 1: Yellow, 2: Blue, 3: Green)

void setup() {
  // Initialize serial communication
  Serial.begin(9600);

  // Initialize OLED display
  u8g2.begin();

  // Initialize rotary encoder pins
  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);
  pinMode(ENCODER_SW, INPUT_PULLUP);

  // Initialize joystick pins
  pinMode(JOYSTICK_SW, INPUT_PULLUP);

  // Initialize LED pins
  for (int i = 0; i < 4; i++) {
    pinMode(ledPins[i], OUTPUT);
    analogWrite(ledPins[i], 0);
  }

  // Display initial brightness
  updateDisplay();
}

void loop() {
  // Read the rotary encoder
  int clkState = digitalRead(ENCODER_CLK);
  int dtState = digitalRead(ENCODER_DT);

  if (clkState == LOW && lastClk == HIGH) {
    if (dtState == HIGH) {
      currentBrightness = min(currentBrightness + 10, 255); // Increase brightness
    } else {
      currentBrightness = max(currentBrightness - 10, 0); // Decrease brightness
    }
    Serial.print("Brightness: ");
    Serial.println(currentBrightness);
    updateDisplay();
  }
  lastClk = clkState;

  // Check if the rotary encoder button is pressed
  if (isButtonPressed(ENCODER_SW)) {
    isLEDOn = !isLEDOn;
    Serial.print("LED: ");
    Serial.println(isLEDOn ? "On" : "Off");
    updateDisplay();
    delay(blinkToggleDelay); // Prevent multiple toggles
  }

  // Read the joystick
  int vrxValue = analogRead(JOYSTICK_VRX);
  int vryValue = analogRead(JOYSTICK_VRY);

  // Map joystick X-axis to change color with dead zone
  if (vrxValue < (joystickCenter - deadZone)) {
    currentColor = (currentColor - 1 + 4) % 4;
    Serial.print("Color: ");
    Serial.println(colorNames[currentColor]);
    updateDisplay();
    delay(joystickDelay); // Delay to prevent rapid changes
  } else if (vrxValue > (joystickCenter + deadZone)) {
    currentColor = (currentColor + 1) % 4;
    Serial.print("Color: ");
    Serial.println(colorNames[currentColor]);
    updateDisplay();
    delay(joystickDelay); // Delay to prevent rapid changes
  }

  // Map joystick Y-axis to toggle blinking mode with dead zone
  if (vryValue < (joystickCenter - deadZone) || vryValue > (joystickCenter + deadZone)) {
    isBlinking = !isBlinking;
    Serial.print("Mode: ");
    Serial.println(isBlinking ? "Blinking" : "Solid");
    updateDisplay();
    delay(blinkToggleDelay); // Delay to prevent rapid toggles
  }

  // Check if the joystick button is pressed
  if (isButtonPressed(JOYSTICK_SW)) {
    isBlinking = !isBlinking;
    Serial.println("Joystick button pressed. Toggling blinking mode.");
    Serial.print("isBlinking: ");
    Serial.println(isBlinking);
    updateDisplay();
    delay(blinkToggleDelay); // Prevent multiple toggles
  }

  // Update LED state
  updateLEDs();
}

void updateDisplay() {
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_5x8_tr); // Use a smaller font to fit more text

  // Column 1
  u8g2.setCursor(0, 8);
  u8g2.print("Brightness:");
  u8g2.setCursor(0, 18);
  u8g2.print(currentBrightness);

  u8g2.setCursor(0, 28);
  u8g2.print("Mode:");
  u8g2.setCursor(0, 38);
  u8g2.print(isBlinking ? "Blinking" : "Solid");

  // Column 2
  u8g2.setCursor(64, 8);
  u8g2.print("Color:");
  u8g2.setCursor(64, 18);
  u8g2.print(colorNames[currentColor]);

  u8g2.setCursor(64, 28);
  u8g2.print("LED:");
  u8g2.setCursor(64, 38);
  u8g2.print(isLEDOn ? "On" : "Off");

  u8g2.sendBuffer();
}

void updateLEDs() {
  unsigned long currentTime = millis();
  bool ledState = true;

  if (isBlinking) {
    if (currentTime - lastBlinkTime >= blinkInterval) {
      lastBlinkTime = currentTime;
      ledState = !digitalRead(ledPins[currentColor]);
    } else {
      ledState = digitalRead(led