スクラッチ&スクラップ

簡単なプログラミングや電子工作など。しょうもない工作の記録。

12セグメント カナフォントをハード化する

f:id:macrochelys99:20190326022939j:plain
写真で見ると文字が白とびしちゃうので露出補正で暗くしていますが、実際は明るい部屋でも綺麗に表示されます。

3ヶ月前ぐらいに見かけたとあるツイート



やってみよう


12セグメント カナフォントをハード化する

回路図

f:id:macrochelys99:20190326012048p:plain

当初、8ビットシフトレジスタ 74HC595 を2個使い、各セグメントを2個のLEDで点灯するよう回路図とアートワークを作ったのですが、どうせこれカラー表示したくなるよね、ということで WS2812B に変更。

基板1枚に WS2812B を24個(各セグメント2個×12セグメント)。数珠つなぎになった信号線の両端にコネクタを配置し、基板同士を連結できるようにします。

基板アートワーク

基板外形
f:id:macrochelys99:20190326022346p:plain
基板が安く作れる最大寸法 100mm×100mm に収めます。

A面
f:id:macrochelys99:20190326012639p:plain

B面
f:id:macrochelys99:20190326012801p:plain

部品が15°単位で傾いているのでグリッドをかなり細かくしないと思い通りのところに置けません。

基板入荷

A面
f:id:macrochelys99:20190326015106j:plain

B面
f:id:macrochelys99:20190326015357j:plain

この12セグメントの表示形式に名前は付いていないようなので、基板名は SnowCrystal としました。

部品実装
f:id:macrochelys99:20190326015651j:plain

スペーサー

各セグメントの形状を出すためのスリット兼LEDの光を均一にするスペーサーです。
f:id:macrochelys99:20190326020217p:plain

高さは 10mm, 15mm, 20mm の3種類を試したところ、15mmが良さそうでした。

3Dプリンタで出力。基板に重ねてネジどめ。
f:id:macrochelys99:20190326020419j:plain

Arduino で点灯させる

スケッチの一部

#define NUM_DIG   5     // 接続した文字数
#define NUM_SEG   12    // ディジットあたりのセグメント数
#define NUM_PPS   2     // 各セグメントに使用するWS2812Bの数 Pixels Per Segment
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel pix = Adafruit_NeoPixel(NUM_PPS * NUM_SEG * NUM_DIG, PIN_PIX, NEO_GRB + NEO_KHZ800);


dig番の文字の seg番のセグメントを rgb色 にセット

void set_seg(uint8_t dig, uint8_t seg, uint32_t rgb) {
  for (uint8_t i = 0; i < NUM_PPS; i++) {
    pix.setPixelColor(NUM_PPS * NUM_SEG * dig + NUM_PPS * seg + i, rgb);
  }
}


dig番の文字に patternの文字を rgb色 にセット

void set_dig(uint8_t dig, uint16_t pattern, uint32_t rgb) {
  for (uint8_t seg = 0; seg < NUM_SEG / 2; seg++) {
    set_seg(dig, seg, pattern >> (13 - seg) & 1 ? rgb : 0);
  }

  for (uint8_t seg = NUM_SEG / 2; seg < NUM_SEG; seg++) {
    set_seg(dig, seg, pattern >> (11 - seg) & 1 ? rgb : 0);
  }
}


フォントを作る

const PROGMEM uint16_t font_map[256] = {
  0,    //  0
  0,    //  1
/* 中略 */
  0,    //  46
  0,    //  47
  B000111 << 8 | B100100,    //  48   0
  B000001 << 8 | B100100,    //  49   1
  B101101 << 8 | B010010,    //  50   2
  B101101 << 8 | B011000,    //  51   3
  B000010 << 8 | B100110,    //  52   4
  B101100 << 8 | B101000,    //  53   5
  B101111 << 8 | B001010,    //  54   6
  B000011 << 8 | B100100,    //  55   7
  B101101 << 8 | B011011,    //  56   8
  B111101 << 8 | B010001,    //  57   9
  /* 中略 */
  0,    //  175
  0,    //  176
  B100001 << 8 | B110100,    //  177  ア
  B000000 << 8 | B010110,    //  178  イ
  B011010 << 8 | B110001,    //  179  ウ
  B001100 << 8 | B010101,    //  180  エ
  B000000 << 8 | B110111,    //  181  オ
  B010000 << 8 | B110110,    //  182  カ
  B100001 << 8 | B101110,    //  183  キ
  B100001 << 8 | B010010,    //  184  ク
  B000011 << 8 | B001101,    //  185  ケ
  B000100 << 8 | B000101,    //  186  コ
  B000010 << 8 | B110110,    //  187  サ
  B101100 << 8 | B000001,    //  188  シ
  B000001 << 8 | B101100,    //  189  ス
  B001000 << 8 | B110110,    //  190  セ
  B011000 << 8 | B000001,    //  191  ソ
  0,    //  192
  0,    //  193
 /* 中略 */
  0,    //  254
  0,    //  255
};


1バイトカナ文字(半角カナ)を Serial.println() すると戻りは3バイトなので、下位1バイトを使って font_mapの配列からパターンを取り出す

uint16_t font(byte ascii) {
  return pgm_read_word(&font_map[ascii]);
}

byte code = 'ア' としたときに、「ア」の下位1バイトだけ取り出して変数 code に代入してくれれば良いのですが、narrowing conversion のエラーが出るPCとコンパイルが通るPCがあります。キャスト面倒だから通して欲しいんだけど何が違うんだろう?

紙を被せて完成

2mmの白いアクリルでは、滲んでピンボケみたいになってしまいました。
f:id:macrochelys99:20190326023920j:plain

アクリルをコピー用紙に変えたらシャキッと表示できました。
f:id:macrochelys99:20190326024057j:plain

まとめ

while 文の無限ループが含まれているのでスケッチの全文公開はやめとこ(笑)

フォントのパターンは、こちらのブログで紹介されているものを再現しています。
12セグメントカタカナフォント|ニートが頑張るブログ