フォントデータで任意の文字をスクロール表示させる 

 

 私キャッスルがArduino UNO R4 WiFiを買ってすぐに作ったプログラムは、文字をスクロール表示させるというものであった。

 

 

 

まぁこれにはスペルミスというオチがあったわけだが、当時としてはなかなか頑張ったのではないかと思っている。

 

 しかし、UNO R4のライブラリもバージョンアップして、公式に文字列をスクロールさせることができるようになった。

めでたしめでたし。

 

 

 ・・・と行きたかったが。

なんか、ちょっと、このフォント読みにくくね?

2種類用意されてるのはいいのだが、大きいサイズでも縦が7ドット。

ただでさえ狭い画面なんだから、縦8ドットフルに使えばいいのに、と思うのは俺だけか?

それに、固定長フォントなのでMとかWとか文字がつぶれてしまって判別しにくい。

英語ネイティブな国の人はこれでも問題なく読めるのだろうか。

 

 少なくとも私キャッスルはこのフォントはあまり好きになれない。

というわけで、フォントデータを自作してみた。 基本的には4x8ドットなのだが、読みやすくなるよう可変幅にしてみた。

ASCIIコードの0x20(スペース)から0x7e(チルダ)までをデータにし、それ以外は省いた。

 

 

 表示させてみると、何かバランスがよくない。 たぶん小文字の表示がよくない。

バランスのよい表示にするなら、小文字を使わないで大文字だけにすると良さそうだ。

なるほど、公式が用意したフォントはバランスも考えられて作られてるんだな。 デザインとはなかなかに奥深い。

 

 とりあえず自作フォントを使った文字列をスクロール表示させてみた。

大文字と小文字混在はあまりオススメできない。 大文字と記号だけなら、そこそこ迫力ある表現になるかと。 あと、あまり長い文字列にすると、変数の容量を超えてしまい、誤動作すると思われる。

ソースコードがやたら長くなるので、フォントデータは別ファイルを用意してインクルードした方がよさそうだな。

/*
 * UNO4 WiFi 任意のメッセージテキストのスクロール表示
 * 独自フォントの使用
*/
#include "Arduino_LED_Matrix.h"
#include "FspTimer.h"

