HomeSTM32 TutorialsArduino TutorialsArduino Displays & InterfacesInterface SH1106 I2C OLED Display

Interface SH1106 I2C 1.3” OLED Display with Arduino – Full Guide with Bitmaps and Animations

The SH1106 OLED display is a popular 1.3-inch graphical screen often used in small embedded projects. It looks very similar to the SSD1306 OLED, but it runs on a slightly different driver chip. In this tutorial, we’ll learn how to interface the SH1106 OLED display with Arduino using the I2C communication protocol.

We’ll start with the basics, where we will understand the pinout and connections, and then move on to displaying text, shapes, and images. Later in the post, we’ll also explore how to create custom bitmaps and even add simple animations to make your project more interactive.

If you are new to OLED displays, I recommend checking out my detailed guide on the Arduino SSD1306 OLED Display Tutorial before continuing. It explains the fundamentals that will help you better understand how OLEDs work and how to use them effectively in your Arduino projects.

If you’re looking for other Arduino display tutorials, check out the links below:

Interface SH1106 I2C 1.3” OLED Display with Arduino

SH1106 OLED Display: Specs, Features & Arduino Compatibility

The SH1106 OLED display is a compact 1.3-inch screen that uses I2C communication to connect with microcontrollers like Arduino, ESP32, and STM32. It’s a monochrome display, meaning it can show graphics and text in a single color, usually white, blue, or yellow, depending on the module version.

SH1106 I2C Display

This display has a resolution of 128×64 pixels, offering a crisp and clear output that’s perfect for showing sensor data, menus, or small graphical animations. Its low power consumption and high contrast make it ideal for battery-powered projects and IoT devices.

Difference between SH1106 and SSD1306 Displays

The SH1106 and SSD1306 displays look almost identical from the outside, but they differ internally in their driver IC and memory organization.

  • The SSD1306 controller has a built-in 128×64 memory that directly matches the display’s pixel resolution.
  • The SH1106, however, has 132×64 internal memory, meaning there are 4 extra columns of pixels that aren’t visible on the display.

Because of this small difference, SSD1306 libraries may not work perfectly with SH1106 modules. You might notice text shifting or graphics misalignment if you use the wrong library. That’s why it’s important to use a library specifically designed for the SH1106 controller.


Why Use SH1106 with Arduino

The SH1106 OLED offers a slightly larger display area (1.3″) compared to the 0.96″ SSD1306, making it easier to read data and display graphics. It’s also widely available, inexpensive, and easy to interface using just two wires (SDA and SCL) via the I2C protocol.

Another reason to choose the SH1106 is its excellent contrast and sharpness, even under different lighting conditions. It doesn’t require a backlight like LCDs, which saves power and simplifies wiring.

With Arduino’s wide library support and straightforward coding environment, you can easily display text, sensor readings, custom logos, and animations on the SH1106 screen within minutes.


Required Hardware and Connections

To get started with this project, you’ll need a few basic components:

  • Arduino Board – You can use Uno, Nano, or Mega.
  • 1.3″ SH1106 OLED Display (I2C version)
  • Jumper Wires – For connecting the display to Arduino.
  • Breadboard – Optional, for neat prototyping.

The I2C version of SH1106 has four pins:

  1. GND – Connect to Arduino GND
  2. VCC – Connect to 5V (or 3.3V for some modules)
  3. SCL – Connect to Arduino A5 (on Uno/Nano)
  4. SDA – Connect to Arduino A4 (on Uno/Nano)

Once these connections are made, your display will be ready for programming. In the next section, we’ll set up the required libraries and write code to initialize the display.

Arduino SH1106 I2C Wiring: Pinout & Circuit Diagram

Before we start coding, let’s take a look at how to connect the SH1106 OLED display with the Arduino board. The SH1106 uses the I2C communication protocol, which makes wiring very simple, only four pins are needed: VCC, GND, SDA, and SCL.

This section will explain the pinout of the SH1106 display, how to wire it correctly with Arduino, and how to verify that the connections are working properly.

SH1106 Pinout and I2C Connection

The SH1106 I2C OLED module usually comes with four pins. The image below shows the pinout of SH1106 I2C Oled display.

SH1106 1.3" I2C Oled display pinout

Here’s what each pin on the display does:

