桜のはなびらどっとねっとロゴ

桜のはなびらどっとねっと

Arduino Uno でグラフィック液晶にテキストを表示する。

この記事は1年以上前に投稿された記事です。 この警告表示について

IMG_7199_20160124

今回はArduino Unoでグラフィック液晶にテキストを表示してみたいと思います。
前回は画像表示から入りましたが、Arduinoでは正直画像を読み込んでどうこうするよりも、何らかのデータを表示するほうが多いと思いますので。今回はグラフィック液晶に日本語を表示してみたいと思います。

はじめに

液晶の説明等はRaspberry Piで同じ液晶を動かした時に説明していますのでそちらを見てください。
操作方法は基本的に同じ、今回はArduinoの少ないピンを少しでも有効活用をするためにシフトレジスタを使ってデータを転送しています。

必要なもの

  • 128×64ドットの白黒グラフィック液晶
    今回は前回と同じTG12864B-02WWBVを使用しました。
  • カーボン抵抗
    10kΩ ←コントラスト調整用1
    15kΩ ←コントラスト調整用2
    470Ω ←R/Wコネクタ用
  • シリアル-パラレルのシフトレジスタ(74HC595)
    74HC595シリーズならなんでもいいので好きなモノを使ってください。
    テキサス・インスツルメンツ製が安くていいでしょう。
  • SDカードシールド
    なんでもいいのでとりあえずArduinoでSDカードが使えるようになるアイテム。
    Arduino標準のSDカードライブラリが使えるもの。

動作説明

この液晶は64x64pxを制御できるコントローラを2つ搭載していて、それを交互に切り替えることによって128x64pxの描画領域を実現しています。

データは8bitパラレル接続でデータを送信し、RSピンを切り替えることによってコマンド・データを、CS1・CS2の2ピンによってデータを転送する液晶コントローラを指定しています。ちなみにこのCSピンは2本ともHレベルにすることによって両方のコントローラに同じコマンド及びデータを送信することが可能です。(2コントローラ同時Hはやって良い処理なのかは知らないが出来るんだから利用させていただく。心配なら片方ずつ書き換えたほうがいいかも。ただし今回は使わないがReadを使うならやめておいたほうがいいかもしれない。)

これを全てIOピンでやろうとすると、13ピン必要になり、20ピンしかないArduinoのIOでは7ピンしか残らないため、SDカードに4ピン、シリアル通信に2ピン使ってしまうともう残るピンがありません。
そこで今回はシフトレジスタを利用してデータ8ピンを3ピンに減らし、更にSPIコマンドが使えるのでSDカードと2ピンを共通化して結果的にデータピンを1ピン相当に減らしています。

これで8ピン空くことになり、色々と使える幅が広がりますね。

接続について

基本的にピン-ピンで接続するだけなので、回路図などは載せません。以下の通りに接続すれば使えるはずです。

液晶側接続先接続先のピン
レジスタ選択Arduino
リードライト切り替えArduino抵抗を介してGNDへ
イネーブル信号Arduino
データビット0-7シフトレジスタQA-QH
チップ選択1(CS1)Arduino
チップ選択2(CS2)Arduino
リセット信号Arduino10

バックライト関係のコネクタはメーカーの指示通りに半固定抵抗を使用するなり、前回のように以下の様な接続をする事でとりあえず使用することが出来ると思います。

tg12864vo

シフトレジスタのピンは以下のように接続します。

液晶側接続先接続先のピン
SIArduino11(MOSI用固定 ※SDカードと共通)
RCKArduino7(SlaveSelect用・任意)
SCKArduino13(SCLK用固定 ※SDカードと共通)
QA-QH液晶モニタデータビット0-7
GArduinoGND
SCLRArduino+5V
QH’なし今回は使用しません。

SDカードはMOSIを11・MISOを12・SCLKを13・SlaveSelectを4に接続します。

 

フォントの格納

