ArduinoでSSD1306 OLEDを使うとき、多機能ライブラリを使うと便利ですが、小さなメモリしかないATtinyシリーズやATmega8では容量不足になりがちです。
そこで今回は 機能を最小限に絞ったオリジナルの軽量ライブラリ を作成し、通常表示に加えて 2倍拡大文字表示 にも対応させてみました。
初心者の方でもわかりやすいように、フォント定義からライブラリ構成、表示の実例までを解説します。
ライブラリを軽量化する理由
- 標準のSSD1306ライブラリは機能豊富だが、メモリ消費が大きい
- ATtiny402やATmega8ではメモリ不足で動かない場合がある
- 必要最低限の機能(文字表示だけ)に絞れば、小さなマイコンでも動作可能
フォントデータの準備
- 5×7 ドットの英数字フォントを配列で定義
- 必要な文字だけを収録(A~Z, 0~9, 記号など)
- 例:
+ - = % .を追加しても数バイトで済む
{ 0b00000, 0b00100, 0b00100, 0b11111, 0b00100, 0b00100, 0b00000 }, // +
{ 0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000 }, // -軽量OLEDライブラリの構造
MyOLED.h SimpleFont.h MyOLED.cpp の3ファイル構成
ファイル構成イメージ
MyOLEDLib/
├─ src/
│ ├─ MyOLEDLib.h
│ ├─ MyOLEDLib.cpp
│ └─ SimpleFont.h
└─ library.properties // 別にこれがなくても大丈夫です(ライブラリーの情報ファイル)SimpleFont.h
#ifndef SIMPLEFONT_H
#define SIMPLEFONT_H
// 5x7 縦向きフォント A-Z, 0-9
const uint8_t font5x7[][7] = {
// A-Z (26文字)
{ 0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001 }, // A
{ 0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110 }, // B
{ 0b01110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b01110 }, // C
{ 0b11100, 0b10010, 0b10001, 0b10001, 0b10001, 0b10010, 0b11100 }, // D
{ 0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111 }, // E
{ 0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000 }, // F
{ 0b01110, 0b10001, 0b10000, 0b10111, 0b10001, 0b10001, 0b01110 }, // G
{ 0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001 }, // H
{ 0b01110, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110 }, // I
{ 0b00001, 0b00001, 0b00001, 0b00001, 0b10001, 0b10001, 0b01110 }, // J
{ 0b10001, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, 0b10001 }, // K
{ 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111 }, // L
{ 0b10001, 0b11011, 0b10101, 0b10001, 0b10001, 0b10001, 0b10001 }, // M
{ 0b10001, 0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001 }, // N
{ 0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110 }, // O
{ 0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000 }, // P
{ 0b01110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10010, 0b01101 }, // Q
{ 0b11110, 0b10001, 0b10001, 0b11110, 0b10100, 0b10010, 0b10001 }, // R
{ 0b01111, 0b10000, 0b10000, 0b01110, 0b00001, 0b00001, 0b11110 }, // S
{ 0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100 }, // T
{ 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110 }, // U
{ 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01010, 0b00100 }, // V
{ 0b10001, 0b10001, 0b10001, 0b10001, 0b10101, 0b11011, 0b10001 }, // W
{ 0b10001, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, 0b10001 }, // X
{ 0b10001, 0b10001, 0b01010, 0b00100, 0b00100, 0b00100, 0b00100 }, // Y
{ 0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b11111 }, // Z
// 0-9 (10文字)
{ 0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110 }, // 0
{ 0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110 }, // 1
{ 0b01110, 0b10001, 0b00001, 0b00110, 0b01000, 0b10000, 0b11111 }, // 2
{ 0b11110, 0b00001, 0b00001, 0b01110, 0b00001, 0b00001, 0b11110 }, // 3
{ 0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010 }, // 4
{ 0b11111, 0b10000, 0b11110, 0b00001, 0b00001, 0b10001, 0b01110 }, // 5
{ 0b00110, 0b01000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110 }, // 6
{ 0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b10000 }, // 7
{ 0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110 }, // 8
{ 0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00010, 0b01100 }, // 9
// a-z (26文字)
{ 0b00000, 0b00000, 0b01110, 0b00001, 0b01111, 0b10001, 0b01111 }, // a
{ 0b10000, 0b10000, 0b10110, 0b11001, 0b10001, 0b10001, 0b11110 }, // b
{ 0b00000, 0b00000, 0b01110, 0b10001, 0b10000, 0b10001, 0b01110 }, // c
{ 0b00001, 0b00001, 0b01101, 0b10011, 0b10001, 0b10001, 0b01111 }, // d
{ 0b00000, 0b00000, 0b01110, 0b10001, 0b11110, 0b10000, 0b01110 }, // e
{ 0b00110, 0b01001, 0b01000, 0b11100, 0b01000, 0b01000, 0b01000 }, // f
{ 0b00000, 0b01111, 0b10001, 0b10001, 0b01111, 0b00001, 0b01110 }, // g
{ 0b10000, 0b10000, 0b10110, 0b11001, 0b10001, 0b10001, 0b10001 }, // h
{ 0b00100, 0b00000, 0b01100, 0b00100, 0b00100, 0b00100, 0b01110 }, // i
{ 0b00010, 0b00000, 0b00110, 0b00010, 0b00010, 0b10010, 0b01100 }, // j
{ 0b10000, 0b10000, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010 }, // k
{ 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110 }, // l
{ 0b00000, 0b00000, 0b11010, 0b10101, 0b10101, 0b10101, 0b10101 }, // m
{ 0b00000, 0b00000, 0b10110, 0b11001, 0b10001, 0b10001, 0b10001 }, // n
{ 0b00000, 0b00000, 0b01110, 0b10001, 0b10001, 0b10001, 0b01110 }, // o
{ 0b00000, 0b00000, 0b11110, 0b10001, 0b11110, 0b10000, 0b10000 }, // p
{ 0b00000, 0b00000, 0b01111, 0b10001, 0b01111, 0b00001, 0b00001 }, // q
{ 0b00000, 0b00000, 0b10110, 0b11001, 0b10000, 0b10000, 0b10000 }, // r
{ 0b00000, 0b00000, 0b01110, 0b10000, 0b01110, 0b00001, 0b11110 }, // s
{ 0b01000, 0b01000, 0b11100, 0b01000, 0b01000, 0b01001, 0b00110 }, // t
{ 0b00000, 0b00000, 0b10001, 0b10001, 0b10001, 0b10011, 0b01101 }, // u
{ 0b00000, 0b00000, 0b10001, 0b10001, 0b01010, 0b01010, 0b00100 }, // v
{ 0b00000, 0b00000, 0b10001, 0b10001, 0b10101, 0b10101, 0b01010 }, // w
{ 0b00000, 0b00000, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001 }, // x
{ 0b00000, 0b00000, 0b10001, 0b10001, 0b01111, 0b00001, 0b01110 }, // y
{ 0b00000, 0b00000, 0b11111, 0b00010, 0b00100, 0b01000, 0b11111 }, // z
{ 0b00000, 0b00100, 0b00100, 0b11111, 0b00100, 0b00100, 0b00000 }, // +
{ 0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000 }, // -
{ 0b00000, 0b00000, 0b11111, 0b00000, 0b11111, 0b00000, 0b00000 }, // =
{ 0b11000, 0b11001, 0b00010, 0b00100, 0b01000, 0b10011, 0b00011 }, // %
{ 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00110, 0b00110 }, // .
{ 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b00000, 0b00000 }, // '/' index=67
{0b01010,0b00100,0b11111,0b00100,0b01010,0b00000,0b00000} // '*' index=68
};
#endifMyOLED.h
#ifndef MYOLEDLIB_H
#define MYOLEDLIB_H
#include <Arduino.h>
#include <Wire.h>
#include "SimpleFont.h"
class MyOLED {
public:
MyOLED(uint8_t addr = 0x3C);
void init();
void clear();
//void setCursor(uint8_t x, uint8_t page);
void drawChar(char c, uint8_t x, uint8_t page);
void drawString(const char* str, uint8_t x, uint8_t page);
void drawChar2x(char c, uint8_t x, uint8_t page);
void drawString2x(const char* str, uint8_t x, uint8_t page);
private:
uint8_t _addr;
void sendCommand(uint8_t cmd);
void sendData(uint8_t data);
void setCursor(uint8_t x, uint8_t page);
};
#endifMyOLEDLib.cpp
#include "MyOLEDLib.h"
const uint8_t init_cmds[] = {
0xAE, 0x20, 0x00, 0xB0, 0xC8, 0x00, 0x10,
0x40, 0x81, 0x7F, 0xA1, 0xA6, 0xA8, 0x3F,
0xA4, 0xD3, 0x00, 0xD5, 0xF0, 0xD9, 0x22,
0xDA, 0x12, 0xDB, 0x20, 0x8D, 0x14, 0xAF
};
MyOLED::MyOLED(uint8_t addr) {
_addr = addr;
}
void MyOLED::sendCommand(uint8_t cmd) {
Wire.beginTransmission(_addr);
Wire.write(0x00);
Wire.write(cmd);
Wire.endTransmission();
}
void MyOLED::sendData(uint8_t data) {
Wire.beginTransmission(_addr);
Wire.write(0x40);
Wire.write(data);
Wire.endTransmission();
}
void MyOLED::init() {
Wire.begin();
delay(100);
for (uint8_t i = 0; i < sizeof(init_cmds); i++) {
sendCommand(init_cmds[i]);
}
}
void MyOLED::setCursor(uint8_t x, uint8_t page) {
sendCommand(0xB0 + page);
sendCommand(0x00 + (x & 0x0F));
sendCommand(0x10 + (x >> 4));
}
void MyOLED::clear() {
for (uint8_t page = 0; page < 8; page++) {
setCursor(0, page);
for (uint8_t i = 0; i < 128; i++) {
sendData(0x00);
}
}
}
void MyOLED::drawChar(char c, uint8_t x, uint8_t page) {
uint8_t index;
if (c >= 'A' && c <= 'Z') {
index = c - 'A';
} else if (c >= '0' && c <= '9') {
index = 26 + (c - '0');
} else if (c >= 'a' && c <= 'z') {
index = 36 + (c - 'a');
} else {
switch (c) {
case '+': index = 62; break;
case '-': index = 63; break;
case '=': index = 64; break;
case '%': index = 65; break;
case '.': index = 66; break;
case '/': index = 67; break;
case '*': index = 68; break;
default: return;
}
}
for (int col = 0; col < 5; col++) {
uint8_t colBits = 0;
for (int row = 0; row < 7; row++) {
if (font5x7[index][row] & (1 << (4 - col))) {
colBits |= (1 << row);
}
}
setCursor(x + col, page);
sendData(colBits);
}
setCursor(x + 5, page);
sendData(0x00);
}
void MyOLED::drawString(const char* str, uint8_t x, uint8_t page) {
while (*str) {
drawChar(*str, x, page);
x += 6;
str++;
}
}
void MyOLED::drawChar2x(char c, uint8_t x, uint8_t page) {
uint8_t index;
if (c >= 'A' && c <= 'Z') {
index = c - 'A';
} else if (c >= '0' && c <= '9') {
index = 26 + (c - '0');
} else if (c >= 'a' && c <= 'z') {
index = 36 + (c - 'a');
} else {
switch (c) {
case '+': index = 62; break;
case '-': index = 63; break;
case '=': index = 64; break;
case '%': index = 65; break;
case '.': index = 66; break;
case '/': index = 67; break;
case '*': index = 68; break;
default: return;
}
}
for (int col = 0; col < 5; col++) {
uint16_t colBits = 0;
for (int row = 0; row < 7; row++) {
if (font5x7[index][row] & (1 << (4 - col))) {
colBits |= (1 << (row * 2)); // 2倍縦拡大
colBits |= (1 << (row * 2 + 1));
}
}
// 横2倍で出力
for (int dx = 0; dx < 2; dx++) {
// 下位8bit → 上位8bit に分割して2ページに描画
setCursor(x + col * 2 + dx, page);
sendData(colBits & 0xFF);
setCursor(x + col * 2 + dx, page + 1);
sendData((colBits >> 8) & 0xFF);
}
}
// 1列分のスペース
for (int dx = 0; dx < 2; dx++) {
setCursor(x + 10 + dx, page);
sendData(0x00);
setCursor(x + 10 + dx, page + 1);
sendData(0x00);
}
}
void MyOLED::drawString2x(const char* str, uint8_t x, uint8_t page) {
while (*str) {
drawChar2x(*str, x, page);
x += 12; // 横幅 10 + 空白2
str++;
}
}- 主な関数:
init()… 初期化処理clear()… 画面クリアdrawChar()… 通常文字表示drawString()… 通常文字列表示drawChar2x()… 2倍拡大文字表示drawString2x()… 2倍拡大文字列表示
スケッチ例
#include <Wire.h>
#include "MyOLEDLib.h" //まだlibraryフォルダの中に保存していませんのでこのようにして呼び出します
MyOLED oled;
void setup() {
oled.init();
oled.clear();
oled.drawString("HELLO123-+/*%", 0, 0);
oled.drawString("Arduino OLED as", 0, 1);
oled.drawString2x("HIabcdl2%", 0, 4);
}
void loop() {
}Nano モードでコンパイル

最大30720バイトのフラッシュメモリのうち、スケッチが4062バイト(13%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が778バイト(37%)を使っていて、ローカル変数で1270バイト使うことができます。
ATtiny402 モードでコンパイル
最大4096バイトのフラッシュメモリのうち、スケッチが2573バイト(62%)を使っています。
最大256バイトのRAMのうち、グローバル変数が97バイト(37%)を使っていて、ローカル変数で159バイト使うことができます。
まとめ
今回作成したライブラリは、
MyOLED::init()を呼ぶだけで簡単に初期化できる- 通常表示と2倍拡大表示を両立
- 小メモリ Arduino でも使えるシンプル設計
「文字だけで十分」「最低限の機能で軽く動かしたい」という方には最適です。これをベースに、自分だけのオリジナル OLED ライブラリをカスタマイズしていくのも楽しいですよ!