PinDescriptionConnection to Arduino
GNDGroundConnect to Arduino GND
VCCPower Supply (3.3V or 5V)Connect to 5V on Arduino Uno/Nano
SCLSerial Clock LineConnect to A5 on Arduino Uno/Nano (SCL pin)
SDASerial Data LineConnect to A4 on Arduino Uno/Nano (SDA pin)
Note: Some SH1106 modules work only at 3.3V, while others can handle 5V. Check your display’s datasheet or product label before connecting it to avoid damage.

The I2C communication allows multiple devices to share the same two data lines (SDA and SCL). Each device is identified by a unique I2C address — for SH1106, this is usually 0x3C or 0x3D, depending on the module version.


SH1106 Arduino Wiring

Let’s take the Arduino Uno as an example. You can connect the SH1106 display as follows:

Image showing the connection between 1.3" SH1106 oled display and Arduino Uno.

Here’s how to connect it:

OLED PinConnects ToDescription
VCC3.3VPower supply for the display
GNDGNDCommon ground
SDAA4 (on Arduino Uno/Nano)I2C Data line
SCLA5 (on Arduino Uno/Nano)I2C Clock line

If you are using a different Arduino board, here are the equivalent I2C pins:

BoardSDA PinSCL Pin
Arduino Uno/NanoA4A5
Arduino Mega2021
Arduino Leonardo23
Arduino Due2021
ESP32GPIO 21GPIO 22

Make sure the connections are firm and not reversed. Incorrect wiring may cause the display not to power up or communicate with Arduino.

Install Adafruit SH110X Library in Arduino IDE

To control the SH1106 OLED display using Arduino, we need to install a suitable library that supports this controller. The SH1106 is very similar to the SSD1306, so it also works with the Adafruit GFX graphics library, but it requires its own display driver library for proper pixel mapping.

In this section, we’ll install the required libraries, understand how they work together, and test a simple example to initialize the display.

Using the Adafruit GFX and SH1106 Library

To make the SH1106 OLED work properly, we’ll use two main libraries:

  1. Adafruit GFX Library – This library provides basic graphics functions like drawing lines, circles, and displaying text. It acts as a universal graphics engine for many displays.
  2. Adafruit SH110X Library – This library specifically supports the SH1106 and SH1107 OLED driver chips. It handles the communication between Arduino and the SH1106 controller through I2C or SPI.

Together, these libraries make it easy to draw shapes, text, and even custom images on the OLED screen with very few lines of code.

If you have previously worked with the SSD1306 display, this setup will look very familiar. The only difference is that we are using the Adafruit_SH110X library instead of Adafruit_SSD1306.


How to Install Libraries in Arduino IDE

You can install both libraries directly from the Arduino Library Manager. Follow these steps:

  1. Open Arduino IDE.
  2. Go to Sketch → Include Library → Manage Libraries…
  3. In the search box, type “Adafruit GFX” and install the Adafruit GFX Library.
  4. Next, search for “Adafruit SH110X” and install the Adafruit SH110X Library.
Install Adafruit GFX library and Adafruit SH110X library for Arduino.

Once installed, Arduino will automatically link these libraries in your sketches. You’ll now have access to functions like display.display(), display.clearDisplay(), and text/graphics drawing routines.

If you prefer manual installation, you can also download both libraries as ZIP files from the Adafruit GitHub repositories and add them using Sketch → Include Library → Add .ZIP Library…


Basic Example Code to Initialize Display

After installing the libraries, let’s test if the SH1106 display initializes correctly. Open a new Arduino sketch and paste the following code:

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin not used with I2C

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

void setup() {
  Serial.begin(9600);
  Serial.println("SH1106 OLED Test");

  if(!display.begin(0x3C, true)) { // Address 0x3C for most modules
    Serial.println("SH1106 allocation failed");
    for(;;);
  }

  display.display(); // Push buffer to the screen
}

void loop() {
}

Explanation of the code:

  • Includes required libraries for I²C and OLED display (Wire, Adafruit_GFX, Adafruit_SH110X).
  • Defines screen width, height, and OLED reset pin (not used with I²C).
  • Creates a display object for the SH1106 OLED module.
  • In setup():
    • Initializes serial communication.
    • Initializes the OLED display at I²C address 0x3C.
    • Displays the initial buffer (usually the Adafruit logo).
  • The loop() function is empty (no continuous updates).

