桜のはなびらブログロゴ

桜のはなびらブログ

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

   

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

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Ω前後で好きなものでいいです。

コーディング

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

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

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

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

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

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

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

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

EEPROMの操作

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

  • #include <avr/eeprom.h>

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

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

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

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

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

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

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

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

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

表示部のループ

表示用のループはこのように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型で同様のビットシフト処理を行う場合は、以下のようにすればいいらしいです。

これはたとえば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ビット毎に分割して配列に押しこむ方法のほうがめんどくさくないと思います。

全体のソースコード

 

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

  1. あらら より:

    早速のアドバイスありがとうございます。
    早速やってみたのですが、動作せず。
    ところで確認ですが、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)写真にはスイッチが使われていますが、なくてもよいですか?

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

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

            それでは。

  2. あらら より:

    たびたびすみません。ラズパイを断念して、アルディーノの記事を見て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 を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事