PIC AVR 工作室別館 arduinoの館->TopPage->各種ライブラリ->キャラクターLCD

キャラクターLCD表示ライブラリ

以前のバージョンのキャラクターLCDライブラリを使って実験してみたところ、 LCDモジュールの初期化が上手く行かずに途中で投げだした経験があるんですが、 先日公開されたarduino0017ではこの初期化ルーチンについてladyadaさん が改善を加えてくれたとのことなので、早速使ってみたら上手く動きました。

このキャラクターLCD用のライブラリの使い方などを簡単に纏めておきたいと思います。

キャラクターLCDについて

マイコンを使って何か工作するときに、数値や文字といった情報を表示したくなることがあるかと思います。

PCと(USBやシリアルケーブルなどで)接続したまま動かすというのであれば、 arduino-IDE側に登載されたシリアルモニター宛に文字や数値を表示するという手もありますが、 arduinoはPCと切り離して単独で動かすことも可能なので、arduinoと直結する表示器が欲しくなります。 でもそういった単体のLCD等を買ってきて、マイコン側で全部制御するとなるとアレコレ骨が折れます。 で、一般にはキャラクターLCDというモジュール化されたものを使うわけです。

これはSUNLIKE社のSC1602Bです。このシリーズは秋月で数百円~千円程度で手に入ります。

LCD単体に何か表示するためには、LCDに常時交流信号を常時流しておいたり、表示の画素1個1個を時分割でダイナミックに走査したり… といった厄介なことをする必要があるため、マイコンがその制御すべてを受け持つととても面倒なのですが、 LCDモジュールならそのあたりの制御機能も内蔵しているので、マイコン側では「何を表示するのか」だけを、 つまりアプリケーション要件だけを考慮すれば良いので、取り扱いが格段に楽になります。

キャラクターLCDモジュールはどのメーカーのものも似たような外見をしていて、ほぼ同じ制御方法で使えるようになっています。 キャラクターLCDモジュールの内部には、日立のHD44780もしくは互換のICが内蔵されていて、 このICがマイコンから送られた表示内容を記憶しておいたり、LCD画面に信号を送ったりという制御を受け持ってくれます。 このHD44780は一種のデファクトスタンダードなので、SUNLIKE製でもシャープ製でも同じプログラムで制御が可能です。

強いていえば、モジュールによっては横方向に表示できる文字数や縦方向に表示できる行数にバリエーションがあったり、 バックライトの有無、 i/f端子の形状(写真のように7×2列だったり1列で14ピンタイプだったり)にもバリエーションがありますが、 基本的な制御方法は同じなのでライブラリ自体は使いまわしが可能です。

秋月などで手に入る一番ポピュラーなものは、先ほどのSUNLIKE社のSC1602Bシリーズでしょう。 16文字2行の表示が可能で、バックライトの有無や発色、表示部の面積などでバリエーションがあります。

比較的単純な機能しか持っていないモジュールですが、マイコン側の容量や処理速度、 I/Oピンの数など限られたリソースをLCD制御に充てるより、 LCDモジュール側が複雑な手続きを代替してくれるので簡単で便利なモノではないでしょうか。

接続方法

arduinoなどのマイコンとキャラクターLCDモジュールの間は、双方向のパラレルI/Fで接続します。

キャラクターLCDモジュールにはデータ用の信号ピンが8本あり、一度に1バイトのデータを送受信することが出来ます。

さらに、この8ビットのデータに加えてLCD側に向けて書き込みするのかLCD側から読み出しするのかを区別する信号や、 I/F内容が「データ」なのか「制御命令」なのかを区別する信号などもあるので、 マイコンとLCDモジュールは計11本の線で接続することになっており、それ以外に電源(VccとGND)や、 表示の濃さを指定するためのcontrast adj信号(VccとGNDを適当な抵抗で分圧して与える)も加えて、 計14ピンのI/F端子を登載しています。

バックライト内蔵モジュールの場合はさらにバックライト用のLEDを光らせるための端子もあります。

電圧について

液晶モジュールを駆動するためにはある程度の電圧が必要なため、通常はVccに5Vを掛けて使います。

5V版のarduinoなら、arduinoと電源を共有させて使うことが出来、とても扱いが簡単に済みます。

3Vや3.3Vなどマイコン用電源ではLCDモジュールをドライブすることが出来ないので、 3.3V動作のarduinoの場合はLCDモジュールと電源を共用することは出来ません。 別途5V程度の電源を用意するなど対策が必要です。以降、5V動作の場合を前提のお話とします。

信号線について

