Three small screens on an Arduino Uno
A 128x32 SSD1306, a 1.3 inch SH1106 and a Nokia 5110 on one Uno, each started by hand: the charge pump, column 2 and Vop. The whole build, an Arduino Uno and 3 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
AdvancedRuns in your browser. Free, and no account needed.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Three small screens: a 128x32 SSD1306, a 1.3 inch SH1106 and a Nokia 5110,
// each driven by hand so the differences between them are in plain sight.
//
// SSD1306 128x32 SCL -> A5 SDA -> A4 address 0x3C
// SH1106 1.3 inch SCL -> A3 SDA -> A2 address 0x3C
// Nokia 5110 RST 3 CE 4 DC 5 DIN 6 CLK 7 LIGHT 8
//
// All three keep their pixels as bytes of eight stacked dots, bit 0 at the
// top, in rows of bytes called pages or banks. What differs is the start-up
// and the addressing:
//
// - the SSD1306 needs its charge pump switched on (0x8D 0x14), and a 32-row
// strip needs its multiplex (0xA8 0x1F) and COM pins (0xDA 0x02) set;
// - the SH1106 starts with its DC-DC on and has 132 columns of RAM, so every
// page is written from column 2;
// - the Nokia's contrast is Vop, which starts at 0: nothing shows until the
// sketch sets it.
//
// The two OLEDs are both at 0x3C, so each has an I2C bus of its own, bit-banged
// on two pins by mokxi_i2c.h. (On one shared bus, one of them would need its
// address jumper moved to 0x3D.) No frame buffers: this board has 2 KB of RAM
// and three screens would want more than that, so each line of text goes
// straight to its screen.
#include "mokxi_font5x7.h"
#include "mokxi_i2c.h"
const uint8_t OLED = 0x3C;
SoftI2c strip(A5, A4);
SoftI2c big(A3, A2);
const uint8_t N_RST = 3, N_CE = 4, N_DC = 5, N_DIN = 6, N_CLK = 7, N_LIGHT = 8;
// ---- the two OLEDs, each on its own bus -------------------------------------
// One transfer: the address, a control byte (0x00 commands, 0x40 display
// data), then the bytes.
static void oledSend(const SoftI2c &bus, uint8_t control, const uint8_t *bytes, uint8_t count) {
if (bus.start(OLED)) {
bus.write(control);
bus.write(bytes, count);
}
bus.stop();
}
// Point an OLED at a page and a column, the page-addressing way both chips
// understand: 0xB0 + page, then the column in two nibbles.
static void oledAt(const SoftI2c &bus, uint8_t page, uint8_t column) {
const uint8_t where[] = {(uint8_t)(0xB0 | page), (uint8_t)(column & 0x0F),
(uint8_t)(0x10 | (column >> 4))};
oledSend(bus, 0x00, where, 3);
}
static void oledClear(const SoftI2c &bus, uint8_t pages, uint8_t first) {
static const uint8_t ZEROS[16] = {0};
for (uint8_t page = 0; page < pages; page++) {
oledAt(bus, page, first);
for (uint8_t chunk = 0; chunk < 128 / 16; chunk++) oledSend(bus, 0x40, ZEROS, 16);
}
}
static void oledText(const SoftI2c &bus, uint8_t page, uint8_t column, const char *text) {
oledAt(bus, page, column);
for (; *text != '\0'; text++) {
uint8_t cell[FONT_WIDTH + 1];
for (uint8_t col = 0; col < FONT_WIDTH; col++) cell[col] = mokxi_font_column(*text, col);
cell[FONT_WIDTH] = 0;
oledSend(bus, 0x40, cell, FONT_WIDTH + 1);
}
}
// ---- the Nokia, on its own five pins -----------------------------------------
static void nokiaSend(bool data, uint8_t value) {
digitalWrite(N_DC, data ? HIGH : LOW);
digitalWrite(N_CE, LOW);
shiftOut(N_DIN, N_CLK, MSBFIRST, value);
digitalWrite(N_CE, HIGH);
}
static void nokiaText(uint8_t bank, uint8_t x, const char *text) {
nokiaSend(false, (uint8_t)(0x40 | bank));
nokiaSend(false, (uint8_t)(0x80 | x));
for (; *text != '\0'; text++) {
for (uint8_t col = 0; col < FONT_WIDTH; col++) nokiaSend(true, mokxi_font_column(*text, col));
nokiaSend(true, 0x00);
}
}
void setup() {
strip.begin();
big.begin();
// The 128x32: 32 rows, sequential COM pins, the charge pump, page mode, the
// two remaps that turn the picture upright, and on.
static const uint8_t STRIP[] = {0xAE, 0xA8, 0x1F, 0xDA, 0x02, 0x8D, 0x14,
0x20, 0x02, 0xA1, 0xC8, 0xAF};
oledSend(strip, 0x00, STRIP, sizeof(STRIP));
oledClear(strip, 4, 0);
oledText(strip, 0, 0, "SSD1306 128X32");
oledText(strip, 2, 0, "PAGES 0 TO 3");
// The SH1106: 64 rows, DC-DC on (it already is), the remaps, and on. No
// 0x20 addressing mode, because it has only one.
static const uint8_t BIG[] = {0xAE, 0xA8, 0x3F, 0xAD, 0x8B, 0xA1, 0xC8, 0xAF};
oledSend(big, 0x00, BIG, sizeof(BIG));
oledClear(big, 8, 2);
oledText(big, 0, 2, "SH1106 1.3 INCH");
oledText(big, 2, 2, "FROM COLUMN 2");
oledText(big, 7, 2, "ONE PAGE AT A TIME");
// The Nokia: reset, then the extended set for Vop, temperature and bias,
// back to the basic set, normal display.
pinMode(N_RST, OUTPUT);
pinMode(N_CE, OUTPUT);
pinMode(N_DC, OUTPUT);
pinMode(N_DIN, OUTPUT);
pinMode(N_CLK, OUTPUT);
pinMode(N_LIGHT, OUTPUT);
digitalWrite(N_CE, HIGH);
digitalWrite(N_RST, LOW);
delay(1);
digitalWrite(N_RST, HIGH);
static const uint8_t NOKIA[] = {0x21, 0x80 | 50, 0x04, 0x14, 0x20, 0x0C};
for (uint8_t i = 0; i < sizeof(NOKIA); i++) nokiaSend(false, NOKIA[i]);
nokiaSend(false, 0x40);
nokiaSend(false, 0x80);
for (int i = 0; i < 504; i++) nokiaSend(true, 0x00);
nokiaText(0, 0, "NOKIA 5110");
nokiaText(2, 0, "VOP IS 50");
digitalWrite(N_LIGHT, HIGH);
}
void loop() {
// A seconds count on each, so all three are plainly alive.
char digits[8];
unsigned long s = millis() / 1000;
uint8_t n = 0;
do {
digits[n++] = (char)('0' + s % 10);
s /= 10;
} while (s != 0 && n < 7);
char shown[8];
for (uint8_t i = 0; i < n; i++) shown[i] = digits[n - 1 - i];
shown[n] = '\0';
oledText(strip, 3, 0, shown);
oledText(big, 4, 2, shown);
nokiaText(4, 0, shown);
delay(200);
}
Parts list
5 parts, plus the jumper wires. Every one is in the editor's parts bin.
How it is wired
12 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- Arduino Uno R3 pin 8; Nokia 5110 display, PCD8544 pin LIGHT
- Arduino Uno R3 pin 7; Nokia 5110 display, PCD8544 pin CLK
- Arduino Uno R3 pin 6; Nokia 5110 display, PCD8544 pin DIN
- Arduino Uno R3 pin 5; Nokia 5110 display, PCD8544 pin DC
- Arduino Uno R3 pin 4; Nokia 5110 display, PCD8544 pin CE
- Arduino Uno R3 pin 3; Nokia 5110 display, PCD8544 pin RST
- Arduino Uno R3 pin 5V; OLED display, 128x32 pin VCC; OLED display, 1.3 inch SH1106 pin VCC; Nokia 5110 display, PCD8544 pin VCC
- Ground: Arduino Uno R3 pin GND; OLED display, 128x32 pin GND; OLED display, 1.3 inch SH1106 pin GND; Nokia 5110 display, PCD8544 pin GND
- Arduino Uno R3 pin A2; OLED display, 1.3 inch SH1106 pin SDA
- Arduino Uno R3 pin A3; OLED display, 1.3 inch SH1106 pin SCL
- Arduino Uno R3 pin A4; OLED display, 128x32 pin SDA
- Arduino Uno R3 pin A5; OLED display, 128x32 pin SCL
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.