グラフィック液晶に文字を表示する場合、基本的には何らかのフォントを用意する必要がありますが。
Arduinoはメモリが非常に少ない。RaspberryPi2は1GB(1073741824Byte)の超広大なメモリ領域があるのに対してArduinoは2048バイトしかありません。なんと524,288分の1しかない!!これじゃあRaspberry Piでやったような画像一覧ファイルを用意してそれを変数に入れ込んで…なんて言うことはとてもじゃないけど出来ません。

ではどうするのかというと。

1.プログラムにコードを書き込んでIFなどで変数に入れ込む

これは非常に手間です。キャラクタ液晶と同じようにアルファベット+カナ程度ならこれでもいいでしょうが。JIS第一水準だけでも軽く死ねるレベルです。

2.漢字ロムを使う

これが非常に簡単でしょうが、漢字ロムの入手性があまり良くなかったり、色々と制約がありますし。
なんといっても結構これをやる方法は紹介されているので今回は省きます。
恐らく速度面や部品点数から考えるとこれが一番いい方法だと思いますが。
今回はいい感じの漢字ロムが入手できなかったので採用しませんでした。

3.なんとかSDカードに文字一覧画像を入れて読み込む

SDカードって何かと使うじゃないですかぁ?じゃあこいつにフォントを入れちゃえばいいかなーって。

というわけで今回もこの方法で行きます。
ただし、メモリの制約上どうしても1文字ずつの読み込みになってしまうのでファイルシークが発生してしまい少々実効速度は遅めです。(といっても平均40ms程度なので中々実用的です。)

それをやったのが前回のこの記事です。

というかこれをやるために書いたようなものですが。長くなったので分けました。

 

コーディング

今回使用するライブラリはSD.h、SPI.hです。この2つをインクルードしてください。

使用するピン番号を設定します。

基本的にSD・シフトレジスタアクセスに使うSPI用の11~13ピン以外は任意で構いません。
実はArduinoのANALOG INピンはデジタルIOとして使用できる(14~19がA0~A5に該当)のでアナログ入力を使用しないのであればこちらに押し込んでしまえばPWMピンが有効活用できます。

次にフォントファイルの仕様を指定します。

今回は上にあげたArduino Unoで漢字を扱う と同じモノを用意します。なお、今回は「左90度回転」させたものを用意します。

次に液晶にデータを送る変数名と塗りつぶしデータを指定します。
連続した8箇所なので毎度書き換えてもいいのですが、面倒なので今回はマクロを使って指定する方法を取ります。マクロの使い方については適当にググってください。

細かい方法等はコメントを参照してください。

フォントファイルのファイルハンドルを格納する変数もココに定義しておきます。

次にSetup関数に必要な初期化コマンドを書いておきます。

今回はシリアル通信で入力されたデータを表示するのでシリアル初期化とポート接続待ち、液晶初期化処理を入れます。

loop関数の前に、必要な変数を定義しておきます。(中でもいいがこの方が若干高速化されるっぽい)

loop関数の中身を書いていきます。

ループ用変数の初期化からデータ取り込みまでです。
特に説明は不要だと思います。

次に文字を転送する行を塗りつぶします。

今回は両方のコントローラに同時に転送する方法をとっていますが。それでも計64回転送をしないといけません。この後関数を作るので個々のコマンドは1行で済むのですが。裏で9行の命令が待っているので、実は64回命令を書いてしまったほうが処理速度が僅かですが早いです。しかし64行は長いので16行を4回ループにしています。これでも30ms程度で終わるので中々高速です。

と思ったけど今やってみたら殆ど実行時間変わらなかったので変更しました。

次に液晶に文字を転送する位置を決めます。

今回は画面を上下反転した状態で使用するのですが。コントローラ1側は9文字目からが表示されるので8文字(16バイト)以上の残りの文字数分オフセットを作っています。

