さくらのジャンク箱ロゴ

Sakura87がお届けするPCや電子工作と写真のブログ @16周年

Arduino Unoで電光掲示板をつくる

この記事は4年ほど前に投稿されました。内容が古くなっている可能性がありますので更新日時にご注意ください。

IMG_7225_20160224

マイコンを使って何かを表示する場合に、一番多用されるのは安価に入手できるLEDや7セグLED、キャラクタ液晶といったものだと思いますが。今回はそのLEDのうちドットマトリクスLEDというものを制御して電光掲示板を作ってみたいと思います。

はじめに

まずドットマトリクスLEDとは何かというと、1つのユニットに複数のLEDランプを二次元的に規則正しく並べたものです。例えば今回使用しているLEDユニットでは縦8×横8個、合計で64個のLEDランプが使われています。これを制御することで文字やイラストといったものが表示できるようになります。

用意するもの

  • 前回作成したドットマトリクスLED表示器
    ただし、これは長辺を一度に制御するように設計しているので、今回の使用方法だと輝度にばらつきが出ます。これを出ないようにするには、前回の図面では各ユニットのカソードをまとめているのですが、これをアノードでまとめ、抵抗をつけている部分にシンクドライバタイプのトランジスタアレイを追加し、アノード側に抵抗を付けシフトレジスタとつなぐ(部品の仕様位置をシフトレジスタ以外真逆にする)ことで置き換え可能だと思われます。
  • FONTX形式の8×8ドットフォント
    今回は恵梨沙フォントのX-Windows版を使い、前回FONTXファイルを扱った時に利用した変換ソフトでFONTXファイルに変換しました。今回美咲から変更した理由は。美咲は画面での閲覧に最適化されており、フォントは7×7以内に収まっていますが。今回は別に8ドットフルで使って構わないため。今までたくさん使用してきた美咲フォントは最初からFONTXファイルが用意されているので、勿論そちらを利用しても問題無いです。

制御方法

ドットマトリクスLEDは、縦横のLEDの縦1列のアノード・横1行のカソード若しくはその逆を一つにまとめたものです。よって制御方法は基本的にはダイナミック点灯方式の7セグLED制御と変わりません。単純に制御した結果が数字の形ではなく1行で表示されるだけです。

今回はビットを回転させるのが面倒くさいので……電光掲示板っぽく文字を流すので縦長で使います。

文字パターンの作成

Raspberry Piで制御する場合は、色々とやりようがありますが。Arduinoでは制約が多いのと、できれば表示時はSDカード無しのドットマトリクス単体で使えるようにしたいため、1つのIOピンを使用して電光掲示板モードにするのか、それとも表示する文字を入力するモードにするのかを切り替えられるようにします。

そこで今回は

  1. ボタンを押しながら起動・リセットを行うと記録モード
  2. 文字転送を待機する
  3. 文字が入力されたら文字コードを格納
    この時半角英数字の文字コードなら全角に変換
  4. 転送した文字コードよりフォントから文字パターンを作成
  5. 作成したパターンを内蔵EEPROMに格納する
  6. リセットされるのを待つ

という手順にしたいと思います。

文字パターンを作成するのは前回利用した関数を使います。全角半角変換用関数も作りますが。ShiftJISは全角記号が散乱しており、変換コードが長くなってしまうので。今回はライブラリとして抜き出しました。

このライブラリには前回作成したFONTX形式のフォントファイルを読み込む関数と、半角→全角変換の関数の2つが格納されています。使用方法は当ライブラリとSD・SPIのライブラリをインクルードしてSDカードを読み込んでやれば使えるようになります。(詳しいことはReadMeファイルに書いてありますのでそちらを読んでください。)

作成したパターンの格納

作成したドットマトリクスパターンの格納法ですが。考えられる方法としては3つ程度あると思います。

ひとつはSDカードなどにファイルとして置く方法。2つ目は内外のEEPROMを利用してデータを格納する方法。3つ目は配列に格納する方法です。

