Raspberry PiでLCDディスプレイに文字を表示する:初期化(Python)

 前々回でLCDとI2Cのざっくり仕様を、そして前回PythonでLCDのバックライトをON/OFFしたりHELLO WORLD!を表示したりしてみました。LCDの主目的は文字表示ですから、これでやる事やった感はあります:

 でも実は大切な事が一つ抜けています。それが「初期化」です。「おいおい、文字表示とか散々やった後に初期化の説明って、順番が逆だろ」と思うかもしれません。でもね、これ仕方ないんです。LCDのフラグの意味、機能モードの設定や画面クリア、この辺りの命令送信周りが揃っていないと実は初期化が出来ないんです。揃っていてもその意味が分からないとコードを見ても「???」なんです。なので先の記事で必要な物をまず揃えたというわけなんですね。

 という事で、今回は超大切なLCDの初期化のお話です。

4bitモードか8bitモードか、それが問題

 実はLCDは電源投入時に4bitモードか8bitモードか分かりません。デフォルトで8bitモードなのかもしれませんが、その保証が無いんです。これとても困るんです。だって、何をするにもこのインターフェイスモードが分からないと始まらないわけですから。4bitモードだと思っと操作したら、実は8bitモードなのかもしれないですし、その逆もありえます。4bitモードの場合、何かトラブった時に1回目の送信で終わっちゃっている事もありえます。その場合こちらが1回目のつもりなのにLCDは2回目…みたなあべこべ状態も起こり得ます。

 LCDに取り付けたI2Cインターフェイスは4bitモード前提なので、何が何でも起動後に4bitモードにしなければならない。でも、LCDは4bitなのか8bitなのか、1回目の命令待ちなのか2回目なのかも分からない状態。果たしてどうしたものか…。これを見事解決するのが「初期化」です。本当に実にうまい仕組みになっています。

4bitモードの方法でFunction Set命令の0x33と0x32を連続で送信する!

 LCDが8bitモードでも4bitモードでも、実は4bitモードの送信方法でFunction Set命令である0x33と0x32を2連続で送信すると、驚く事に確実に4bitモードに設定する事ができます:

def initLCD( bus, lcd ):
    # 4bitモードの送信方法でFunction Setで一旦8bitモードに設定(0x33送信)
    sendLCDCommand( bus, lcd, 0x33 )

    # 4bitモードの送信方法で引き続き0b00|0011|0010を送信(0x32送信)
    # 2回目の送信(下位4bit)で4bitモードに切り替わる
    sendLCDCommand( bus, lcd, 0x32 )

理屈を紐解いてみましょう。

起動時に8bitモードだった場合

 LCD起動時に8bitモードだった場合、LCDはD0~D7まで揃った値が来ることを期待しています。

 4bitモードの送信方法で最初に0x33、2進数にすると0011 0011を送信すると、1回目でD4~D7までの上位4bitが送られる事になります。つまりD0~D7の並びは「0011 0000」です。下位4bitが0000になるのは、そもそもD0~D3が結線していないので8bitモードでは0以外になれないためです。

 0011 0000は命令表で見るとFunction Set命令に当たり、4bit目がDL=1、すなわち8bitモードに設定せよという指示になっています:

これにより1回目の送信でLCDは8bitモードになります。今8bitモードですから、これは現状維持です。

 4bitモードでの送信は2回で1セット。よって2回目が続けて発生するわけですが、0x33の下位4bitもまた3なので、同じコマンド送信になります。よって8bit設定再びなわけです。

 初期化では次に0x32を送信するのでした。これも1回目は上位4bitの「3」が送信されるのでやはり8bitモードに設定。そして2回目で初めて下位4bitの「2」を送信する事になります。2進数にすると0010 0000です。上の表でDL=0が指定される事になり、これで4bitモードに切り替わるんです。

起動時に4bitモードだった場合

 起動時に4bitモードだった場合、最初の0x33の送信で1回目に上位4bitにある「3」が送信されます。2進数だと0011 0000です。これはFunction SetでDL=1の指定なので8bitモードへ切り替えになります。2回目の下位4bitも「3」なので、8bitモード指定で変わらず。

 続く0x32の送信も、1回目はやっぱり上位4bitの「3」なので8bitモード指定ですが、2回目の「2」の送信で0010 0000。これはDL=0なのでここで4bitモードへ切り替えとなります。

起動時に4bitモードの1回目送信状態だった場合

 4bitモードは2回命令で1セットなんですが、停電やらデバッグでプログラムを途中で止めたりなどした場合、LCDが1回目の命令を受信後の中途半端な状態になってしまう事があります。実はこれも0x33と0x32の送信で解消されます。

 今LCDは1回目の受信が終わり、2回目の受信を待っている中途半端な状態だとします。これで初期化処理を行ってみます。

 0x33を4bitモードのつもりで送信すると、上位4bitの3がまず送信されます。LCDはそれを2回目の物として受け取ります。つまりLCD内では「?? ???? 0011」という命令となります。これがどう動くかは正直わかりませんが、機能不全になるという事はまず無いです。

 続いて下位4bitの「3」が送信されます。LCDはこれを新しい1回目の命令として受け取り、2回目を受信待ちします。「0011 ????」の状態です。

 初期化の2回目は0x32の送信です。上位4bitの「3」が送信されるとLCDは2回目の下位4bitにそれを入れ命令を成立させます。「0011 0011」が実行されるわけです。これはFunction SetでDL=1なので8bitモードへ切り替えになります。下位にある11は無効フラグなので無視されます(これがうまい仕様)。

 最後の「2」の送信ですが、今LCDは8bitモードに切り替わっています。よって「0010 0000」として受け取ります。ほら、これFunction SetでDL=0、4bitモードへの切り替えです!最後の最後でちゃんと4bitモードに切り替わるんですね~。

 このようにLCDが電源投入時に8bitモードでも4bitモードでも、そして4bitモードで1回目のみ送信している中途半端な状態でも、0x33と0x32を送信する事で確実に4bitモードに設定されるんです。この初期化方法はLCDのデータシートにちゃんと記載されています。これホント感動的なビットマジックです!

画面クリアや行数設定なども指定しよう

 初期化時に0x33と0x32を送信すれば4bitモードに確実に切り替わりますが、その後の表示設定は仕様によって異なります。もしかしてDDRAMにゴミデータが残っているかもしれませんのでClear Display命令(0x01)は呼ぶべきでしょう。呼んだ後は1.53ms以上必要なので注意ですよ。またFunction Set命令で改めて行数設定なども指定しないといけないですね。この辺りはお好きにどうぞです。

終わりに

 今回はLCDの初期化について見て来ました。巷のコードでも最初に0x33と0x32を4bitモードとして送信するコードがあるのですが、正直僕は何の事か最初サッパリ分かりませんでした。でも仕様を把握して動作を丁寧に王都、それが非常に良く出来たビットマジックである事がわかりました。マジでこれ考えた人天才だと思いますw。LCDを扱う前とか、何かあった時にこの初期化コマンドを呼べば一安心ですね。

 次回はLCDのカーソルとブリンカーについて押さえておこうと思います。

ではまた(^-^)

<次回>


この記事が気に入ったらサポートをしてみませんか?