After uploading the code, the Adafruit logo will appear on the screen. This is shown in the image below.

Adafruit logo being displayed on the SH1106 I2C display, connected to the Arduino.

Display Text, Shapes & Graphics on SH1106 OLED

In this section, we’ll go step by step — from showing simple text to drawing geometric shapes like lines, rectangles, and circles. We’ll also learn how to adjust display contrast and enable text scrolling for better visual effects.

Displaying Simple Text

Displaying text on the SH1106 OLED is straightforward. The GFX library lets you choose text size, color, and cursor position. Here’s a simple example:

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin not used with I2C

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

void setup() {
  Serial.begin(9600);
  Serial.println("SH1106 OLED Test");

  if(!display.begin(0x3C, true)) { // Address 0x3C for most modules
    Serial.println("SH1106 allocation failed");
    for(;;);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(0, 10);
  display.println("Hello from ControllersTech!");
  display.display();
}

void loop() {
}

Explanation of the Code

  • The code starts by including the required libraries for I2C and SH1106.
  • We define the display resolution as 128×64 pixels, matching the module’s size.
  • The display.begin(0x3C, true) function initializes the OLED at address 0x3C.
  • Inside setup(), we clear the display, set the text size and color, and print a sample message.
  • Finally, display.display() updates the screen with the written content.

The image below shows the text “Hello from ControllersTech!” displaying on the OLED screen.

Image shows the Text being displayed on the SH1106 oled screen, connected to the Arduino.

In the next section, we’ll explore how to display text, draw shapes, and add basic graphics to the screen.

You can print multiple lines by moving the cursor position and calling println() again.


Drawing Lines, Rectangles, and Circles

The Adafruit GFX library also provides easy functions to draw basic shapes — useful for creating UI elements, progress bars, or custom icons.

Here’s a sample code showing different shapes:

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

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

void setup() {
  display.begin(0x3C, true);
  display.clearDisplay();

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

  // Draw rectangle outline
  display.drawRect(10, 10, 50, 30, SH110X_WHITE);

  // Draw filled rectangle
  display.fillRect(70, 10, 40, 20, SH110X_WHITE);

  // Draw circle outline
  display.drawCircle(30, 50, 10, SH110X_WHITE);

  // Draw filled circle
  display.fillCircle(90, 50, 10, SH110X_WHITE);

  display.display();
}

void loop() {
}

Explanation of the code:

  • drawLine(x0, y0, x1, y1, color) draws a straight line between two points.
  • drawRect(x, y, w, h, color) and fillRect() create empty or filled rectangles.
  • drawCircle(x, y, r, color) and fillCircle() create circular shapes.

These commands make it easy to design custom layouts, highlight areas, or create animated graphics. The image below shows the output on the screen for the above code.

image showing different shapes being drawn on the SH1106 oled display.

Show Integer & Float Values on Arduino SH1106 OLED

Printing numbers on the SH1106 OLED display is just as easy as printing text. Whether you want to show sensor readings, counter values, or real-time measurements, the Adafruit GFX library provides simple methods to print both integers and floating-point numbers. You can even combine them with text for clear and informative displays.

Displaying Integer Values

To display integer values, you can directly use the display.print() or display.println() functions — just like you would use with the Serial Monitor.

Here’s a simple example that shows a counter increasing every second:

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

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

int counter = 0;

void setup() {
  display.begin(0x3C, true);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SH110X_WHITE);
}

void loop() {
  display.clearDisplay();
  display.setCursor(10, 20);
  display.print("Count: ");
  display.print(counter);
  display.display();
  counter++;
  delay(1000);
}

In this example:

  • The variable counter increases by 1 every second.
  • display.print(counter); shows the current count value.
  • Each time the display is updated, it clears the previous value to prevent overlapping text.

Tip: If you forget to use display.clearDisplay(), the old numbers might overlap with the new ones, making the display unreadable.

The gif below shows the output of the code.

Numbers being printed on the 1.3"  SH1106 Oled display with Arduino.

Printing Floating Point Numbers with Precision

The Adafruit GFX library also allows you to display floating-point numbers directly using display.print(). You can control the number of decimal places by passing a second parameter to the print() function.

Example:

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

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

float temperature = 23.2678;

