Most Arduino owners, at some point, want to output text or results to a screen for their projects. Most of these begin with the use of a two-line LCD because they’re readily available, cheap, and have tons of example programs already available. It uses most of your digital I/O lines and only prints text- no graphs, shapes, or icons. The small yet versatile SSD1306 OLED measures diagonally only at 0.96 inches. It is a mono digital display using only two pins (SCL and SDA) to communicate, perfect for graphing or displaying geometrical shapes. You can power it directly from the Arduino with 5V and GND, and it works on 3V devices as well.
Materials Required
Component | Description | Quantity |
Arduino | UNO or similar microcontroller board | 1 |
SSD1306 OLED Display | 128×64 I2C interface OLED screen | 1 |
Connecting Wires | Male-to-male or male-to-female jumper wires | 4-6 |
10k Ohm Potentiometer | Variable resistor with three pins | 1 |
Step 1: Hooking up the display
Connect your display like this:
Connect for a UNO or a Nano
GND → GND
SDA → A4
SCL → A5
On a Mega or Leonardo:
SDA → Pin 20
SCL → Pin 21
Note: The pins on some of the SSD1306 modules might be in a different order. So, refer to the labels on your board for clarity.
Step 2: Confirm the I2C Address
To test your display’s I2C address:
Download the I2C Scanner script from Arduino Playground.
Copy the code to Arduino IDE and compile and upload it.
Open the Serial Monitor. Your display’s I2C address will be displayed (mine was 0x3C). Note that down for later.
Step 3: Include the necessary libraries
Import the SSD1306 library now:
Open the Arduino IDE and follow the instructions:
Draw → Add Library → Libraries.
You look for “SSD1306” at the top-right corner.
Install the library Adafruit1306.
Step 4: Installing Additional Libraries After installing the SSD1306 library:
Proceed with installing all dependencies following the prompts.
Confirm that the new library is listed under Sketch → Include Library.
Step 5: Testing the Installation
Testing the Installation Step 5 Load the example sketch
Drawing → Examples → Adafruit SSD1306 → ssd1306_128x64_i2c.
In the void setup() section
locate the following line:
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64
Replace 0x3D with your board’s address (e.g., 0x3C).
Preserve, assemble, and submit the design.
This demo shows many features of the SSD1306 display and library—quite impressive!
Step 6: Library Methods
The SSD1306 library provides various drawing and text methods:
Drawing Primitives
- Pixels: drawPixel(x, y, color);
- Lines: drawLine(x0, y0, x1, y1, color);
- Shapes: drawRect(), fillCircle(), etc.
Text Commands
- Draw Text: drawChar(x, y, char, color, bg, size);
- Cursor Management: adjustCursor(x, y);
- Text Size/Color: setTextSize(size);, setTextColor(color);
- Important: Always call display.display(); after drawing or writing to update the screen!
Step 7: Illustrative Diagrams
This illustration employs arbitrary pixels, sinusoidal curves, and fundamental geometric figures.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
// Not needed with I2C
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED RESET 4 // Reset pin (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display (SCREEN WIDTH, SCREEN HEIGHT, &Wire, OLED RESET);
void show() { // Often used sequence - Function to simplify code display.display(); delay(2000); display.fillScreen (SSD1306_BLACK);
}
void setup() {
Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin (SSD1306_SWITCHCAPVCC, 0x3C)) { // Old Address 0x3D for 128x64 Serial.println (F("SSD1306 allocation failed"));
}
for(;;); // Don't proceed, loop forever
// Initialise variables
int x0 = 5; // 3 pairs of co-ordinates int y0 = 5;
int x1
120;
int y1
23;
55;
int x2
int y2 = 60;
int w= 105; // width inth 55; // height
int r 25; // radius
int cw= SSD1306_WHITE; // colour white int cb = SSD1306_BLACK; // colour black int wait 2000; // 2 second delay
Text Example
Here, you’ll explore text wrapping, font sizes, and positioning messages along curves.
Combining Text and Graphics
Add a potentiometer to simulate input values that change a bar graph in real-time.
Step 8: Illustration Example (GFX #2)
This section shows how to create a title screen, generate random pixels, and plot a sine wave on the display. Instructions: Start with the initialization code in Step 7. Add functions to generate random points and sine wave values.
// Title screen
display.clearDisplay();
display.setTextSize(1);
display.setTextColor (cw); display.setCursor (28,25);
display.println("Screen"); display.setCursor(28,33); display.println("Primitives");
display.display(); delay (wait); randomSeed (analogRead (3)); display.fillScreen (cw);
display.display(); delay (wait); display.fillScreen (cb); display.display();
// Pixels
for (int i = 0; i <= 25; i++) int xx random (127);
}
int yy
random (63);
display.drawPixel (xx, yy, cw);
display.display();
delay(200);
delay (wait); display.fillScreen (cb);
float sine [127];
// Initialise variables
display.fillScreen (cb);
// Normal 1:1 pixel scale
// Fill screen WHITE
// Fill screen BLACK
// 25 random pixels
display.drawFastHLine (0, 32, 127, cw);
for (int i = 0; i < 128; i++) {
sine [i]
(sin (radians (i *2.8125))) * -1;
display.drawPixel (i, int (sine [i] *25+32), cw); display.display();
}
Here’s a simple code snippet for a sine curve:
for (int x = 0; x < 128; x++) {
int y = 32 + 20 * sin(x * 0.1);
display.drawPixel(x, y, SSD1306_WHITE);
}
display.display();
Step 9: Advanced Graphics (GFX #3)
Filled Shapes
Using fillCircle()
and fillRect()
, you can make solid structures.
For instance
// Basic Draw & Fill
show();
display.drawLine (x0, yo, xl, yl + 30, cw);
show();
display.drawFastVLine (35, 15, h, cw); // Fast vertical line of length 1
show();
show();
display.drawFastHLine (5, 25, w, cw);
// Fast horizontal line of length w
display.drawRect(x0, y0, w, h, cw);
show();
display.fillRect(x0, y0, w, h, cw);
show();
display.drawRoundRect (x0, yo, w, h, 8, cw); // Rounded corners of radius 8
show();
display.fillRoundRect (x0, yo, w, h, 8, cw);
show();
display.drawCircle (63, 31, r, cw); electronicsmith.com
show();
display.fillCircle (63, 31, r, cw);
show();
display.drawTriangle (x0, yo, xl, yl, x2, y2, cw);
show();
display.fillTriangle (x0, y0, xl, yl, x2, y2, cw);
show();
Step 10: Rotation of screen
To rotate the screen, use the following function:
display.setRotation(1); // 0 = default, 1 = 90°, 2 = 180°, 3 = 270°
Step 11: Playing with Text
The text capabilities of the SSD1306 library allow for a range of applications, from basic messages to dynamic updates.
Example: Displaying more than one font size
// Initialise variables
int cw
SSD1306_WHITE;
int cb= SSD1306_BLACK;
// Title screen
display.clearDisplay();
display.setTextSize(2);
display.setTextColor (SSD1306_WHITE); // Draw white text
display.setCursor (20, 10);
display.setTextSize (2);
display.println("Playing");
display.setCursor (20, 25); display.println("with");
display.setCursor (20,40); display.println("Text");
show();
display.setTextSize(1);
// Text Sizes
display.clearDisplay(); display.setTextSize(1);
// Medium
electronicsmith.com
display.setTextColor (SSD1306_WHITE); display.setCursor(0,0);
display.println("Text Size Demo");
display.setTextSize(2):
display.println("SSD1306"); display.setTextSize (3);
display.println("SSD1306");
display.setTextSize(1);
display.println(" ");
// Normal 1:1 pixel scale // Draw white text
// Start at top-left corner
// Medium
// Large rather blocky
display.println("
show();
Tony Go");
Step 12: Combining Features
A Small Project
For this project, hook up a 10k Ohm potentiometer as in the previous sections. Twisting the potentiometer will dynamically:
Update a bar graph.
Display raw potentiometer values (0–1023).
Show the percentage of the maximum value on-screen.
char msg[]
=
"Arduino+SSD1306-MAGIC";
char msg2[] = "Follow the Cosine +"; char msg3[] "...Tangents go up.//1"; char bigMsg[] = ".+Arduino+.";
display.clearDisplay();
for (int i = 0; i < 21; i++) {
}
msg[i];
i*6;
char ch
int xx
float yl
=
int yy
// Sine curve
(sin (radians (xx *2.8125)) * -1); int (yl 25.0 + 32);
display.drawChar (xx, yy, ch, cw, cb, 1); display.display();
show();
display.clearDisplay();
for (int i = 0; i < 21; i++) {
// Cosine curve
char ch
msg2 [i];
}
int xx
float yl
i*6;
(cos (radians (xx 2.8125)) * -1);
int yy = int(yl *25.0 + 32);
display.drawChar (xx, yy, ch, cw, cb, 1); display.display();
show();
display.clearDisplay();
for (int i = 0; i < 21; i++) { // Tangent curve
}
char ch msg3[1];
int xx= 16;
float yl= (tan (radians (xx 2.8125/4)) * -1); int yy int (yl
5.458);
display.drawChar (xx, yy, ch, cw, cb, 1); display.display();
show();
display.clearDisplay();
int y2 = 50;
for (int i = 0; i < 11; i++) { // Diagonal
char ch = bigMsg[i];
int xx
i*12;
display.drawChar (xx, y2, ch, cw, cb, 2); y2 = y2 5;
display.display();
}
Step 13: Playing with Text #2
Plotting Text Along Curves
You can display text messages along mathematical curves like sine, cosine, or tangent. For instance:
for (int x = 0; x < 128; x += 12) {
int y = 32 + 20 * sin(x * 0.1); // Sine curve
display.setCursor(x, y);
display.print("O"); // Plot text along the curve
}
display.display();
This will place the character ‘O’ along the sine wave at regular intervals. Try using other shapes or characters to make for some interesting visualizations!
Adding Large Characters
To include bigger characters diagonally on the screen
for (int i = 0; i < 5; i++) {
display.setTextSize(i + 1);
display.setCursor(i * 10, i * 8);
display.print("X"); // Large character diagonal
}
display.display();
// Overwrite method #1 - Same text but write in background colour for (int i = 0; i < 5; i++) {
}
display.setTextColor (cb); // Black text overwrite previous
display.setCursor (100,56);
display.println("Done");
display.display();
delay(500);
display.setTextColor(cw);
display.setCursor (100, 56);
display.println("Done"); // White text overwrite
display.display();
delay (500);
// Overwrite method #2 Filled background rectangle over text
int x = 50;
int y = 40;
display.clearDisplay();
display.setTextSize (3);
for (int i=95; i < 9999; i++) {
display.setCursor(x, y);
display.setTextColor (cw); display.println(i);
display.display();
delay(200);
electronicsmith.com
display.fillRect(x, y, 127, 63, cb); // Overwrite with black rectangle display.display();
}
}
void loop() {
// put your main code here, to run repeatedly:
Step 14: 3rd Sketch – A Little Project
For this project, you’ll add a 10k Ohm potentiometer to the circuit. The potentiometer will allow us to interact with the display dynamically by changing an analog input.
Circuit Connections
- Center pin of the potentiometer → A0 (Analog pin).
- One outer pin → 5V.
- Other outer pin → GND.
Code Overview
Dynamic Bar Graph
- The length of the bar graph will adjust based on the potentiometer’s position.
Display
Raw potentiometer readings, 0–1023, are shown in a box.
At the bottom of the graph is a percentage of the maximum.
Timer Update
The following timer, displayed at top right, refreshes in an interval not blocking().
Example:
#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);
unsigned long previousMillis = 0;
const long interval = 1000;
int seconds = 0;
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Replace 0x3C with your address
display.clearDisplay();
}
void loop() {
int potValue = analogRead(A0);
int barLength = map(potValue, 0, 1023, 0, 128);
int percentage = map(potValue, 0, 1023, 0, 100);
// Clear screen
display.clearDisplay();
// Draw bar graph
display.fillRect(0, 50, barLength, 10, SSD1306_WHITE);
// Display raw value and percentage
display.setCursor(0, 0);
display.setTextSize(1);
display.print("Raw: ");
display.println(potValue);
display.print("Percent: ");
display.println(percentage);
// Timer
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
seconds++;
}
display.setCursor(90, 0);
display.print("Time: ");
display.print(seconds);
// Update display
display.display();
}
Results
As you turn the potentiometer, the bar graph’s length changes on the fly.
The raw potentiometer value and its percentage are shown in real-time.
A timer counts elapsed time every second and does not freeze up the program using delay().