SDカードにファイルを置くとPCからでも操作でき便利ですが。今回は文字を設定してしまったあとはSDカードが無くても動作するようにしたいためこの方法は見送りました。

また、配列に格納する方法は電源を切ると初期化されるので。これも今回の趣旨とは違うものなのでやめました。

最後に残ったのはEEPROMに格納する方法ですが。Arduino Unoに使われているAVRマイコンには1024バイトのEEPROMが内蔵されていますので。今回はこれを使うことにします。1024バイトあれば今回利用する8×8ピクセルのフォントデータで127文字(先頭1バイトを文字数格納として利用するため)、16×16のフォントデータで31文字分のデータが格納できます。(ただし今回はシリアル通信のバッファサイズが64バイトなので32文字を上限として作成します。)

しかし、動作プログラム自体が900バイト近くメモリを使っているので実際は512バイト(8×8 64文字 16×16 16文字)程度が限界でしょう。SRAMを増設するという手もありますが。今回はハードウェアが8×16ドットなので内蔵メモリだけで何とかさせます。

というか、本格的な電光掲示板を作るのならArduinoならM0みたいなARM系コアのメモリサイズの大きなものを使うか。それこそRaspberry Piを使ったほうが絶対にいいと思います。

表示機構

実際にパターンを読み込んで表示させる部分ですが。

EEPROMに格納されたデータを一旦RAMへ読み込んでしまい、それをSPI転送でシフトレジスタに転送してやろうと思います。表示データは一定回数書き換え後に配列を1つずらすことで文字を流します。なお、綺麗に流れているように見せるためには、前後に空白が必要になるので実際は表示文字数+4文字分の変数を確保するようにします。

回路説明

まず表示器を作りますが。
前回と全く同じものを作っても一応は使うことが出来ますので、前回の回路図を載せておきます。

dmatrix

ただし、これだと表示ドット数によって明るさが変わってしまいますので前述のとおり、LED GND切り替え部分と桁切り替えの部分を入れ替えたほうがいいかもしれません。その場合の回路は以下のとおりになると思いますが。この回路図の動作は未検証なので作成する場合は十分検証してから使ってください。

dmatrix2

なお、接続についてはSPIで接続するのでSDカードと共通のところに接続します。(SS用のIOだけ分けてください。)

接続位置については既に何度も書いてあるので今回は載せません。
わからない場合は以下の記事を参考にしてください。使用しているものは出力先が液晶モジュールになっている以外は同じです。

なお、モード切り替え用のswitchは以下の回路図のような回路になります。

AruINPUT

心配な人はIOピンとスイッチの間にも抵抗を入れてください。無くても動きます。
スイッチとGNDの間にある抵抗の抵抗値は10kΩ前後で好きなものでいいです。

コーディング

今回は多くを説明すると長くなりますので。要所だけ説明をして全体のコードを貼り付けておきます。

まずシフトレジスタへデータを転送する部分です。

////// シフトレジスタ側の転送命令 //////

// long型1つをchar型4つに切り離して転送する命令。
void data_tr_long(int tr_byte, unsigned long data) {
  unsigned char d[tr_byte];
  int i = tr_byte, r = 0;
  while (i--) d[r++] = (data >> (i * 8)) & 0xff;
  data_tr(tr_byte, d);
}

// データの転送用命令
// 配列を後ろから転送する
void data_tr(int tr_byte, unsigned char *data) {

  digitalWrite(SPI_SSel, 0);
  while (tr_byte--) SPI.transfer(*(data + tr_byte));
  digitalWrite(SPI_SSel, 1);
}

今回は3バイトで制御できますので転送データをunsigned longで扱っています。
これはRaspberry Piのコードを流用したことによるもので。ArduinoのSPIライブラリは一度に1バイトごとの転送にしか対応していないので、unsigned longだと一度に転送することが出来ません。

そのために一度unsigned longの値をunsigned charに切り分けて転送しています。