void setup() {
  display.begin(0x3C, true);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(10, 20);
  display.print("Temp: ");
  display.print(temperature, 2);  // prints 23.27
  display.display();
}

void loop() {
}

In the line display.print(temperature, 2);, the number 2 specifies that only two digits after the decimal point should be shown.
You can adjust this value depending on the precision you need — for example, use (temperature, 1) for one decimal place or (temperature, 3) for three.

This feature is very helpful for displaying sensor values such as temperature, voltage, or humidity, where accurate decimal representation is needed.

Note: Avoid using too many decimal places because the OLED has limited space and smaller fonts may become hard to read.

The image below shows the float number displaying on the Oled.

Float Numbers being printed on the 1.3" SH1106 Oled display with Arduino.

SH1106 OLED Bitmap: Convert & Display Custom Images

The SH1106 OLED display is not limited to just text and shapes — you can also display custom images, icons, and logos by converting them into bitmap format. This feature is perfect for adding branding, startup logos, or small graphical elements to your Arduino projects.

In this section, we’ll learn how to convert an image into a compatible bitmap format, generate the C array code, and display it on the SH1106 OLED using Arduino.

Understanding Bitmaps on OLED Displays

A bitmap is a collection of binary data that represents each pixel on the screen.

  • Each bit in the array corresponds to one pixel.
  • A value of 1 means the pixel is turned ON (white), while 0 means it’s OFF (black).
  • Since the SH1106 display is monochrome, there are no shades or colors — only black and white pixels.

You can use bitmaps to display small icons (like a Wi-Fi or battery symbol) or full-screen logos for branding your project.

Example of a simple 8×8 pixel bitmap:

const unsigned char myLogo [] PROGMEM = {
  0x00, 0x7E, 0x81, 0xA5, 0x81, 0x7E, 0x00,
  // more hex values...
};

Here, each byte represents 8 pixels, and the pattern defines the shape to be displayed.


Converting Images to Bitmaps

To use your own image, you need to convert it into a C byte array. You can easily do this using the Image2CPP online tool.

The image below shows how to create bitmap using an existing image.

create bitmap using an existing image using Image2CPP tool.

Follow these steps:

  1. Create a simple black-and-white image (for example, your logo).
  2. Upload it in Image2CPP.
  3. Configure the Image Settings. You can check the preview to see how the final image will look.
  4. Adjust the brightness/alpha threshold to generate clear image.
  5. Set output as Arduino Code.
  6. Choose Monochrome and Horizontal byte orientation.
  7. Click Generate Code and copy the byte array.

After copying the byte array, paste it in a new header file. It will keep the code clean as our image data will be in a separate file. In the image below, I have created a separate file named logo.h.

create a separate header file to store the bitmap byte array.

Now copy the file to the Arduino project folder, so that we can use it in the code.

copy the bitmap header file to the arduino project folder.

Displaying a Bitmap Using Adafruit Library

To show your bitmap on the OLED, include the bitmap header file in the main file. Then use the drawBitmap() function provided by the Adafruit GFX library.

Here’s a simple example:

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

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

// Example bitmap data (replace with your own)
const unsigned char myLogo [] PROGMEM = {
  0x00, 0x7E, 0x81, 0xA5, 0x81, 0x7E, 0x00,
};

void setup() {
  display.begin(0x3C, true);
  display.clearDisplay();

  // Draw bitmap: (x, y, bitmapArray, width, height, color)
  display.drawBitmap(32, 0, myLogo, 64, 64, SH110X_WHITE);
  display.display();
}

void loop() {
}

Explanation:

  • #include "logo.h" will include the bitmap header file.
  • drawBitmap(x, y, array, width, height, color) is used to place the image on the screen.
  • You can adjust (x, y) coordinates to move the image position.
  • Finally, display.display() updates the screen to show the image.

If your image appears inverted (white background, black logo), simply invert the color setting in the online tool or change the color constant to SH110X_BLACK.

The image below shows the output of the above code. You can see the ControllersTech Logo is being displayed on the oled.

Controllerstech logo (bitmap) is being displayed on the SH1106 oled display.

With this method, you can show your brand logo, custom icons, or even simple graphics at startup or during operation.


Combining Text and Bitmaps

You can mix text and graphics to make your OLED display more interactive. For example, show a Wi-Fi icon beside connection status text, or a battery symbol next to voltage readings.