上述の通りキャラクターLCDモジュールはマイコン側と11本の制御信号で相互接続することになるのですが、 arduinoよりももっと小さいマイコン等の場合11本も信号線に引き出してしまうとピンが足らなくなることがあります。 そのために、使用するピンを省略することが出来る「省ピンモード」というのがあります。

通常、8本の信号線を一まとめにして一度に1バイトのデータを送受信するのですが、これを半分の4本にしてしまい、 1バイトのデータを2回に分けて送受信するというモードが設けられています。これによって信号線を4本省略することができます。

arduinoのライブラリもこの省ピンモードに対応しています。スケッチの初期化処理時に「省ピンで使うよ」と宣言するだけでOK。 それ以降、表示内容を上下4ビットずつに分離するなどの面倒なことはライブラリが引き受けてくれます。 よほど通信速度に拘る場合を除けば、アプリケーションプログラム上で省ピンモードか否かを意識する必要は基本的にないので、 通常は省ピンモードで使うのが一般的かと思います。(詳しくは後述)

さらに、通常LCD表示といえば書き込みだけ(LCDからの読み出しは行わない…表示だからデータを一方的に送るだけ) という用途が大部分だと思いますが、それを見越して「書き込み/読み出し」用のピンを接続しない=常時書き込み動作として扱うことも可能です。

現時点でarduinoの最新のバージョン=0017では、これらの省ピンモードと読み書きモードを好きなように組み合わせて設定することが可能になりました。 このため、単純に表示だけ行うなら、ピンを出来るだけ省略すればarduinoとLCDの間を最小では6本の信号線を繋ぐだけで良いことになります。 (別途電源とかは必要ですが)

この図の赤い線で消した部分が省ピンモード時に省略できるデータピン4本です。 書き込み専用で使用するなら、R/Wも常時LOW(=GND電位)に固定させてしまうことでさらに1ピン減らすことが出来ます。

具体的な接続方法などは後ほど回路図に示します。

arduino用のライブラリ

キャラクターLCDモジュールは、電源投入後に初期化のコマンドでLCDモジュールを一度初期化してしまえば、 あとはキャラクターコード(≒asciiコード+α)をマイコンから送信すだけでそのキャラクターがLCD画面上に表示されるというものです。

さらに、制御コマンドを使ってカーソル位置を指示したり画面を消去したりといったといったことも出来るようになっています。 イメージ的には大昔の8ビットPCのキャラクター画面と機能的には似た感じの操作性でしょうか。

キャラクターLCDのデータシートを眺めると、初期化やカーソル位置の設定方法などが詳しく書いてあるのですが、 これを紐解きながら1ビット1ビット設定を行っていくのは面倒ですし、正直言って生産的ではありませんよね。

大抵のマイコンの開発環境には、そのあたりの手続きを代替してくれるようなLCDライブラリが用意されているんですが、 arduinoにもそれが標準で用意されていて、arduinoのIDEをPCにインストールすると自動的にこのライブラリも一緒にインストールされます。 ユーザーは、スケッチを書くときに「このライブラリを使いますよ」という宣言をするだけで、LCDを簡単に扱うことが出来るようになります。

さらにarduino0017からは「外字」の表示、つまりキャラクターコード表に元々載っていない文字を 「ビットマップイメージ」で指定して表示する機能もサポートしました。(ladyadaさんに感謝!)

arduinoのキャラクターLCDライブラリで表示が可能な文字のコード表を挙げます。

真中辺のピンクの四角で囲ったところがおおよそasciiコードにあたる部分。 ベルコード(0x07)のようないわゆる制御コードは対応してませんが…。左側の緑の四角はカタカナや記号類。 右の赤い楕円のところは外字登録が可能な8文字です。(詳しくは後述)

この赤い楕円部分に8文字分まで自由にビットマップで文字を登録することが可能な訳です。

ちなみに緑の四角の部分は、発売される国によって色々なバージョンがあるみたいですね。

とりあえず動かしてみる

スケッチや配線の前に、まずは動かした結果を。冒頭の写真です。

いわゆる「hello world!」とプラスαなんですが、普段使いそうな機能を短いスケッチに盛り込んでみました。

その一つはカーソル移動です。「arduino.」と書く際に、2行目の6桁目(座標値では(5,1)に相当) にカーソルを移動してからarduino.と表示しているわけ。カーソル移動が使えないと不便ですからね。

もう一つ。便利な便利な外字登録。この写真の液晶中、右下にあるハートマークみたいなやつ。 1ドット1ドット自由に設定した文字を作って、アルファベットや数字などと同じ一つの文字として扱うことが出来て便利です。 ちなみにホントはハートじゃなくて「ネコ」のビットマップを作ったつもりだったんですけどね… でも先ほどのキャラクターコード表には載ってない文字でしょ?

