Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Arduino & Microcontrollers

Arduino OLED Display SSD1306: Menu and Graphics Tutorial

Arduino OLED Display SSD1306: Menu and Graphics Tutorial

March 11, 2026 /Posted byJayesh Jain / 1

The Arduino OLED SSD1306 menu system is one of the most satisfying things you can build for a handheld device or instrument. The SSD1306 is a 0.96-inch monochrome OLED display with 128×64 pixels that communicates over I2C or SPI. It draws very little power, offers excellent contrast even in bright light, and is supported by mature libraries that make graphics and navigation menus surprisingly easy to implement. In this tutorial, you will learn to wire the display, install the right library, draw graphics, render text, and build a fully functional scrollable menu system with button navigation.

Table of Contents

  • What is the SSD1306 OLED Display?
  • Wiring the SSD1306 to Arduino
  • Library Options: Adafruit vs U8g2
  • Basic Text and Graphics
  • Building a Scrollable Menu System
  • Bitmaps, Icons and Progress Bars
  • Power Saving and Performance Tips
  • Frequently Asked Questions

What is the SSD1306 OLED Display?

The SSD1306 is a single-chip CMOS OLED/PLED driver controller manufactured by Solomon Systech. It drives 128×64 or 128×32 dot matrix OLED panels and handles all the refresh timing, charge pump generation, and pixel addressing internally, so your Arduino only needs to send display commands and pixel data over I2C or SPI.

Key characteristics of the SSD1306:

  • 128×64 pixels (or 128×32 on smaller variants)
  • Monochrome — each pixel is either on or off (no greyscale)
  • I2C address: 0x3C (default) or 0x3D (when ADDR pin is pulled high)
  • SPI variant: up to 10 MHz clock, faster refresh than I2C
  • Supply voltage: 3.3V–5V (most breakout boards include a regulator)
  • Power consumption: ~20 mA at full brightness, ~0.08 mA in sleep mode
  • Operating temperature: –40°C to +85°C

OLED pixels emit their own light, so there is no backlight. Black pixels are truly off (zero power), and only lit pixels consume power. This gives OLED displays their characteristic high contrast ratio and makes them ideal for dashboards, instrument panels, wearable devices, and battery-powered gadgets.

Recommended: Arduino Uno R3 Beginners Kit — Complete starter kit with Arduino Uno, breadboard, jumper wires, and components — everything you need to follow this tutorial.

Wiring the SSD1306 to Arduino

The most common SSD1306 breakout modules use I2C (4-pin) or SPI (7-pin). Here is how to wire both configurations to an Arduino Uno or Nano.

I2C Wiring (4-pin module)

I2C requires only 2 signal wires plus power. This is the most common module type sold in India:

SSD1306 VCC  →  Arduino 3.3V (or 5V if module has regulator)
SSD1306 GND  →  Arduino GND
SSD1306 SCL  →  Arduino A5 (Uno/Nano) or Pin 21 (Mega)
SSD1306 SDA  →  Arduino A4 (Uno/Nano) or Pin 20 (Mega)

Use 4.7 kΩ pull-up resistors on both SDA and SCL lines if your module does not already include them (most breakout boards do include them).

SPI Wiring (7-pin module)

SPI is faster (better for frequent full-screen updates) but uses more pins:

SSD1306 VCC   →  Arduino 3.3V
SSD1306 GND   →  Arduino GND
SSD1306 D0    →  Arduino Pin 13 (SCK)
SSD1306 D1    →  Arduino Pin 11 (MOSI)
SSD1306 RES   →  Arduino Pin 8 (configurable)
SSD1306 DC    →  Arduino Pin 6 (configurable)
SSD1306 CS    →  Arduino Pin 10 (SS)

For menu-based projects with button inputs, I2C is usually the better choice because it frees up SPI pins for other peripherals and the refresh speed is more than adequate for menu navigation.

Library Options: Adafruit vs U8g2

Two main library options dominate Arduino SSD1306 development:

Adafruit SSD1306 + Adafruit GFX: This combination is the most popular starting point. Adafruit GFX provides drawing primitives (lines, circles, rectangles, text rendering) while the SSD1306 library handles hardware communication. Install via Arduino IDE Library Manager: search for “Adafruit SSD1306” and install it along with “Adafruit GFX Library” when prompted.

U8g2: A more powerful and memory-efficient library that supports a huge range of OLED and LCD controllers (including SSD1306). U8g2 supports multiple fonts and rendering modes. It is slightly more complex to initialise but offers better text rendering and lower RAM usage through its page buffer mode.

For this tutorial, we will use the Adafruit library for basic examples and U8g2 for the menu system, as U8g2’s menu-friendly architecture makes complex UI logic much cleaner.

Basic Text and Graphics

Start with the Adafruit library. Install it, then try this minimal example to verify your wiring and display are working correctly.

Hello World

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1  // no reset pin
#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 24);
  display.println(F("Hello!"));
  display.display();
}

void loop() {}

Drawing Shapes

The Adafruit GFX library provides a rich set of drawing functions:

// Draw a rectangle
display.drawRect(10, 10, 50, 30, SSD1306_WHITE);

// Draw a filled circle
display.fillCircle(90, 32, 20, SSD1306_WHITE);

// Draw a line
display.drawLine(0, 0, 127, 63, SSD1306_WHITE);

// Draw a triangle
display.drawTriangle(64, 5, 20, 58, 108, 58, SSD1306_WHITE);

// Always call display() to push buffer to screen
display.display();
Recommended: Arduino Nano Every with Headers — More RAM than the original Nano (6KB SRAM vs 2KB), essential when working with display buffers and menu state arrays.

Building a Scrollable Menu System

A working menu system needs three things: a list of items to display, logic to track which item is selected (cursor position), and input handling (buttons to scroll up/down and select). Let us build a complete 5-item menu with three physical buttons: UP, DOWN, and SELECT.

Hardware Setup for Menu

Button UP     →  Arduino Pin 2  (INPUT_PULLUP, other side to GND)
Button DOWN   →  Arduino Pin 3  (INPUT_PULLUP, other side to GND)
Button SELECT →  Arduino Pin 4  (INPUT_PULLUP, other side to GND)
SSD1306 I2C   →  A4 (SDA), A5 (SCL)

Complete Menu Sketch

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Button pins (active LOW with INPUT_PULLUP)
const int BTN_UP   = 2;
const int BTN_DOWN = 3;
const int BTN_SEL  = 4;

// Menu configuration
const char* menuItems[] = {
  "1. LED Blink",
  "2. Temperature",
  "3. Data Logger",
  "4. WiFi Config",
  "5. System Info"
};
const int NUM_ITEMS = 5;
const int ITEMS_PER_PAGE = 4;  // rows visible at once (8px font, 64px tall)

int currentItem = 0;   // highlighted item index
int scrollOffset = 0;  // first visible item index
bool inMenu = true;

void setup() {
  pinMode(BTN_UP,   INPUT_PULLUP);
  pinMode(BTN_DOWN, INPUT_PULLUP);
  pinMode(BTN_SEL,  INPUT_PULLUP);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  drawMenu();
}

void loop() {
  if (digitalRead(BTN_UP) == LOW) {
    delay(200);  // debounce
    if (currentItem > 0) {
      currentItem--;
      if (currentItem < scrollOffset)
        scrollOffset = currentItem;
      drawMenu();
    }
  }
  if (digitalRead(BTN_DOWN) == LOW) {
    delay(200);
    if (currentItem < NUM_ITEMS - 1) {
      currentItem++;
      if (currentItem >= scrollOffset + ITEMS_PER_PAGE)
        scrollOffset = currentItem - ITEMS_PER_PAGE + 1;
      drawMenu();
    }
  }
  if (digitalRead(BTN_SEL) == LOW) {
    delay(200);
    handleSelection(currentItem);
  }
}

void drawMenu() {
  display.clearDisplay();
  
  // Draw title bar
  display.fillRect(0, 0, 128, 12, SSD1306_WHITE);
  display.setTextColor(SSD1306_BLACK);
  display.setTextSize(1);
  display.setCursor(4, 2);
  display.print(F("  MAIN MENU"));

  // Draw menu items
  display.setTextColor(SSD1306_WHITE);
  for (int i = 0; i < ITEMS_PER_PAGE; i++) {
    int itemIndex = scrollOffset + i;
    if (itemIndex >= NUM_ITEMS) break;
    int yPos = 14 + i * 13;
    if (itemIndex == currentItem) {
      // Highlight selected item
      display.fillRect(0, yPos - 1, 128, 12, SSD1306_WHITE);
      display.setTextColor(SSD1306_BLACK);
      display.setCursor(4, yPos);
      display.print(menuItems[itemIndex]);
      display.setTextColor(SSD1306_WHITE);
    } else {
      display.setCursor(4, yPos);
      display.print(menuItems[itemIndex]);
    }
  }

  // Draw scrollbar indicator
  if (NUM_ITEMS > ITEMS_PER_PAGE) {
    int barHeight = (ITEMS_PER_PAGE * 52) / NUM_ITEMS;
    int barY = 12 + (scrollOffset * 52) / NUM_ITEMS;
    display.drawRect(124, 12, 4, 52, SSD1306_WHITE);
    display.fillRect(124, barY, 4, barHeight, SSD1306_WHITE);
  }

  display.display();
}

void handleSelection(int item) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print(F("Selected:"));
  display.setCursor(0, 12);
  display.print(menuItems[item]);
  display.setCursor(0, 48);
  display.print(F("Press DOWN to return"));
  display.display();
  // Wait for DOWN press to return to menu
  while (digitalRead(BTN_DOWN) == HIGH) delay(50);
  delay(200);
  drawMenu();
}

This menu includes a title bar, highlighted current selection with inverted colours, scrolling support, and a scrollbar indicator. It handles wrapping correctly so items scroll in and out of view smoothly.

Bitmaps, Icons and Progress Bars

Menus with icons look more professional. The Adafruit GFX library supports drawing 1-bit bitmaps using the drawBitmap() function.