Example WiFi icon and Connected:

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

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

// 16x16 WiFi icon bitmap (simple example)
static const unsigned char PROGMEM wifi_icon[] = {
  0b00000000, 0b00000000,
  0b00000111, 0b11100000,
  0b00011111, 0b11111000,
  0b00111100, 0b00111100,
  0b01110000, 0b00001110,
  0b01100011, 0b11000110,
  0b00001111, 0b11110000,
  0b00011100, 0b00111000,
  0b00110000, 0b00001100,
  0b00000000, 0b00000000,
  0b00000011, 0b11000000,
  0b00000111, 0b11100000,
  0b00000110, 0b01100000,
  0b00000000, 0b00000000,
  0b00000001, 0b10000000,
  0b00000000, 0b00000000
};

void setup() {
  display.begin(0x3C, true);
  display.clearDisplay();

  // Draw WiFi icon at (10, 20)
  display.drawBitmap(10, 20, wifi_icon, 16, 16, SH110X_WHITE);

  // Draw text next to icon
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(30, 26);
  display.print("Connected");

  // Update display
  display.display();
}

void loop() {
}

Here is how the code works:

  • The bitmap array (wifi_icon) defines a simple 16×16 WiFi symbol.
  • display.drawBitmap(10, 20, wifi_icon, 16, 16, SH110X_WHITE);
    → Draws the icon at (x=10, y=20).
  • Then text "Connected" is drawn right next to it using normal text functions.
  • display.display(); pushes everything to the OLED.

The image below shows the output of the code on the Oled.

Image showing the bitmap (WiFi Icon) and text both displaying on the SH1106 Oled.

Next, we’ll go one step further and learn how to create animations on the SH1106 OLED — by displaying multiple bitmaps in sequence for a smooth motion effect.

SH1106 OLED Animations: Pac-Man & Moving Objects

Animations can make your SH1106 OLED display come alive. You can create moving objects, blinking icons, or even scrolling graphics that add a professional touch to your Arduino projects. The concept is simple — by displaying a series of images one after another, you create the illusion of motion, much like a flipbook or video frame sequence.

In this section, we’ll understand how frame-based animation works, write a simple animation example, and finally create a moving logo on the OLED display.

Concept of Frame-Based Animation

The SH1106 OLED display doesn’t support video playback, but you can still show motion using frame-based animation. This method works by displaying different images (frames) quickly in succession.

Each frame is stored as a bitmap array in the Arduino sketch, and the code switches between these frames with short delays in between. When done correctly, this gives the appearance of smooth movement.

Here’s how it works conceptually:

  1. Prepare multiple bitmap frames of your image in slightly different positions.
  2. Display one frame on the OLED.
  3. Wait a short time (e.g., 100 milliseconds).
  4. Clear the screen and display the next frame.
  5. Repeat this process continuously.

Because the SH1106 OLED has a fast refresh rate, even simple frame-based motion looks fluid. You can animate text, icons, or objects moving across the screen.


Writing Code for Simple Animation

Let’s start with a very basic animation example — moving a small box across the display. This will help you understand the timing and update process.

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

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

void setup() {
  display.begin(0x3C, true);
  display.clearDisplay();
}

void loop() {
  for (int x = 0; x < 128; x += 2) { // Move the box across the screen
    display.clearDisplay();
    display.fillRect(x, 25, 20, 20, SH110X_WHITE); // Draw a 20x20 box
    display.display();
    delay(20); // Adjust for animation speed
  }
}

Code Explanation:

  • The loop moves a small square horizontally from left to right by incrementing the X position.
  • fillRect() draws the shape at each new position.
  • clearDisplay() clears the previous frame to prevent overlapping graphics.
  • The delay(20) value controls the animation speed — smaller values create smoother motion.

This simple approach works great for sliding icons, progress bars, or moving text.

The gif below shows the animation on the bitmap.

Gif shows the rectangle animation on the SH1106 Oled display.

Pac-Man Animation on SH1106 OLED

This sketch creates a simple Pac-Man animation on an SH1106 OLED display. Pac-Man moves across the screen, chomping dots one by one and then resetting to repeat the sequence.

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

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