コントローラ2の方は8文字以上の場合は普通にアドレス0に設定してしまえばいいのでそのままコマンドを送ります。8文字以下の場合はコントローラ1で行った処理をコントローラ2にも行ってやります。

最後に今回はfor命令ではなくWhileとデクリメントでループ処理を行います(この方が数ms高速)そのため、ループ用変数に+2(ループ1回分)しています。

次にSDカードをオープンする命令を書きます。
この命令は本来KanjiRead命令の中に入りますが、これを外に出すだけで100msも違うのでループ外に持ってきました。

次に文字転送ループを書きます。

どうしているかはコメントに書いてある通りですが。文字コードはArduinoのシリアルモニタはShift_JISであって。Shift_JISがそこそこ扱いやすいのでShift_JISを使っています。
よってこの命令を使用するときはUTF-8では使用できません。何らかの方法でShift_JISにて送信してやる必要があります。(PCからのデータを表示する場合はPCの文字コードをShift_JISにしてやればいいのですが、Arduino単体や他のArduinoと通信する場合はArduinoのIDEが文字コード指定できないので非常に手間です。)

最後のパターン転送も塗りつぶしと同様に、forやwhileで転送するより8回書いたほうが若干早いのでこうしました。(これは実際にコッチのほうが1msほど早いみたいなのでこのままで行きます。)

最後にSDカードのファイルを閉じて、行をインクリメントして終了です。

次に液晶制御に必要なコマンド転送命令を書きます。

コマンド転送命令です。RSピンを設定、CSピンを設定、シフトレジスタのRCKをLにした後、
SPIコマンドを利用してデータを転送。
シフトレジスタのRCKをHにしてその後2μ秒待ちイネーブルを切り替えてデータを転送しています。

本来ならCSピントシフトレジスタのRCK切り替えの前に0.45μ秒のディレイを置くべきですが、digitalWriteの処理が44サイクル(1サイクル0.0625μ秒@16MHz)SPI転送コマンドに2サイクルを要していて、両方で既に3μ秒経過していますので不要となります。

という事で実はその後のdelayMicrosecondsも不要だったりしますが。こちらは保険として残しておきます。

次に漢字パターンを読み込んで返す命令を作ります。

前回とだいぶ変わっていますが。前回のコードをいろいろと洗い流した結果。これが一番高速に処理できました。
SD関係の命令は前述のとおり関数外にだしてしまいましたが、一応コメントアウトで残しております。

これを全てつなげたコードが以下のとおりです。

動作結果

以上のコードをコンパイルし転送して、以下の文字を転送すると画像のようになります。

IMG_7201_20160124

上の文字列を転送した結果、所要時間は以下のとおりでした。

  1. processing time 743 ms
  2. processing time 616 ms
  3. processing time 725 ms
  4. processing time 689 ms
  5. processing time 599 ms
  6. processing time 690 ms
  7. processing time 690 ms
  8. processing time 617 ms

概ね1秒程度で書き換え完了していますのでまぁまぁ実用的だと思います。

終わりに

今回はArduinoにとっては処理が大変なグラフィック液晶を使ってみました。
やはりこれくらいのものになるとArduino Unoでは若干処理が重たいようです。
といっても、実際に一番時間を割いているのはSDカードにアクセする。それもファイルのシーク位置を決めている部分のようなので、そこをどうにかできればもう少し高速化出来ると思います。(今回はRaspberry Piと極力同じ方法で扱えるようにということが重要だったのでこうしましたが、本来ならもう少しArduinoに扱いやすいデータ形式で格納してやる必要がありますね。)

しかし、態々漢字を入れる必要が無く、英数字だけでいいのであればもっと簡単に処理することも可能でしょうが。そこまでして漢字を扱うのなら、もういっそRaspberry Piをメインにしてみたほうがいろいろと楽だと思います。第一世代ならそんなに値段変わらないしね。

というわけで以上でおわります。

コメントを残す

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