//LED matrix用のフォントを独自に作成
static unsigned char F4x8asciiP[][6] PROGMEM = {
  { 4, 0x00, 0x00, 0x00, 0x00 },        // Space
  { 2, 0xfb, 0x00 },                    // !
  { 3, 0xc0, 0x00, 0xc0 },              // "
  { 5, 0x24, 0xff, 0x24, 0xff, 0x24 },  // #
  { 5, 0x22, 0x52, 0xff, 0x52, 0x4c },  // $
  { 5, 0xc1, 0xc6, 0x18, 0x63, 0x83 },  // %
  { 5, 0x76, 0x89, 0x95, 0x62, 0x0d },  // &
  { 2, 0xc0, 0x00 },                    // '
  { 3, 0x18, 0x66, 0x81 },              // (
  { 3, 0x81, 0x66, 0x18 },              // )
  { 5, 0x42, 0x24, 0xff, 0x24, 0x42 },  // *
  { 5, 0x10, 0x10, 0x7c, 0x10, 0x10 },  // +
  { 2, 0x0d, 0x0e },                    // ,
  { 4, 0x08, 0x08, 0x08, 0x08 },        // -
  { 2, 0x03, 0x03 },                    // .
  { 4, 0x03, 0x0c, 0x30, 0xc0 },        // /

  { 4, 0x7e, 0x8d, 0xb1, 0x7e},         // 0
  { 3, 0x41, 0xff, 0x01},               // 1
  { 4, 0x67, 0x89, 0x91, 0x61},         // 2
  { 4, 0x46, 0x91, 0x91, 0x6e},         // 3
  { 4, 0x38, 0x48, 0xff, 0x08},         // 4
  { 4, 0xf2, 0x91, 0x91, 0x8e},         // 5
  { 4, 0x7e, 0x91, 0x91, 0x4e},         // 6
  { 4, 0xc0, 0x87, 0x98, 0xe0},         // 7
  { 4, 0x6e, 0x91, 0x91, 0x6e},         // 8
  { 4, 0x72, 0x89, 0x89, 0x7e},         // 9

  { 2, 0x36, 0x36 },                    // :
  { 2, 0x6d, 0x6e },                    // ;
  { 4, 0x10, 0x28, 0x44, 0x82 },        // <
  { 4, 0x24, 0x24, 0x24, 0x24 },        // =
  { 4, 0x82, 0x44, 0x28, 0x10 },        // >
  { 4, 0x40, 0x8d, 0x90, 0x60 },        // ?
  { 5, 0x7e, 0x99, 0xa5, 0x99, 0xea },  // @

  { 4, 0x7f, 0x88, 0x88, 0x7f },        // A
  { 4, 0xff, 0x91, 0x91, 0x6e },        // B
  { 4, 0x7e, 0x81, 0x81, 0x42 },        // C
  { 4, 0xff, 0x81, 0x81, 0x7e},         // D
  { 4, 0xff, 0x91, 0x91, 0x91},         // E
  { 4, 0xff, 0x90, 0x90, 0x90},         // F
  { 4, 0x7e, 0x81, 0x89, 0x4e },        // G
  { 4, 0xff, 0x10, 0x10, 0xff},         // H
  { 3, 0x81, 0xff, 0x81},               // I
  { 4, 0x0e, 0x01, 0x01, 0xfe },        // J
  { 4, 0xff, 0x18, 0x66, 0x81 },        // K
  { 4, 0xff, 0x01, 0x01, 0x01 },        // L
  { 5, 0xff, 0x40, 0x30, 0x40, 0xff},   // M
  { 5, 0xff, 0x60, 0x18, 0x06, 0xff},   // N
  { 4, 0x7e, 0x81, 0x81, 0x7e},         // O
  { 4, 0xff, 0x90, 0x90, 0x60},         // P
  { 4, 0x7e, 0x85, 0x82, 0x7d },        // Q
  { 4, 0xff, 0x98, 0x94, 0x63},         // R
  { 4, 0x62, 0x91, 0x91, 0x4e},         // S
  { 5, 0x80, 0x80, 0xff, 0x80, 0x80},   // T
  { 4, 0xfe, 0x01, 0x01, 0xfe},         // U
  { 5, 0xe0, 0x1c, 0x03, 0x1c, 0xe0 },  // V
  { 5, 0xf8, 0x07, 0x38, 0x07, 0xf8},   // W
  { 5, 0xc3, 0x2c, 0x10, 0x2c, 0xc3 },  // X
  { 5, 0xc0, 0x30, 0x0f, 0x30, 0xc0 },  // Y
  { 4, 0x83, 0x8d, 0xb1, 0xc1 },        // Z

  { 3, 0xff, 0x81, 0x81 },              // [
  { 5, 0xca, 0x3a, 0x0f, 0x3a, 0xca },  // Yen
  { 3, 0x81, 0x81, 0xff },              // ]
  { 3, 0x40, 0x80, 0x40 },              // ^
  { 4, 0x01, 0x01, 0x01, 0x01 },        // _
  { 2, 0x80, 0x40 },                    // `

  { 3, 0x2e, 0x2a, 0x3e },              // a
  { 3, 0xfc, 0x12, 0x0e },              // b
  { 3, 0x1c, 0x22, 0x14 },              // c
  { 3, 0x0c, 0x12, 0xfc },              // d
  { 3, 0x1c, 0x2a, 0x1a },              // e
  { 3, 0x10, 0x7e, 0x90 },              // f
  { 3, 0x11, 0x29, 0x3e },              // g
  { 3, 0xfe, 0x10, 0x1e },              // h
  { 2, 0x5e, 0x00 },                    // i
  { 3, 0x02, 0x01, 0x5e },              // j
  { 3, 0xfe, 0x08, 0x36 },              // k
  { 3, 0x40, 0x7e, 0x02 },              // l
  { 5, 0x1e, 0x20, 0x1e, 0x20, 0x1e },  // m
  { 3, 0x1e, 0x20, 0x1e },              // n
  { 3, 0x1c, 0x22, 0x1c },              // o
  { 3, 0x1f, 0x28, 0x10 },              // p
  { 3, 0x10, 0x28, 0x1f },              // q
  { 3, 0x1e, 0x20, 0x20 },              // r
  { 3, 0x12, 0x2a, 0x24 },              // s
  { 3, 0x10, 0x3e, 0x10 },              // t
  { 3, 0x3e, 0x02, 0x3e },              // u
  { 3, 0x3c, 0x02, 0x3c },              // v
  { 5, 0x3c, 0x02, 0x0c, 0x02, 0x3c },  // w
  { 3, 0x36, 0x08, 0x36 },              // x
  { 3, 0x31, 0x0a, 0x3c },              // y
  { 3, 0x26, 0x2a, 0x32 },              // z

  { 3, 0x10, 0xfe, 0x82 },              // {
  { 2, 0xe7, 0x00 },                    // |
  { 3, 0x82, 0xfe, 0x10 },              // }
  { 4, 0x40, 0x80, 0x40, 0x80 }         // ~
};

//スクロール時間
#define SCROLL_TIME 75   //ミリ秒

unsigned char show_message[256];
unsigned char show_length;
unsigned long tm = 0;
int idx = 0;
int ic1 = 0;

static FspTimer fsp_timer;

void setup() {
  Serial.begin(9600);

  //タイマー割り込みの設定
  uint8_t timer_type;
  int8_t timer_ch = FspTimer::get_available_timer(timer_type);
  if (timer_ch < 0) {
    Serial.println("get_available_timer() failed.");
    while(1);
  }
  fsp_timer.begin(TIMER_MODE_PERIODIC, timer_type, timer_ch, 10000.0, 50.0, timer_callback, nullptr);
  fsp_timer.setup_overflow_irq();
  fsp_timer.open();

  show_length = make_text("Hello World!!");  //文字をLEDマトリックスに変換
  idx = 0;  //メッセージ参照場所クリア
  fsp_timer.start();

}

void loop() {

}

int make_text(char *str){
  int i_font, i_str;  //フォントのインデックスと文字列のインデックス
  unsigned char i_show = 12;  //sho_messageのインデックス

  Serial.println(str);
  memset(show_message, 0, sizeof(show_message));  //show_messageクリア

  for(i_str = 0; *(str + i_str) != '\0'; i_str++){  //文字数だけ繰り返し
    memcpy(show_message + i_show, &F4x8asciiP[str[i_str] - 0x20][1], 
                                   F4x8asciiP[str[i_str] - 0x20][0]);
    i_show += F4x8asciiP[str[i_str] - 0x20][0] + 1;
  }
  return i_show;
}

void timer_callback(timer_callback_args_t *arg)
{
  //スクロール時間が経過したらスライドさせる。末端に到達したら始めに戻る
  if(tm + SCROLL_TIME <= millis()) {
    if (idx < show_length)
      idx++;
    else{
      idx = 0;
    }

    //経過時間を再計測
    tm = millis();
  }

  //12x8LED View
  turnLed(ic1, show_message[idx + ic1 % 12] >> (7 - ic1 / 12) & 0x01);
  ic1++;
  if(ic1 > 96)
    ic1 = 0;
}