void drawPacman(int x, int y, bool mouthOpen) {
  int r = 12;  // Even bigger radius: 24x24 Pacman
  int cx = x + r;
  int cy = y + r;
  display.fillCircle(cx, cy, r, SH110X_WHITE);
  if (mouthOpen) {
    // Black triangle for open mouth facing right (scaled up further)
    display.fillTriangle(cx, cy, cx + r, cy - 6, cx + r, cy + 6, SH110X_BLACK);
  }
}

void drawDot(int x, int y) {
  // Slightly bigger dot: 6x6 filled square for visibility with huge Pacman
  display.fillRect(x, y, 6, 6, SH110X_WHITE);
}

void setup() {
  display.begin(0x3C, true);  // Use 0x3C for most SH1106G OLEDs; adjust if needed
  
  // Clear the entire screen during initialization
  display.clearDisplay();
  display.display();  // Force immediate clear to black
  
  // Initial big dots (6x6 squares, spaced wider for 24x24 Pacman)
  int dotY = 30;  // Moved up to center vertically now that WiFi is gone
  int dotPositions[5] = {12, 35, 58, 81, 104};
  for (int i = 0; i < 5; i++) {
    drawDot(dotPositions[i], dotY);
  }
  
  // Update display after all initial draws
  display.display();
}

void loop() {
  // Pacman animation: moves right, eats dots (erases them), chomps mouth, resets on screen cross
  static int pacX = -24;  // Start off-screen left (bigger size)
  static bool mouthOpen = true;
  static bool eaten[5] = {false};  // Match numDots
  static unsigned long lastUpdate = 0;
  const int pacY = 18;  // Pacman top-left Y (centered vertically)
  const int dotY = 30;  // Dots centered with Pacman
  int dotPositions[5] = {12, 35, 58, 81, 104};
  const int numDots = 5;
  const int moveSpeed = 4;  // Faster to traverse screen quicker with massive size
  const int animationDelay = 120;  // ms delay (balanced for big visual heft)

  unsigned long currentTime = millis();
  if (currentTime - lastUpdate >= animationDelay) {
    // Clear old Pacman position if on screen (bigger clear area)
    if (pacX >= 0 && pacX < SCREEN_WIDTH) {
      display.fillRect(pacX, pacY, 24, 24, SH110X_BLACK);  // Clear 24x24 area
    }

    // Move Pacman
    pacX += moveSpeed;
    bool shouldReset = (pacX > SCREEN_WIDTH);

    if (shouldReset) {
      // Reset animation: reposition Pacman and restore all dots
      pacX = -24;
      for (int i = 0; i < numDots; i++) {
        eaten[i] = false;
        drawDot(dotPositions[i], dotY);
      }
    } else {
      // Check for eating dots at new position (wider range for huge Pacman)
      for (int i = 0; i < numDots; i++) {
        if (!eaten[i] && abs((pacX + 12) - (dotPositions[i] + 3)) <= 12) {  // Center-to-center <=12
          eaten[i] = true;
          display.fillRect(dotPositions[i], dotY, 6, 6, SH110X_BLACK);  // Erase dot
        }
      }
    }

    // Draw new Pacman if on screen
    if (pacX >= 0) {
      drawPacman(pacX, pacY, mouthOpen);
      mouthOpen = !mouthOpen;  // Toggle for chomping
    }

    // Update display
    display.display();
    lastUpdate = currentTime;
  }
}

How It Works (in short):

  • Display setup:
    Initializes the SH1106 OLED using the Adafruit library at I²C address 0x3C.
  • Pac-Man drawing (drawPacman):
    Draws a filled circle for Pac-Man and a small black triangle to simulate an open mouth that toggles each frame.
  • Dot drawing (drawDot):
    Creates small white squares that act as the food pellets.
  • Setup phase:
    Clears the display and draws 5 dots across the screen at fixed positions.
  • Loop animation:
    • Pac-Man moves right by a few pixels every frame (moveSpeed = 4).
    • His mouth opens and closes alternately (mouthOpen toggles).
    • When he reaches a dot, the dot is erased to look like it’s eaten.
    • After crossing the screen, Pac-Man resets to the left and dots reappear.
  • Display updates:
    The screen buffer is updated using display.display() after each move.

Result:

The gif below shows the output of the code. A smooth Pac-Man chomp animation — Pac-Man moves from left to right, eats the dots, then restarts for a continuous looping effect.