Creating a Bitmap Icon

Use an online tool like image2cpp to convert a 16×16 or 8×8 PNG icon to a C byte array. Then use it in your sketch:

// 8x8 WiFi icon example
const uint8_t wifiIcon[] PROGMEM = {
  0b00111100,
  0b01000010,
  0b10011001,
  0b00100100,
  0b01011010,
  0b00000000,
  0b00011000,
  0b00011000
};

// Draw it at position (2, 14)
display.drawBitmap(2, 14, wifiIcon, 8, 8, SSD1306_WHITE);

Progress Bar

A progress bar is easy to implement with fillRect():

void drawProgressBar(int x, int y, int w, int h, int percent) {
  display.drawRect(x, y, w, h, SSD1306_WHITE);
  int fillWidth = (w - 2) * percent / 100;
  display.fillRect(x + 1, y + 1, fillWidth, h - 2, SSD1306_WHITE);
}
Recommended: 1.8 Inch SPI 128×160 TFT LCD Display Module for Arduino — For projects needing colour and larger screen space, this TFT module pairs well with Arduino and supports full graphics.
Recommended: Arduino Mega 2560 R3 Board — When your project outgrows the Uno’s RAM (only 2KB), the Mega’s 8KB SRAM handles large display buffers and complex menu state with ease.

Power Saving and Performance Tips

Use PROGMEM for strings and bitmaps. The ATmega328P has only 2KB of SRAM. Every string literal you store eats into this. Use the F() macro to keep strings in flash: display.print(F("My string"));

Limit full-screen updates. A full 128×64 I2C screen refresh takes approximately 14ms at 400 kHz (fast I2C). If you are only updating part of the screen, use display.drawFastHLine(), drawFastVLine(), or region-specific drawing followed by display.display() to minimise data transfer.

Enable fast I2C mode. The Wire library defaults to 100 kHz. For the SSD1306, 400 kHz (fast mode) is supported and cuts refresh time by 75%:

Wire.begin();
Wire.setClock(400000);  // 400 kHz I2C

Sleep the display when inactive. The SSD1306 supports a sleep command that reduces power to ~8 µA. In Adafruit library: display.ssd1306_command(SSD1306_DISPLAYOFF); to sleep, and display.ssd1306_command(SSD1306_DISPLAYON); to wake.

Adjust contrast. You can reduce OLED brightness to extend panel lifespan: display.ssd1306_command(SSD1306_SETCONTRAST); display.ssd1306_command(0x50); — values from 0x00 (dim) to 0xFF (full brightness).

Frequently Asked Questions

Why does my SSD1306 display nothing after uploading?

First verify the I2C address. Most modules use 0x3C, but some use 0x3D. Run an I2C scanner sketch (available in Arduino IDE examples) to find the actual address of your module. Also check that your SDA and SCL connections are not swapped.

Can I use two SSD1306 displays on the same Arduino?

Yes, if one module is configured to address 0x3C and the other to 0x3D (by pulling the ADDR pin high on one module). Both can share the same SDA/SCL lines. In your sketch, create two Adafruit_SSD1306 instances with different addresses.

How do I add button debouncing to the menu system?

The simple delay(200) in the example works for most use cases. For production code, use a proper debounce library like Bounce2, which tracks button state transitions without blocking your program loop.

What is the maximum refresh rate achievable with SSD1306 over I2C?

At 400 kHz I2C (fast mode) with a 128×64 display, a full-screen update takes approximately 3.5ms, giving a theoretical maximum of ~285 FPS. In practice, with Arduino library overhead, you will get 40–70 FPS, which is perfectly smooth for menus and simple animations.

Can I show grayscale images on the SSD1306?

No. The SSD1306 is strictly monochrome — each pixel is either fully on or fully off. You can simulate greyscale using dithering techniques (Floyd-Steinberg dithering patterns), but true greyscale requires a different controller like the SH1106 or a colour display.

With these techniques, you can build professional-quality menu interfaces and graphics on the SSD1306 that rival commercial embedded products. The combination of low power, high contrast, and comprehensive library support makes the SSD1306 one of the best display choices for Arduino projects of all kinds.

Shop Arduino Boards and Shields at Zbotic →

Tags: adafruit ssd1306, arduino display, arduino menu, arduino oled, oled display, ssd1306, u8g2
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Arduino Soil Moisture Sensor C...
blog arduino soil moisture sensor calibration get accurate values 594714
blog arduino rotary encoder menu navigation and position sensing 594723
Arduino Rotary Encoder: Menu N...

Related posts

Svg%3E
Read more

Arduino Batch Programming: Flash Multiple Boards Quickly

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Based Radar System with Ultrasonic Sensor

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Automatic Plant Monitor: Sunlight, Moisture, Temperature

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Lie Detector: GSR Sensor Polygraph Project

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Metal Detector: Build a Treasure Finder

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading

One comment

  • Avatar of vikranth

    vikranth

    March 20, 2026 - 10:58 am

    Thankyou so much for this tutorial and code sir. it worked perfect

    Reply

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now