というわけで、このように文字を書いたり、外字を登録したり表示したりということをやってみます。 この過程を通して、配線、初期化、文字の表示、外字の登録と表示といった一通りのモノが扱えるようになるわけです。

サンプルスケッチ

先ほどの写真を実現するためのスケッチです。例によって半角の不等号やダブルコーテーションは全角に換えてあるので戻して使ってください。

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

void setup()
{
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(”hello, world!”);
  lcd.setCursor(5, 1);
  lcd.print(”arduino.”);
  
  byte neko[8] = {
    B00000,
    B01010,
    B11111,
    B11111,
    B01110,
    B00100,
    B00000,
  };

  lcd.createChar(0, neko);
  lcd.setCursor(15, 1);
  lcd.write(0);

}

void loop() {}

スケッチの意味は後ほど。

配線と回路図について

arduinoとキャラクターLCDを接続する配線は、1ピン1ピン自由に設定することが可能です。そのピン配置は、 先ほどのスケッチ中に出てきたLiquidCrystal型オブジェクトのインスタンス生成のところで1ピンずつピン番号を指定することで設定しています。

そのピン配置設定の意味について整理した上で、それを配線図に落としていきます。

先ほどのスケッチでは、ピン指定のパラメタが7個指定されています。 この7つの意味は公式ファイルに載っているリファレンスと見比べると解ります。↓これです。

今回作ったサンプルスケッチでは7個のパラメタがあるので、リファレンスでいうとこの赤い矢印で指したところ… rs、R/W、E、D4、D5、D6、D7の7本を接続してそれぞれ12, 11, 10, 5, 4, 3, 2を使用するよ、という意味です。 そしてR/Wピンを使用するので、書き込みと読み出しの両機能を使うことが出来、 データピンは4本だけ使っているので省ピンモードという意味になります。

LiquidCrystal型インスタンスを生成する際に指定するパラメタの数で、これら4パターンの組み合わせから配線を選ぶことが可能です。 TPOにあわせて適当なものを選択すればよいでしょう。

配線例…データ4本+制御3本の場合

で、今回の7本の場合を回路図に表すとこんな感じになります。

5V版arduinoの例としてduemilanoveを回路図に載せてます。(megaやsanguinoのような多ピン版を除き)5V版なら何を使っても大差ありません。

これらの配線のうちrs、R/W、E、D4、D5、D6、D7の7本のつなぎ方は特に説明するまでも無いでしょう。単純に直結するだけです。

コントラスト調整

残りのVdd、Vss、adjの3ピンについて補足します。adjピンはLCD表示のコントラストを調整するためのピンで、 電圧の高低によってLCDのコントラストが変わります。通常は、VddとVssの間に10kΩ程度の抵抗を挟み、 その可変抵抗で分圧した電圧をajdに入力してあげます。可変抵抗のツマミをグルグルまわすことでコントラストを自由に変えられます。

電源ピン、つまりVddとVssはarduinoボードから拝借しています。通常ならPCからUSBケーブル経由でduemilanoveなどに供給されている5Vが、 スタンドアロンで使用している場合は外部から供給する電源をレギュレータで5Vにしたものが、それぞれarduinoのピンから取り出せることになっています。

配線に関する補足

arduino0017以降に収録されているライブラリを使う限りにおいては、ライブラリ中の各関数(メソッド)ともに、 R/Wピンも、今回のサンプルスケッチで使用していない4本のデータピンも接続不要なようです。

サンプルスケッチの他にも幾つか実験用スケッチを書いて実験してみましたが、R/WピンをGNDに落としたままでも普通に動くことが確認できました。 スクロールなどもそれなりに機能していた様です。0017用のライブラリは基本的にR/W信号を使わない方針に変わったようです。

貴重なマイコンのI/Oピンを省エネし、マイコンとの接続はデータピン4本+制御ピン2本、 あとLCD用の電源とコントラスト用の配線だけで制御可能なのはイイカンジです。

その場合、4本のデータピンはオープンに、R/WピンはGND電位にしておくと良いようです。使わない4本のデータピンをオープンにしておく理由は 居酒屋ガレージさんサイトに詳しく書かれています。

というわけで、特にコダワリが無い限りはR/Wも除いた6ピンで接続するのが良さそうです。

サンプルスケッチの意味

先ほどのスケッチを大まかに言うと、前半は初期化や文字表示を行っていて、後半は外字登録と表示を行っています。

前半部分…文字列の表示

