ESP8266+MAX7219でDotMatrix LEDを使ってみる

日本語の表示


前回、ESP8266+MAX7219で8x8のドットマトリクスLEDに英 数 字の表示方法を紹介しました。
そこで、今回はSPIFFSに漢字フォントを格納して、日本語の表示を紹介します。

使用するマトリクスは10x10の製品ですが、こちらで公開されている 8ドット の美咲フォント(FONTX2形式)を使いたいので、
上下左右の端のLEDは使わずに、8x8ドットのマトリクスとして利用します。

配線、MAX72197のライブラリ、フォントの反転関数は前回と同じです。
また、フォントドライバーとして、こちらのライ ブラリを利用させていただきました。

最初にSPIFFS ファイルシステムアップローダーを使ってフォントファイルをSPIFFS領域にアップロードします。
使用するフォントファイルは、FONTX2形式の「misaki_fontx_2012-06-03.zip」に含まれているファイルです。
SPIFFS ファイルシステムアップローダーの使い方はこちらに 詳しく紹介されています。
今回、アップロードするフォントファイルは、以下の3つのファイルです。
[1] /4X8.FNT             2065
[2] /MISAKI.FNT         56082
[3] /MISAKIMN.FNT        56082

WeMosのスケッチは以下の通りです。
使用するフォントファイルはお好みで変更してください。
また、文字ごとに表示時間を変更できるようにしています。
デフォルトでは1文字の表示時間は300ミリ秒ですが、文字の前に0x00XXを入れると、XX*10ミリ秒(最大2550ミリ秒)の表示となり ます。
/*
  MAX7219経由で8x8 Dot Matrix LEDに日本語を表示する
*/

#include <FS.h>
#include <Fontx.h> // https://github.com/h-nari/Fontx
#include <FsFontx.h> // https://github.com/h-nari/Fontx
#include "LedControl.h" // https://github.com/sej7278/LedControl

FsFontx fx("/MISAKIMN.FNT","/4X8.FNT");
//FsFontx fx("/MISAKI.FNT","/4X8.FNT");

#define INTERVAL 300 // You can change

/*
 Now we need a LedControl to work with.
 ***** These pin numbers will probably not work with your hardware *****
 GPIO16(D0) is connected to the DataIn
 GPIO12(D6) is connected to the CLK
 GPIO14(D5) is connected to LOAD
 We have only a single MAX72XX.
 */
//LedControl lc=LedControl(12,11,10,1);
LedControl lc=LedControl(16,12,14,1);

static unsigned long lastMillis;
static unsigned long timeOut;
// 0x00xx : xxは表示時間(xx*10ミリ秒 最大2550ミリ秒)
uint16_t str[] = \
  {u'こ',u'ん',u'に',u'ち',0x0096,u'は',u'今',u'日',u'は',u'6',u'月',u'4',u'日',u'で ',0x00FF,u'す'};
int stlen;

//
// http://nuneno.cocolog-nifty.com/blog/2016/07/48x8led-0f0f.html から借用しました
//
// 任意サイズビットマップのドットON/OFF反転
//  bmp: スクロール対象バッファ
//  w:   バッファの幅(ドット)
//  h:   バッファの高さ(ドット)
void revBitmap(uint8_t *bmp, uint16_t w, uint16_t h) {
  uint16_t bl = (w+7)>>3;           // 横バイト数
  uint16_t addr;                    // データアドレス
  uint8_t d;
  addr=0;
  for (uint8_t i=0; i <h; i++) {
    for (uint8_t j=0; j <bl; j++) {
      d = ~bmp[addr+j];    
      if (j+1 == bl && (w%8)!=0) {
        d &= 0xff<<(8-(w%8));
      }
      bmp[addr+j]=d;
    }
    addr+=bl;
  }
}

uint8_t bitConv(uint8_t val) {
  uint8_t mask = 1;
  uint8_t rval = 0;
  uint8_t bits[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
 
  for(int i=0;i<8;i++) {
    if (val & mask) rval = rval + bits[i];
    mask=mask << 1;
  }
  return rval;
}


void setup() {
  Serial.begin(9600);
  if(!SPIFFS.begin())
    Serial.println("SPIFFS failed.");
  else {
    Dir dir = SPIFFS.openDir("/");
    int cnt = 0;
    while(dir.next()){
      File f = dir.openFile("r");
      Serial.printf("[%d] %-12s %12u\n",++cnt,f.name(), f.size());
      f.close();
    }
    Serial.printf("%d files found.\n",cnt);
  }

  const uint8_t *p;
  uint8_t w,h;
  stlen = sizeof(str)/sizeof(str[0]);
  Serial.println("stlen=" + String(stlen));

//  for(int i=0;i<sizeof(str)/sizeof(str[0]);i++){
  for(int i=0;i<stlen;i++){
    if((str[i] & 0xFF00) == 0x0000) continue;
    if(!fx.getGlyph(str[i], &p, &w, &h)){
      Serial.printf("getGlyph failed. code:%x\n",str[i]);
    } else {
      for(int y=0; y<h; y++){
        Serial.printf("%02d: ",y);
        for(int x=0; x<w; x++){
          Serial.print(p[x/8] & (0x80 >> (x % 8)) ? '*' : '.');
        }
        Serial.println();
        p += (w + 7)/8;
      }
    }
  }

 /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);
  lastMillis = millis();
  timeOut = millis() + INTERVAL;
}

void loop() {
  uint8_t bitmap[8];
  static int pos = 0;
  uint8_t buf[2];
  const uint8_t *p;
  uint8_t w,h;

  if(!fx.getGlyph(str[pos], &p, &w, &h)){
    Serial.printf("getGlyph failed. code:%x\n",str[pos]);
  } else {
    memcpy(bitmap,p,8);
#if 0
    for(int i=0;i<8;i++) {
      bitmap[i] = bitConv(*p);
      p++;
    }
#endif
//    revBitmap(bitmap, 8, 8); //ビットマップの反転

    //1行単位に表示
    int col = 7;
    for(int i=0;i<8;i++) {
      lc.setColumn(0,col--,bitmap[i]);
    }
  }

  //次の文字を処理するかどうかの判定
  unsigned long now = millis();
  if (now < lastMillis) timeOut = now + INTERVAL;
  if (now > timeOut) {
    pos++;
    if (pos == stlen) pos = 0;
    int interval = INTERVAL;
    if((str[pos] & 0xFF00) == 0x0000) {
      interval = (str[pos] & 0x00FF) * 10;
      pos++;
    }

//    Serial.print("pos=" + String(pos));
//    Serial.print(" interval=" + String(interval));
//    Serial.println();
    lastMillis = now;
//    timeOut = now + INTERVAL;
    timeOut = now + interval;
  }
}

74HC595と比べるとこんな感じで表示されます。(右:MAX7219 左:74HC595)
右側基盤には抵抗が2つ付いていますが、このピンは使っていません。








続く...