Raspberry Pi – I2C~LCD1602

概要

ここではI2C接続によるLCD1602の制御について整理する。

Raspberry Pi用のキットにはI2CがセットされたLCD1602が同梱されていたが、Pythonのモジュールが見つからなかった。ゼロから組み立てようかとCのコードを読んでみたが、いま一つわからない。そこでネット上をいろいろと探して、自分なりに理解してみた。

LCD1602

LCD1602のピン配置

LCD1602のピン配置は以下の様になっているらしい。上から順番に1~16。

各ピンの意味は以下の通り。

GND Ground
+5V Vcc(電源)
CNT L→H→LでDB0~DB7ピンと信号伝送
RS Register Select -> H: Data, L: Command
R/W H: Read, L: Write
E L→H→LでDB0~DB7ピンと信号伝送
DB0~DB7 8ビットデータ
A LEDのアノード
K LEDのカソード

表示領域~DDRAM

2行表示の場合のDDRAMアドレスの割り当ては以下の様になっている。

LCD1602のコマンド

LCD1602のコマンドは以下の通り。H→1、L→0で表している。

  • RS=0のときはコマンド、RS=1のときはデータを表す
  • R/W=1で読み出し、R/W=0で書き込みで、コマンドは常にR/W=0
  • コマンドの場合は8ビットのDB7~0で最初に1が現れたビットによってコマンドが変わる
  • 書き込み/読み出しは、EをL→H→Lと変化させて実行

8ビット/4ビットモードの設定

LCD1602起動時、確実に8ビット/4ビットモードをセットする手順は以下の通り。

起動直後の初期設定では、適切な待機時間を挟んで4ビットで0x3を3回書き込んだ後に0x2を書き込むことで4ビットモードに設定される。

I2CによるLCD1602の制御

接続

キットのLCD1602にはあらかじめI2C接続のためのボードが接続されていた。チップはHLF8574Tと書かれていたが、これは中国製らしくフィリップス製のPCF8574と同じ機能らしい。PCF8574はI2C I/Oエクスパンダ―というチップで、I2Cに準拠しSDAを介したシリアルの通信と、P0~P7の8ビットパラレルの通信を変換する。

PCF8574のP0~P7が8ビットのレジスターの各ビットに相当し、それらはLCD1602の各ピンと以下のように接続されている(他のピンは省略している)。

参考サイト:

PCF8574 LCD1602 LCD1602の機能
P7 DB7 4ビットデータのbit3
P6 DB6 4ビットデータのbit2
P5 DB5 4ビットデータのbit1
P4 DB4 4ビットデータのbit0
P3 K バックライトのカソード
P2 E L→H→LでDB0~DB7ピンと信号伝送
P1 R/W H: Read, L: Write
P0 RS Register Select -> H: Data, L: Command

DB0~DB3は接続されていないことから、このモジュールは常に4ビットモードで使用する必要がある。

P2に接続されたKピンはバックライトのカソードにあたり、トランジスターのC~Bを介してGNDに接続されている。

LCDとRaspiの接続

Rasberey PiのGPIO2と3(3番ピンと5番ピン)がSDAとSCLに対応しており、電源・GNDとともにこれらをLCDの端子(正確にはLCDに接続されたエキスパンダーの端子)に接続する。

SDAとSCLに対するプルアップ抵抗がないが、LCD/I2C内部でプルアップされているらしい。

初期手順

Raspberry Piの手順に従ってI2Cを有効化した後、デバイスアドレスを確認(I2Cを参照)。ここでは、LCD1602のデバイスアドレスは0x27。

コード

動作テスト

LCDモジュールを4ビットモードにセット後、画面をクリアしてカーソルをブリンクさせる。

冒頭で定数を定義している。TWはEを1にしてからLに戻すまでの待機時間で、データシートでは最小230nsという値もあったが、Pythonのtime.sleepの分解能もあり、1ms(以上)としている。

次に、4ビットのデータを書き込む関数を定義している。

  1. 引数のデータの下位4ビットを取り出し、4ビットシフトして上位4ビットへ
  2. 下位4ビットにコマンドセット
    • バックライトON、転送Enable、Writeモード、コマンドレジスターに書き込み指示
  3. 書き込みウェイト
  4. EnableをLowにして書き込み

もう1つの関数は、1バイトのコマンドをLCDに書き込む。4ビットモードなので上位・下位の4ビットに分けて書き込んでいる。

コマンド送信の場合の手順は、上位4ビットの場合は0xF0でマスク、下位4ビットの場合は0xFでマスクして4ビット分シフトした後、以下の通り。

  1. 下位4ビットはコマンド書き込みイネーブルで、KE(RW)(RS)=0b1100=0xC
  2. TWの間ウェイト
  3. その後Eのみ0とするため0b11111011=0xFBでマスクして書き込み

実行部分の先頭で、8ビットモードを確定してから4ビットモードを設定。

いろいろなサンプルコードで0x33→0x32とバイト単位で書き込む例が多いが、4ビットごとの待機時間を意識するならこの方がデータシートの説明とも合っている。

最後にコマンド送信。

まず001で始まるFunction setで0b00101000=0x28とする。

  • DL=0で4ビットモード
  • N=1で2行表示
  • F=0で5×8フォントを使用

次に00001で始まるDisplay ONで0b00001111=0x0Fとする。

  • D=1でディスプレイ表示
  • C=1でカーソル表示
  • B=1でブリンクさせる

最後に0b00000001=0x01でディスプレイをクリア。

文字表示

先のコードに変更・追加を加えて、LCDに文字を表示してみる。

まず、write_command関数をwrite_byte関数に変更し、引数is_commandTrue/Falseに応じてRSの0/1を切替え、コマンド・データの両方を取り扱えるようにした。

データ送信の場合イネーブル時にRS=0となるため、下位4ビットはKE(RW)(RS)=0b1101=0xDとなる

また、新たに文字を表示する関数write_charを定義した。アドレスが与えられた場合はDDRAMのそのアドレスに、アドレスを指定しない場合は現在のアドレスに文字を書き込む。1文字書き込むとアドレスはインクリメントされるため、続けて文字を書き込む場合にはアドレス指定はしなくてよい。

実行の前半では、カーソルOFF、ブリンクOFFとしている。

文字表示の部分は以下の通りで、1行目に”ABC”、2行目に半角カナで”アイウ”と表示している。

LCD1602クラス

LCD1602を扱うクラスを作成。これまで作った関数をクラスのメソッドにしただけ。インスタンス生成時にLCDのアドレスを与える。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です