まずはライブラリの呼び出し。標準でインストールされているライブラリなので、この1行を書けばすぐに使えるようになります。

#include <LiquidCrystal.h>

LiquidCrystal型のオブジェクトを生成し、その配線の定義をしています。

LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

使用するピンの数とその配置を決めているわけですが、スケッチ上ではどのピンをどこに繋ぐか判り難いですね。 なので、どのピンをLCDモジュールのどこに接続するのかはこの図か、公式サイトの使用をご確認ください。

次に初期化処理。x座標が0~15の16文字、y座標が0~1の2行に設定し、画面をクリアしている処理です。

void setup()
{
  lcd.begin(16, 2);
  lcd.clear();

で、実際に文字表示する処理。カーソルを移動したり文字列をプリントしたりしています。簡単です。

  lcd.setCursor(0, 0);
  lcd.print(”hello, world!”);
  lcd.setCursor(5, 1);
  lcd.print(”arduino.”);

ここまでが主に文字表示に関するところでした。

後半部分…その1:外字定義の登録

次は外字関係です。先述のとおりHD44780もしくは互換のICでは8文字分の外字登録が可能になっています。

この場合の外字登録というのは、あるキャラクターコードのビットマップイメージを自由自在に定義できるということで、 一度定義してしまえば、その後は普通の文字と同じようにLCD上に”文字として表示”することが出来るようになります。 G-LCDだと都度都度ビットマップを指定する必要がありますが、C-LCDではその必要がないのでとてもラクチンです。

HD44780もしくは互換のICでは、ビットマップを自由自在に定義できるのはキャラクターコードが「0x00」から 「0x07」の8文字だけです。asciiコードでは特殊機能コードのところに割り当たっているので、 print("abcd...");のようにprintメソッドにダブルコーテーションで括って扱うことは出来ませんが、 print(0,byte);とか、write(0);みたいな指定をすれば大差なく扱うことができます。

特にprintメソッドはSerial.printの時と同じ指定方法で使えるので、極めて簡単に使えることがわかります。

余談ですが、0~7番に指定したビットイメージは、それぞれ8~15番にも同じモノが適用されるようで、 0番にビットマップを指定してから8番のキャラクターコードを表示すると、 画面には0番として定義したのと同じものが表示されるようです。

さて、具体的にどのようにビットマップを定義するかについて。

  byte neko[8] = {
    B00000,
    B01010,
    B11111,
    B11111,
    B01110,
    B00100,
    B00000,
  };
  lcd.createChar(0, neko);

こんな風に、byte型で要素が8個の配列を作っておきます。各要素がそれぞれ上から順に液晶画面に表示される1列1列になるわけです。

ご覧の通り横5ビットしか指定してませんが、各バイトデータの下位5ビットだけが有効で、上位3ビットは指定しても無視されるようです。 LCD1文字の横方向は5ドットですから。

縦は7行分のビット列しか明示指定してませんが、LCDは1文字7行のドットしかないので残り1行はやはり無視されるようです。

「0」がドット無し、「1」がドット有りです。今回は小さい耳、丸い顔、小さい鼻って感じでネコを描いたつもりだったんですが、 表示したらハートマークみたいになってしまいました。まぁ、ネコを表示すること自体が目的じゃないので、これはこれでいいことにします。

で、その定義したビットイメージをcreateCharメソッドを使ってLCDに流し込むわけですが、このスケッチの場合は引数が (0,neko)となってます。これは、キャラクターコード=0番のビットイメージを、配列名=nekoという配列のビットイメージを使って定義しますよ、 という意味です。もちろんこの番号は0~7の8種類から好きな番号を指定することができます。

後半部分…その2:外字の表示と注意事項

で、定義したビットイメージを実際にLCDに表示するわけですが、定義した外字は普通の文字と同様に 「1つの文字」として扱うことが出来るので、せっかくだからカーソル位置を指定して好きなところに表示してみます。

  lcd.setCursor(15, 1);
  lcd.write(0);

}

void loop() {}

こんな風にsetCursorメソッドでカーソル位置を指定して、writeメソッドやprintメソッドを使って表示すればいいわけです。

キャラクターのビットイメージは、スケッチ実行の最中でも任意のタイミングで変更することができ、 動的にビットイメージを変化させることもできるので、たった8文字とはいえ表現力はそこそこ期待できますね。

ちなみに、このように一旦LCD画面上に外字を表示した状態で、その外字番号に相当するビットマップイメージをcreateCharで定義しなおすと、 即時ビットマップが反映されます。(この際LCDに文字を表示し直す必要はありません→既に表示されている文字のビットイメージが自動的に変化します)