Gif shows the Pac-Man animation on the SH1106 Oled display, connected to Arduino.

Create Custom OLED Animations with Bitmap Frames

Creating your own custom animations on the SSD1306 OLED display is one of the most exciting parts of using this module. You can design unique motion effects, such as moving icons, rotating logos, or sensor-based visualizations, by displaying a series of bitmap frames in quick succession.

In this section, we’ll go step by step through the process of designing, converting, and displaying your own animation frames on the OLED screen.

Converting Images to Bitmaps

To display any custom animation, you first need to convert your images into bitmap arrays that Arduino can understand. Since the SSD1306 is a monochrome display, all images must be black and white.

You can follow the process of converting image to Bitmap mentioned above. To simulate an animation, you need to convert multiple frames and save them different header files, for example, frame1.h, frame2.h, frame3.h etc.


Displaying Custom Frames in a Loop

Once you’ve converted your images, it’s time to display them in sequence to form an animation.

Here’s an example of how to loop through several bitmap frames:

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

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

#include "frame1.h"
#include "frame2.h"
#include "frame3.h"

void setup() {
  display.begin(0x3C, true);  // Use 0x3C for most SH1106G OLEDs; adjust if needed
  display.clearDisplay();
}

void loop() {
  display.clearDisplay();
  display.drawBitmap(0, 0, frame1, 64, 32, SH110X_WHITE);
  display.display();
  delay(100);

  display.clearDisplay();
  display.drawBitmap(0, 0, frame2, 64, 32, SH110X_WHITE);
  display.display();
  delay(100);

  display.clearDisplay();
  display.drawBitmap(0, 0, frame3, 64, 32, SH110X_WHITE);
  display.display();
  delay(100);
}

Each frame is drawn and displayed for a short duration (100 ms here) before switching to the next. Adjusting the delay changes the animation speed — shorter delays result in smoother motion.

Tip: If your animation loops endlessly, you can use sensor inputs or button presses to trigger it at specific times (for example, when a sensor reading crosses a threshold).


Combining Multiple Frames for Motion Effect

To make your animation look more natural, use more frames with slight differences between them. For example, a rotating fan can be drawn in 4 or 6 positions to create the illusion of spinning.

You can store all your frames in an array and loop through them programmatically instead of repeating code blocks.

Example: In this example, I am using cat eye animation. I use this gif to extract the individual frames and then converted them to arrays.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include "cat_animation.h"

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


void setup() {
  display.begin(0x3C, true);  // Use 0x3C for most SH1106G OLEDs; adjust if needed
  display.clearDisplay();
}

void loop() {
    for (int i = 0; i < 3; i++) {
    display.clearDisplay();
    display.drawBitmap(0, 0, cat_allArray[i], 128, 64, SH110X_WHITE);
    display.display();
    delay(80); // frame delay for blinking effect
  }
}

The gif below shows the animation on the Oled Display.

Cute Cat eyes animation on SH1106 oled with Arduino

Conclusion

The SH1106 OLED display is a great choice for adding compact yet high-quality visuals to your Arduino projects. Throughout this tutorial, you learned how to connect the SH1106 display using the I2C interface and properly install the Adafruit GFX and SH1106 libraries to get it working. You also discovered how to display text, draw basic shapes like lines and rectangles, and adjust the contrast or scroll text across the screen for dynamic effects.

Additionally, you explored how to convert and display bitmap images on the OLED and even create simple animations using frame-based techniques. These skills allow you to design more creative and interactive display outputs, such as moving icons or logos. By understanding how to troubleshoot common problems like connection errors, flickering, or inverted display issues, you are now well-prepared to handle real-world challenges and confidently use the SH1106 OLED in your Arduino projects.

Browse More Arduino Display Tutorials

1 2

Arduino SH1106 Oled Project Download

Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

Arduino SH1106 Oled FAQs

About the Author
Arun Rawat
Arun Rawat
Embedded Systems Engineer · Founder, ControllersTech

Arun is an embedded systems engineer with 10+ years of experience in STM32, ESP32, and AVR microcontrollers. He created ControllersTech to share practical tutorials on embedded software, HAL drivers, RTOS, and hardware design — grounded in real industrial automation experience.

Subscribe
Notify of

0 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
×

Don’t Miss Future STM32 Tutorials

Join thousands of developers getting free guides, code examples, and updates.