小さなArduinoでも使える!シンプルなSSD1306ライブラリと2倍文字表示の作り方

小さなArduinoでも使える!シンプルなSSD1306ライブラリと2倍文字表示の作り方
スポンサーリンク

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
};
#endif

MyOLED.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);
};

#endif

MyOLEDLib.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 モードでコンパイル

ATtiny402 モードでコンパイル

まとめ

今回作成したライブラリは、

  • MyOLED::init() を呼ぶだけで簡単に初期化できる
  • 通常表示と2倍拡大表示を両立
  • 小メモリ Arduino でも使えるシンプル設計

「文字だけで十分」「最低限の機能で軽く動かしたい」という方には最適です。これをベースに、自分だけのオリジナル OLED ライブラリをカスタマイズしていくのも楽しいですよ!

タイトルとURLをコピーしました