Font to Binary Converter ツールを開く

8×8 LED マトリクス(MAX7219)に文字を表示する:ドットフォントを 1 文字 8 バイトの配列にする

公開: · 作者: takushio2525

8×8 の LED マトリクスに文字を出すときは、1 文字を「8 行 × 8 ドット」の点灯パターンとして持ちます。横 1 行の 8 個の LED を 1 バイトの 8 ビットに対応させれば、1 文字はちょうど 8 バイトです。この記事では、Font to Binary Converter で美咲フォント 8×8 の配列を作り、MAX7219 を載せた LED マトリクスのモジュールに表示するまでを説明します。

ハロー

1 文字 = 8 バイトの考え方

「ロ」を例にすると、上の行から順に、点灯する LED を 1、消える LED を 0 にして 8 ビットの数にしたものが 1 行ぶんのデータです。左端の LED を最上位ビット(bit7)に置いています。

行ドット(# が点灯)2 進16 進
0........0b000000000x00
1#######.0b111111100xFE
2#.....#.0b100000100x82
3#.....#.0b100000100x82
4#.....#.0b100000100x82
5#.....#.0b100000100x82
6#######.0b111111100xFE
7........0b000000000x00

この 8 個の数を上の行から順に並べたものが、「ロ」1 文字のデータです。

用意するもの

  • Arduino Uno など。この記事のスケッチは、Arduino IDE 同梱の arduino-cli で Uno 向けにコンパイルできることを確かめています
  • MAX7219 を載せた 8×8 LED マトリクスのモジュール(VCC・GND のほか、DIN・CS・CLK の 3 本で制御します)
  • Arduino IDE のライブラリマネージャで入れる「LedControl」

配線はスケッチの LedControl lc(12, 11, 10, 1) に合わせて、DIN を 12 番、CLK を 11 番、CS を 10 番ピンにつなぎます。ほかのピンにつなぐときは、この数字を変えます。

配列を作る

  1. Font to Binary Converter を開き、「かんたん」モードのまま「1 変換したい文字」に ハロー と入力します
  2. 「2 見た目」のフォントで「Misaki Gothic (8x8)」を選びます(ドットサイズも 8 になります)
  3. 「3 出力フォーマット」で「Arduino / C言語」を選び、出力をコピーします
const uint8_t font_data[] PROGMEM = {
  // char: "ハ" (8x8)
  // ..#.#...
  // ..#..#..
  // ..#..#..
  // .#...#..
  // .#....#.
  // .#....#.
  // #.....#.
  // ........
  0x28, 0x24, 0x24, 0x44, 0x42, 0x42, 0x82, 0x00,
  // char: "ロ" (8x8)
  // ........
  // #######.
  // #.....#.
  // #.....#.
  // #.....#.
  // #.....#.
  // #######.
  // ........
  0x00, 0xFE, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00,
  // char: "ー" (8x8)
  // ........
  // ........
  // #.......
  // .######.
  // ........
  // ........
  // ........
  // ........
  0x00, 0x00, 0x80, 0x7E, 0x00, 0x00, 0x00, 0x00
};

1 文字ずつ表示する(setRow)

LedControl の setRow で、1 行ずつ 8 回送ると 1 文字になります。次のスケッチは「ハ」「ロ」「ー」を 0.8 秒ずつ順に表示します。

#include <LedControl.h>

// LedControl(DIN のピン, CLK のピン, CS のピン, つないだ MAX7219 の数)
LedControl lc(12, 11, 10, 1);

// ↓ Font to Binary Converter の出力をそのまま貼る
const uint8_t font_data[] PROGMEM = {
  // char: "ハ" (8x8)
  // ..#.#...
  // ..#..#..
  // ..#..#..
  // .#...#..
  // .#....#.
  // .#....#.
  // #.....#.
  // ........
  0x28, 0x24, 0x24, 0x44, 0x42, 0x42, 0x82, 0x00,
  // char: "ロ" (8x8)
  // ........
  // #######.
  // #.....#.
  // #.....#.
  // #.....#.
  // #.....#.
  // #######.
  // ........
  0x00, 0xFE, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00,
  // char: "ー" (8x8)
  // ........
  // ........
  // #.......
  // .######.
  // ........
  // ........
  // ........
  // ........
  0x00, 0x00, 0x80, 0x7E, 0x00, 0x00, 0x00, 0x00
};

const uint8_t CHAR_COUNT = sizeof(font_data) / 8;  // 8×8 は 1 文字 8 バイト

void setup() {
  lc.shutdown(0, false);  // 省電力モードを解除する
  lc.setIntensity(0, 4);  // 明るさ(0〜15)
  lc.clearDisplay(0);
}

void loop() {
  for (uint8_t c = 0; c < CHAR_COUNT; c++) {
    for (uint8_t row = 0; row < 8; row++) {
      // 1 バイト = 1 行ぶん。bit7 が 0 列目の LED
      lc.setRow(0, row, pgm_read_byte(&font_data[c * 8 + row]));
    }
    delay(800);
  }
}
  • setRow(0, row, value) は、value の bit7 を 0 列目、bit0 を 7 列目の LED に対応させます(LedControl.cpp の setLed が B10000000 >> column でビットを選んでいます)。「Arduino / C言語」の出力は左端のドットが bit7 なので、そのまま渡せます。
  • 配列は PROGMEM(フラッシュ)にあるので、pgm_read_byte で 1 バイトずつ読み出してから渡しています。

向きが合わないとき

モジュールによって、LED の並びと MAX7219 の配線の向きが違います。表示してみて文字の向きがおかしければ、次のように直します。

見え方直し方
左右が逆ツールを「詳細」モードにして、「ビット順」を「LSB first」にして出力し直す
上下が逆スケッチの setRow(0, row, …) を setRow(0, 7 - row, …) にする
90 度回っている「構造」を「ビットパック(列方向)」にして出力し、そのまま setRow に渡す(行と列が入れ替わる)。それでも左右か上下が逆なら、上の 2 つを組み合わせる

文字を流す(スクロール)

8×8 では一度に 1 文字しか出せないので、長い言葉は横に流すと読みやすくなります。流すときは、1 バイトが縦 1 列になる列方向のデータが扱いやすくなります。列を 1 つずつずらして表示するだけで済むからです。

  1. かんたんモードで「Arduino / C言語」を選んだあと、画面の右上で「詳細」に切り替えます
  2. 「構造」を「ビットパック(列方向)」にします(「ビット順」は MSB first のまま)
const uint8_t font_data[] PROGMEM = {
  // char: "ハ" (8x8)
  // ..#.#...
  // ..#..#..
  // ..#..#..
  // .#...#..
  // .#....#.
  // .#....#.
  // #.....#.
  // ........
  0x02, 0x1C, 0xE0, 0x00, 0x80, 0x70, 0x0E, 0x00,
  // char: "ロ" (8x8)
  // ........
  // #######.
  // #.....#.
  // #.....#.
  // #.....#.
  // #.....#.
  // #######.
  // ........
  0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00,
  // char: "ー" (8x8)
  // ........
  // ........
  // #.......
  // .######.
  // ........
  // ........
  // ........
  // ........
  0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00
};

1 文字ぶんの 8 バイトは、左の列から順に並んでいます。各バイトの bit7 が一番上の LED です。このデータを 1 列ずつずらしながら表示するスケッチです。

#include <LedControl.h>

LedControl lc(12, 11, 10, 1);

// ↓ 構造を「ビットパック(列方向)」、ビット順を MSB first にして出力したもの
const uint8_t font_data[] PROGMEM = {
  // char: "ハ" (8x8)
  // ..#.#...
  // ..#..#..
  // ..#..#..
  // .#...#..
  // .#....#.
  // .#....#.
  // #.....#.
  // ........
  0x02, 0x1C, 0xE0, 0x00, 0x80, 0x70, 0x0E, 0x00,
  // char: "ロ" (8x8)
  // ........
  // #######.
  // #.....#.
  // #.....#.
  // #.....#.
  // #.....#.
  // #######.
  // ........
  0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00,
  // char: "ー" (8x8)
  // ........
  // ........
  // #.......
  // .######.
  // ........
  // ........
  // ........
  // ........
  0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00
};

const int16_t COLS = sizeof(font_data);  // 1 バイト = 1 列(bit7 が上端)

void setup() {
  lc.shutdown(0, false);
  lc.setIntensity(0, 4);
  lc.clearDisplay(0);
}

void loop() {
  // offset 列目からの 8 列を表示し、1 列ずつずらす(右から入って左へ流れる)
  for (int16_t offset = -8; offset < COLS; offset++) {
    for (uint8_t col = 0; col < 8; col++) {
      int16_t i = offset + col;
      uint8_t bits = (i >= 0 && i < COLS) ? pgm_read_byte(&font_data[i]) : 0;
      lc.setColumn(0, col, bits);
    }
    delay(80);
  }
}
  • setColumn(0, col, value) は、value の bit7 を 0 行目(一番上)に対応させます(LedControl.cpp の setColumn が value >> (7 - row) で 1 行ずつ取り出しています)。列方向・MSB first の出力は上端が bit7 なので、1 バイトをそのまま 1 列として送れます。
  • 美咲フォントは右端の 1 列が空いているので、文字を詰めて並べて流しても、文字と文字の間が空きます。
  • offset を -8 から始めているのは、何も表示していない状態から、文字が右端から入ってくるようにするためです。
  • setColumn は内部で LED を 1 個ずつ設定するので、setRow より MAX7219 へ送る回数が多くなります(1 列で 8 回)。流す速さは delay で調整します。

モジュールを複数つなぐとき

MAX7219 のモジュールは数珠つなぎにできます。LedControl lc(12, 11, 10, 4) のように最後の引数で台数(LedControl では最大 8 台)を指定し、setRow や setColumn の最初の引数で何台目か(0 から数える)を選びます。流す場合は、4 台なら 32 列ぶんを並べて、同じ考え方で 1 列ずつずらします。

配列の並び方の詳しい説明は「出力の読み方」に、OLED に出す方法は「Arduino と OLED で日本語を表示する」にまとめています。