ちなみに、今回のスケッチでは外字登録先にはキャラクターコード=0番を使用しましたが、 この0番を使用する際にはarduinoを含めてC言語系の場合工夫が要りそうです。

外字を1文字1文字表示するのであれば今回のようにwriteメソッドなどを使って記述していけばいいのですが、 外字を文字列変数中に埋め込んで扱う場合にはC言語系の文字列の「仕様」が少々厄介になります。

ご存知の通りC言語系では文字列(charの配列)の終端文字は「¥0」(キャラクターコード=0)とされており、 今回登録した0番の外字と重複しています。このためこの外字0番目を文字列中に埋め込むと、 その文字列は外字0番の1文字手前で終端だと認識されてしまいます。

で、文字列中に埋め込んで使うには、先ほど触れた件…0番~7番と8番~15番は同じビットイメージが表示される…という件。 これを上手く使ってやるのが良いと思います。例えば、0番を表示したい場合にキャラクターコードを8番に置き換えて文字列に格納する方法があります。

こうすることで、arduino含めC言語系でも普通の文字列関数が使用できることになります。 例えば、arduinoではprintメソッドの引数に文字列変数を使って文字を表示する場合などにこの件が適用できます。

ちなみに外字を文字列に格納する際、キャラクターコードに一律8を加算しておく(結果8~15番に置き換わる)といった方法も考えられますが、 arduinoの場合、0x09はTAB、0x0Aはラインフィード、0x0Dがキャリッジリターンがそれぞれ割り当たっており、 特にラインフィードとキャリッジリターンの扱いがwindows、mac、linuxでマチマチなので、思いもしないようなバグが表面化する恐れもあるので、 この3つの特殊コードにあたる部分についてはprintメソッドを使用しないほうがいいかも知れません。

arduinoのキャラクターコードは 公式サイトの該当ページをご参照ください。

なお、キャラクターコード=8番を使用する場合もcreateCharでビットマップ定義を登録する先は0番なので、 その点は間違えないようにする必要があります。

配線に関する注意点

LCDモジュールのピン配置

注意といっても大した話ではありません。モノによってピンコネクタが少し違っているものがあるよ、というお話。

入手のしやすさという意味では、秋月とかに行くとすぐに手に入るSUNLIKE社の16文字×2行のタイプ。

このタイプは通常1ピンから順に「Vdd」「Vss」「コントラスト」「RS」「R/W」…となっています。 このタイプが一番多いとおもいます。この配置であれば何の問題も無し。

気をつけないといけないのは少し配置が違うタイプのこと。

最近秋月で見かけるLCDでは、20文字×4行のタイプや8文字×2行のタイプには電源のピン配置が逆になっているものがあります。 1番ピンから順に「Vss」「Vdd」「コントラスト」「RS」…と言う風にVss、Vddの順番が入れ替わっています。

ピン配置は各パーツのデータシートに書いてあるので、LCDを買ってきたらまずここを真っ先に確認するといいと思います。

あともう一つはピン番号が逆に書いてあるものもあるということです。 セイコー製とかの一部のものは1~14番のピンが逆順にふられているものがあります。要注意。 ただ、番号の振り方が逆なだけで、物理的なピン配置は普通の16×2のタイプと変わらないようなので、単純に差し替えが出来るようです。

その他の点としては、バックライト登載タイプの場合のバックライト用電源供給でしょうか。 バックライトは通常LEDが埋め込まれているので、適当に抵抗などで電流制限をかけて使うことになります。 使用する抵抗の値はデータシートにおおよそ書いてあると思うので、その値を元に実際の明るさを見ながら輝度調整するとよいでしょう。 抵抗の変わりに定電流ダイオード(CRD)を使って電流制限をする方法もあります。

arduino側のピン配置

一方arduino側のピン配線ですが、これは1ピン1ピン自由自在にアサインできるので、 LCD以外にも接続したい他の機器とピンが重複しないように適当に選べばよいでしょう。その点ではあまり不自由や混乱は無いと思います。

要は、他の機能で使用するピンを避けて空いているピンの中から適当に配置を考えればいいでしょう…ということです。

実際に実験してみた様子をブログの記事の実験結果 に載せてありますので、あわせてお読みください。

まとめ

arduinoにLCDを接続して、文字を好きなところに表示したり外字登録をして表示したりしました。

arduinoのライブラリはその他にもカーソル制御やスクロール制御といった機能なども提供してくれていますが、 ひとたび文字の表示が出来てしまえば、それ以外の機能を利用するのは大した苦ではないと思うので、 必要性にあわせて挑戦してみてください。

そんな感じでこのページは纏めにしたいと思います。