次にシリアル通信の受信データを取り込みます。

  // データ受信待ち
  while (!Serial.available()) {

    // 受信待機中は先頭行のドットマトリクス1ドットを点滅させてお知らせする
    data_tr_long(3, 0x010001);
    delay(250);
    data_tr_long(3, 0x010000);
    delay(250);
  };  
  // 受信データを取り込む
  while (Serial.available()) {
    unsigned int zen = 0;
    r_kanji[r] = Serial.read();
    if (!(r & 1) && r_kanji[r] <= 0x80) {
      zen = AsciiZen(r_kanji[r]);

      r_kanji[r] = zen >> 8;
      r_kanji[++r]   = zen &  0xFF;

    }

まずデータの到着を待ちます。

到着を待っている間は、そのことを示すためにドットマトリクス表示器の端1ドットを点滅させておきます。

データの到着後はデータを配列に入れ込みますが。受け取ったデータの受信バイト数が偶数でなく、数値が0x80以上であれば2バイト文字だと判断し次のデータを取り込みに行きます。もしそれ以外の数値であれば半角→全角変換に通して全角の文字コードを取得した後、配列に入れ込み、次のデータを受信します。

EEPROMの操作

EEPROMを操作するにはArduinoの標準ライブラリを使う方法もありますが。
実はArduino標準ライブラリも単純にAVRの標準ライブラリに投げているだけなので、ここではAVRの標準ライブラリを使いたいと思います。

  • #include <avr/eeprom.h>

標準ライブラリのEEPROMライブラリはこれで呼び出せます。

EEPROMを書き込む処理は以下の2行で行うことが出来ます。

  // EEPROM処理待ち
  eeprom_busy_wait();

  // EEPROMに書き込み
  eeprom_write_byte((uint8_t *)ROMアドレス, (uint8_t)書き込みデータ);

eeprom_busy_waitはEEPROMが書き込み可能になるまでループする関数で。
EEPROMが書き込み可能になったら抜けます。

eeprom_write_byteが書き込み用関数で。1番目の引数に書き込み対象のROMアドレス。
2番目に書き込む1バイトのデータを指定することで書き込みが行われます。

ちなみにこの書き込み命令はbyteの部分をword・dwordと変えることで2バイトごと、4バイトごとの書き込みができるようです。また、floatにすると実数値も書き込めるようです。

読み込みの場合は以下のとおりです。

  eeprom_busy_wait();

  unsigned int data = eeprom_read_byte(ROMアドレス(uint8_t *));

1行目は書き込みと同じです。

eeprom_read_byteが読み込み関数で。()の中にアドレスを指定することて指定されたアドレスのデータが読み込まれます。これもbyteの部分を変更することで2バイトごと、4バイトごとと読み込むことが可能です。

なお、今回はloop関数は使用しません。表示用と書き込み用で関数を分けて、setup関数の中で分岐させてループします。

表示部のループ

  // 表示用ループ
  // 今回は縦1列を書き換えて行く。
  while (1) {
    data_tr_long(3, ((unsigned long)matrix_pat[(i % DM_LEN) + po] << DM_LEN) | ((unsigned long)1 << (i % DM_LEN)));
    delayMicroseconds(MAT_LDL);
    if (++i > (DM_LEN * MAT_DEL)) i = 0;
    if (i == 0) po++;
    if (po >= r) po = 0;

  }

表示用のループはこのようにwhile(1)で無限ループを作り、unsigned long の値に表示パターンと桁切り替えビットをくっつけて転送しています。文字を流す動作については、文字を表示させるためのループカウンタである変数 i の数値を監視し、変数 i が規定の表示回数になって0に戻ったらオフセット用の変数 po をインクリメントします。

poの値が変数分を超えたらpoも0に戻します。

この数値を元に転送する配列番号を決定しています。

全体的な動作(書き込み)
  1. シリアルからデータが転送されてくるのを待つ
  2. 受信したデータを読み込む
  3. 受信データを元に漢字パターンをフォントファイルから抜き出す
  4. 全部抜き出し終えたら配列をEEPROMに書き込む
  5. 書き込み完了を知らせてリセットされるまで待つ
全体的な動作(電光掲示板表示時)

電光掲示板の場合は、EEPROMに格納されているデータを配列に読み出し、それを上のループを使って表示しているだけです。特に特別な動作はしていません。

動作結果

以下にある全体コードを実行すると以下の様な感じになるはずです。

IMG_7225_20160224

動画

終わりに

というわけでArduino Unoで電光掲示板を作ってみました。

と言ってもハードウェアはRaspberry Pi2向けに作ったものの流用ですけどね。
ArduinoやRaspberry Pi等のマイコンボードを使って何か物を作る場合、程よく複雑な回路が必要で、かつプログラムも比較的大きくなる電光掲示板というものはぜひ作っておきたいアイテムだと思います。
しかも自由な文字を表示することが出来、本格的に作れば実用性も高いです。

今回は実験ということで8×16の小さい電光掲示板だったので余り実用性は高くありませんが。
16×32、16×48くらいの大きさのドットマトリックス表示器を作れば中々実用性が高いものが出来ると思います。

なお、写真ではブレッドボードにLEDが刺さっていますが。これは製作時に動作確認に使用したLEDですので今回は使いません。

なお、今回はunsigned long型に入れ込みましたが。unsigned char型で同様のビットシフト処理を行う場合は、以下のようにすればいいらしいです。

int i=32;
while(i--){

  a[0] =( 1 << i - 23) >>1;
  a[1] =( 1 << i - 15) >>1;
  a[2] =( 1 << i -  7) >>1;
  a[3] =( 1 << i -  0) ;

}

これはたとえばunsigned longと同じ4バイト32bit分ビットシフトで桁を切り替える場合のコードですが。
最初の桁はそのまま1をビットシフトしていけばよく、2番目以降は i からbit数-(8*バイト数)-1をした数引きます。

例えば32bitで右から2バイト目だった場合はa[2]=( 1 << i –  7) >>1;となります。
右から2バイト目以降、最後に1bitシフトしているものは、これを行わないと2バイト目以降に常に1が残ってしまうからです。

ただし、これは例えば桁数が56bit以上(先頭をパターンとした場合のunsigned long longの最大値)になってしまった場合にこうすれば同じことが出来ますよ。というものであり。特に桁数が4バイト(32bit)以内に収まるのであれば、今回のように、最初はunsigned long変数を作ってビットシフトを行い、その後8ビット毎に分割して配列に押しこむ方法のほうがめんどくさくないと思います。

全体のソースコード

#include <avr/eeprom.h> // 内蔵EEPROMを使うライブラリ
#include <SD.h>
#include <SPI.h>
#include "fontx.h"      // 漢字パターン変換はヘッダファイルに移動しました。

#define SD_SELECT 4

///// ドットマトリックスLED側の設定 /////

// シフトレジスタピンの設定
#define SPI_SSel 8


// 流れる文字の余白
#define DM_MARG 2

// 長辺のドット数
#define DM_LEN 16

// 1行あたりの表示ディレイ(マイクロ秒)
// 大きいほど明るくなる
#define MAT_LDL 10

// 1ドットずらすまでの表示回数(回)
// 文字が流れる速さを決定する
// (MAT_LDL × DM_LEN)× 回数
#define MAT_DEL 60

/***** フレームレートについて *****

 長辺のドット数    16ドット
 1行あたりのディレイ 100μs
 表示回数             60回

とした場合。

 100×16 = 1600 μs

8x16pxのLED表示器を1回表示してしまうまでに
1600μsかかり。これを60回なので

1600×60=96000μs

つまり合計で96000μs=9.6msのディレイが
発生し104fps程度となる。
※実際は書き換え自体に時間がかかるので
 104fpsよりは少なくなる。

***********************************/

///// 全体で使う設定 /////

// ROM書き込みor表示切り替え用ピン
#define SEL_PIN 2

// ROM書き込みモード表示用ピン
#define WRL_PIN 7

// 最大表示文字数 シリアル通信が64バイトのバッファなので32文字まで
#define MAX_LEN 32

///// EEPROMの構造 /////
// ※初期設定の場合
// 0x0000  表示文字数格納(これを8倍する。)
// 0x0001
//  |   表示パターン格納
//  

// パターン格納用変数の設定
unsigned char matrix_pat[(MAX_LEN * 9) + (DM_MARG << 4)] = {0,};



void setup() {


  // モード切替に使うピンの初期化
  pinMode(SEL_PIN, INPUT);

  // シフトレジスタに使用するピンの定義
  pinMode(SPI_SSel, OUTPUT);

  digitalWrite(WRL_PIN, 0);
  SPI.begin();
  // ピンの値によりモード切替
  // L=電光掲示板モード
  // H=ROM書き換えモード
  switch (digitalRead(SEL_PIN)) {

    case 1:

      Serial_read();
      break;

    case 0:

      matrix();
      break;

  }

}


////// ロム書き換えモード //////

void Serial_read() {
  unsigned char r = 0,  r_kanji[MAX_LEN * 2], pat[8];
  int i, p;
  data_tr_long(3, 0x000000);
  // SerialPortの初期化
  Serial.begin(9600);

  while (!Serial);

  // SDカードの初期化
  if (!SD.begin(SD_SELECT)) {
    Serial.println(F("SD card error !"));
    return;
  }


  Serial.print(F("Ready! Max ")); Serial.print(MAX_LEN, DEC); Serial.println(F(" characters."));


  // データ受信待ち
  while (!Serial.available()) {

    // 受信待機中は先頭行のドットマトリクス1ドットを点滅させてお知らせする
    data_tr_long(3, 0x010001);
    delay(250);
    data_tr_long(3, 0x010000);
    delay(250);
  };
  // 受信データを取り込む
  while (Serial.available()) {
    unsigned int zen = 0;
    r_kanji[r] = Serial.read();
    if (!(r & 1) && r_kanji[r] <= 0x80) {
      zen = AsciiZen(r_kanji[r]);

      r_kanji[r] = zen >> 8;
      r_kanji[++r]   = zen &  0xFF;

    }

    r++;
    //char x[10];sprintf(x,"%02d 0x%04X 0x%02X %02X",r>>1 ,zen | (r_kanji[r - 2]<<8 | r_kanji[r - 1]),r_kanji[r - 2],r_kanji[r - 1]);if(~r&1)Serial.println(x);
    //  ↑デバッグ用 文字コード表示したいときはコメント外す。

  }
  // 2バイト文字なので2で割る
  r /= 2; i = 0;

  Serial.print(F("Receive ")); Serial.print(r, DEC); Serial.println(F(" characters."));

  // 最大文字数より大きい場合は最大文字数でカットする
  if (MAX_LEN <= r) r = MAX_LEN;

  // 文字パターン取得ループ
  Serial.println(F("Kanji pattern Reading.... "));

  while (i < r) {

    // 文字コードを1文字ずつ取り出す
    unsigned int kanji = (unsigned int)r_kanji[(i << 1)] << 8 | r_kanji[(i << 1) + 1];

    // パターンの取得
    unsigned long n = KanjiReadX(kanji, pat);

    // 受信した文字コードと文字をフィードバックする
    Serial.println(kanji, HEX);
    Serial.write(kanji >> 8);
    Serial.write(kanji & 0xff);
    Serial.println();
    // 取得したパターンを配列に書き込む
    p = 8;
    while (p--)matrix_pat[(i << 3) + p] = pat[p];
    i++;
    data_tr_long(3, 0xC00000 | (0xFFFF >> (int)((DM_LEN * ((double)i / (double)r))) ));






  }
  Serial.print(F("EEPROM Writing... "));

  // パターンを格納した配列を内蔵EEPROMに書き込む
  Serial.print(p = i * 8, DEC);
  Serial.println(" byte.");
  while (p--) {
    // EEPROM処理待ち
    eeprom_busy_wait();

    // EEPROMのアドレス0x01以降に書き込み
    eeprom_write_byte((uint8_t *)p + 1, (uint8_t)matrix_pat[p]);

  }

  // 最大文字数を内蔵EEPROMのアドレス0x00に書き込む

  // EEPROM処理待ち
  eeprom_busy_wait();

  // EEPROMに書き込み
  eeprom_write_byte((uint8_t *)0x00, (uint8_t)r);
  Serial.println(F("EEPROM Written. [ OK ]"));
  Serial.println(F("Please RESET !"));

  // 書き込みが完了したら先頭1行を点滅させて書き込み完了を通知
  while (1) {
    data_tr_long(3, 0xFF0001);
    delay(250);
    data_tr_long(3, 0x010000);
    delay(250);
  };
}




////// 電光掲示板表示部分 //////

void matrix() {



  // アドレス0x00にある文字数データを読み込んで8倍する。
  eeprom_busy_wait();
  unsigned int p = eeprom_read_byte(0x00) , r = p + DM_MARG + (p >> 3), i, po, all;
  r *= 8; p *= 8; all = p;

  // EEPROMに格納されている表示パターンを読み込む
  // 読み込みの際にドットマトリクスにプログレスバーを出す。
  while (p--) {
    eeprom_busy_wait();
    matrix_pat[p + (DM_MARG * 8) + (p >> 3)] = eeprom_read_byte((uint8_t *)p + 1);
    data_tr_long(3, 0x030000 | (0xFFFF >> (int)((DM_LEN * ((double)p / (double)all))) ));
    delay(1);

  }

  delay(100);
  // 表示用ループ
  // 今回は縦1列を書き換えて行く。
  while (1) {
    data_tr_long(3, ((unsigned long)matrix_pat[(i % DM_LEN) + po] << DM_LEN) | ((unsigned long)1 << (i % DM_LEN)));
    delayMicroseconds(MAT_LDL);
    if (++i > (DM_LEN * MAT_DEL)) i = 0;
    if (i == 0) po++;
    if (po >= r) po = 0;

  }


}

////// シフトレジスタ側の転送命令 //////

// long型1つをchar型4つに切り離して転送する命令。
void data_tr_long(int tr_byte, unsigned long data) {
  unsigned char d[tr_byte];
  int i = tr_byte, r = 0;
  while (i--) d[r++] = (data >> (i * 8)) & 0xff;
  data_tr(tr_byte, d);
}

// データの転送用命令
// 配列を後ろから転送する
void data_tr(int tr_byte, unsigned char *data) {

  digitalWrite(SPI_SSel, 0);
  while (tr_byte--) SPI.transfer(*(data + tr_byte));
  digitalWrite(SPI_SSel, 1);
}












// 今回使わないので隅っこに追いやっておく。
void loop() {
  // put your main code here, to run repeatedly:

}

 

“Arduino Unoで電光掲示板をつくる” への14件のフィードバック

  1. あらら より:

    こんにちは。2点教えて下さい。
    1)文字の流れる速度は、変えれますか?どこの数値を変えれば良いですか?
    2)アルファベットは表示できるのですが、日本語はうまく変換できていません。
      原因として、何が考えられますか?

    • Sakura87 より:

      コメントありがとうございます。

      1:
      27行目のMAT_DELの数値を大きくすれば遅く、小さくすれば早くなります。

      2:
      「うまく変換できない」の状況にもよりますが、全く見当違いの文字が出るようでしたら送信される文字コードが違うのかもしれません。

      1.送信される文字コードがShift-JIS形式であることを確認する
      2.フォントファイルが正しく指定されていることを確認

      この二つを確認すれば正しく表示されると思います。

      1は以下のコードをスケッチとして書き込んで「あ」と入力して送信後出た数字が「82」と「A0」であればShit-JIS。それ以外だと別の文字コードが転送されているので、もしArduinoのシリアルモニタをつかっているなら別のターミナルエミュレータで文字コードをShift-JISに変更して転送してみてください。シリアルモニタで変更する方法はなさそうです。

      // スケッチここから
      void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      while (!Serial);
      }

      void loop() {
      // put your main code here, to run repeatedly:
      // データ受信待ち
      while (!Serial.available()) delay(1);
      // 受信データを取り込む
      while (Serial.available()) {
      unsigned char c = Serial.read();
      Serial.println(byte(c), HEX);
      }
      }
      //スケッチここまで

  2. あらら より:

    こんにちは。
    スイッチを追加したのですが、下記がわかりません。
    1)書き込みモードと表示モードは何をみれば、どのモードになっているのかわかりますか?
    2)入力はPC(&キーボード)からすると思うのですが、どうしらた入力できますか?

    • Sakura87 より:

      コメントありがとうございます。

      1)書き込みモードと表示モードは何をみれば、どのモードになっているのかわかりますか?

      Arduino IDEを起動してシリアルコンソール(画面右上の虫眼鏡のマーク)をクリックします。
      (これが開けない場合はツール→シリアルポートからお使いのArduinoの名前があるものを選んで再度クリックしてください)

      そうしてボタンを押しながらArduinoをリセットすると「Ready! Max 32 characters.」と表示されます。
      また、電光掲示板の四隅のうちどこか1つのLEDが点滅しているはずです。

      2)入力はPC(&キーボード)からすると思うのですが、どうしらた入力できますか?

      1)の状態にしたらシリアルコンソール一番上の入力欄に、表示したい文字を入れて「送信」を押しますと入力された文字を処理してArduinoに保存します。

      保存中色々とメッセージが出ますが、最後に

      「EEPROM Written. [ OK ]
       Please RESET !」

      と表示され、今度は電光掲示板の1点ではなく、端っこ1行が点滅するようになります。
      こうなれば書き込み完了なので、ボタンを押さずにもう一度Arduinoをリセットすれば、電光掲示板に文字が表示されるはずです。

      それでは。

      • あらら より:

        遅くなりましたが、動作しました。ありがとうございます。
        ところが、文字の流れが90度に流れているので、LEDの並びを
        90度にして、新たに基板を作り直そうとしています。
        又、文字が左右反転になっているようです。
        原因は、LEDのタイプがAタイプではなくて、Bタイプだからかなと考え中。
        ちなみに、プログラムで、文字の左右反転や文字の流れの向きを簡単に変更することってできますか?

        • Sakura87 より:

          コメントありがとうございます。

          まずは動作おめでとうございます。

          文字の反転などについては249行目~253行目が文字を表示しているループ、260行目~がデータを転送している命令になりますので、
          この中のDM_LENと8の倍数の計算式があるところを、自身の電光掲示板で正しく表示されるように修正すると回路の変更までは不要だと思います。

          ただ、左右が反転している場合は、シフトレジスタのどちらかのピンの順番が逆(シフトレジスタの15・1234567ピンの順序で接続しているが実際は7654321・15の順でつながなければならない)になっている可能性が高いので、
          もしかすると回路を作り直した方が早いかもしれません。

          それでは。

  3. あらら より:

    早速のアドバイスありがとうございます。
    早速やってみたのですが、動作せず。
    ところで確認ですが、Arduinoと電光掲示板の配線は5本で、GMDと5V以外の3本は、
    Arduinoピン
    11     MOSI
    13     SCLK
    7      RCK
    ですか?

    • Sakura87 より:

      コメントありがとうございます。

      配線ですが、RCKが7ではなく8番です。
      プログラムの11行目

      #define SPI_SSel 8

      で設定されたピンに接続します。

      それ以外は問題ないと思います。
      これで光らないのならば、やはり電光掲示板の方に何らかの問題が
      あると思われるので、一度近くの電気回路に詳しい人に見てもらった方がいいかもしれません。

      それでは。

      • 匿名 より:

        ありがとうございます。
        LEDのアノードとカソードが逆タイプのLEDであることに気付き、入れ替えたら点灯しました。
        SDカードシールド使うのは難しそうなので、もう一度ラズパイに戻るか、SDカードシールドを購入して、Arduinoで行くか悩み中。

        • Sakura87 より:

          コメントありがとうございます。

          点灯しましたか。おめでとうございます!

          SDカードシールドは調べてみると2,000円程度で売られているようです。
          使用方法は多くのSDカードシールドはSPIで通信し、シールドのCSピン(ものによって表記が違います)の番号とコード6行目の

          #define SD_SELECT 4

          の数字を一致させるだけで概ね使えますので、操作も難しくはないです。
          (お店が近くにないなどの物理的なものは仕方ないですが。

          ただ、今もまだRaspberry Piをお持ちなら、一旦そちらで使えるかどうかを確認してみるのが一番安上がりでしょう。

          ところで、もしArduino用の液晶モジュールをお持ちでしたら、その中にSDカードやマイクロSDカードを取り付けられるものがありましたら、流用出来る可能性もありますので、参考にしてみてください。

          それでは。

          • あらら より:

            たびたびすみません。
            下記スイッチサイエンスのSDカードシールドを購入して文字出力させたいのですが、
            https://www.switch-science.com/catalog/1292/
            とりあえず、アルディーノにのっけて、実行してみたのですが、
            エラーはなく点灯するのですが、特に文字が流れることはありませんでした。
            下記教えて下さい。
            1)SDカードには何を保存します?
            2)ラズパイのように出力したい文字は入力しないの?
            3)写真にはスイッチが使われていますが、なくてもよいですか?

          • Sakura87 より:

            コメントありがとうございます。

            1)SDカードには何を保存します?

            こちらのプログラムではFONTXというフォントファイルを使用して文字を出力しますので、該当のフォントファイルを使用します。

            記事内のリンクはリンク切れを起こしている部分がありますので。

            http://littlelimit.net/misaki.htm#download

            以下のサイトから「misaki_fontx_2012-06-03.zip (82,207 bytes)」をダウンロードし、解凍して出てきた以下の2つの名前(矢印の左側)をSDカードのルートフォルダ(SDカードを開いたところ)に入れてください。入れた後は矢印の右側のファイル名に変更します。

            4X8.FNT → FONTXA.FNT
            MISAKI.FNT → FONTXJ.FNT

            2)ラズパイのように出力したい文字は入力しないの?

            文字の入力はArduinoのIDEにあるシリアルコンソールを使って入力します。ただし、ArduinoはRaspberry Piに比べると非常に非力なコンピュータなので、スイッチで書き込みモードと表示モードを切り替えて、書き込みモードで表示をしたい文字を書き込んでから表示モードで表示をする方法にしています。

            なお、FONTXファイルの取り扱いおよびシリアル通信の詳しい扱い方は以下の記事で紹介しています。

            https://sakura87.net/archives/3526

            3)写真にはスイッチが使われていますが、なくてもよいですか?

            上で説明したように、書き込みモードと表示モードを切り替えるスイッチになりますので、必要ですが。電線などで代用できるなら必ず必要というわけではないです。

            以上が問題なく出来れば、使えるはずです。

            それでは。

  4. あらら より:

    たびたびすみません。ラズパイを断念して、アルディーノの記事を見てTryしてみました。単純にラズパイをアルディーノに変えて、プログラムを書き込み完了したのですが、LEDは点灯せず。SDカードシールドはないのですが、本記事では、ラズパイをアルディーノに置き換えて、プログラムを書き込むだけで、動作はしますか?

    • Sakura87 より:

      コメントありがとうございます。

      こちらのプログラムはSDカード内に記録されたデータからフォントデータを読み込んで
      書き込んだデータを電光掲示板に表示させるプログラムになるので、SDカードシールドは必要です。

      ただ、単に動作確認と言うことであれば239行目の

      matrix_pat[p + (DM_MARG * 8) + (p >> 3)] = eeprom_read_byte((uint8_t *)p + 1);

      matrix_pat[p + (DM_MARG * 8) + (p >> 3)] = 0x55;

      と書き換えることで、LEDが縞模様に光ると思います。
      これが光らなければおそらくは電光掲示板の方に何らかの問題があるかと。

      ただし、テストなどはしていないので、保証は出来ません。
      ArduinoのIDEでコンパイルが通るのであれば恐らく大丈夫です。

      それでは。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事