RaspberryPiでLCDを使う方法

前回は温度と湿度をセンサから取得する方法を書いた.

温度や湿度を確認するのにターミナルを開くのは面倒なのでLCDに結果を表示する.

必要なもの

RasPiは前回用意したので,今回用意するのはLCDのみ.

使うのはスイッチサイエンスの「16×2 I2C液晶モジュール(水平タイプ)」.ArduinoUNOのピン配列に合わせて入力5Vとなっているので注意.ちょっと回路をいじれば3.3Vに改造もできそう.

16x2 I2C液晶モジュール(水平タイプ) - スイッチサイエンス
16x2行の小さい液晶を2.54mmピッチに変換する基板にはんだ付けしたモジュールです。モジュールとマイコン基板を水平に接続することを想定しています。

前回のHTU21Dは非常に丁寧なデータシートで見やすかったが,今回のデータシートはHTU21Dよりも難解かもしれない.しかも表がコピペ画像で字が読みにくい...

LCDモジュールの使い方

使い方を考える

モジュールによってコマンドの使い方が異なるが,データシートにはシーケンス図は無いし,コマンドリストにあるRSビットやR/Wビットの説明がどこかわからない.一般的なLCDの記事と共通部分も多く,それらを参照するのもいい.

今回はArduino用のサンプルスケッチがあるので,これとデータシートのコマンドを突き合わせてコマンドの使い方を理解していく.

まずはコマンドリストを眺めてコマンド体系をなんとなく理解する.重要な部分に着色した.コピペ画像のコピペ画像で見にくいと思うので,オリジナルのデータシートを並べて見てほしい.

コマンドリスト1(データシートより抜粋)
コマンドリスト2(データシートより抜粋)

緑部分:このモジュールでは初めて1が出現する位置でコマンドを区別している.それ以降のビットでコマンドの詳細(コマンドリスト2)を指定する.

赤部分:このモジュールでは通常コマンド(H=0)と拡張コマンド(H=1)が用意されている.例えば”Rerun home”と”Screen configuration”のような緑部分が同じ位置にあるコマンドを区別するために”Function set”コマンドのHビットを使う.

青部分:一部しか色をつけてないけど,大切なのは,RSビットでコマンドかデータかを区別して,R/Wビットでコマンドの読み書き区別する.
RS=0:コマンド,RS=1:データ
R/W=0:書き込み,R/W=1:読み込み

ちなみに,
DDRAM(DisplayDataRAM)はLCD上の文字を保持しているところで,
CGRAM(CharacterGeneratorRAM)は標準フォントを保持しているところ.

なんとなくコマンド体系がわかったところでサンプルスケッチを上から見ていく.

// setup
 Wire.begin();
 delay(100);
 lcd_cmd(0x34);
 delay(5);
 lcd_cmd(0x34);
 delay(5);
 lcd_cmd(0x34);
 delay(40);

// function
void lcd_cmd(unsigned char x) {
 Wire.beginTransmission(I2Cadr);          // LCDへ送信開始
 Wire.write(0b00000000); // CO = 0,RS = 0 // 0x00(0b00000000) を送信
 Wire.write(x);                           // 0x34(0b00110100) を送信
 Wire.endTransmission();                  // 送信終了
}

LCDに対して3回 0x00 0x34 を送っている.最初の0x00はCOビットとRSビットの位置がわからないが,コメントからRS=0なのでコマンドを投げるとわかる.コマンド0x34は最初に1が出現する位置からFunction setコマンドを投げている.COビットは一旦おいておく.

  • DL=1:データ長8ビット
  • M=1:16文字2列のディスプレイ
  • SL=0:MUX1:18
    • DDRAMのデータはMUX(マルチプレクサ)によってディスプレイ上の32文字に割り当てられる
    • このモジュールでは16文字+2列なので基本的に0のまま
  • H=0:通常コマンド

続いて,文字の表示部分を見るとCOビットとRSビットの位置,COビットの意味がわかる.

// 文字の表示
void lcd_printStr(const char *s) {
  Wire.beginTransmission(I2Cadr);
  while (*s) {
    if (*(s + 1)) {
      Wire.write(0b11000000); // CO = 1, RS = 1  まだ後ろにデータがある
      Wire.write(*s ^ 0x80);
    } else {
      Wire.write(0b01000000); // CO = 0, RS = 1  最後のデータ
      Wire.write(*s ^ 0x80);
    }
    s++;
  }
  Wire.endTransmission();
}

ここまででコマンドの使い方は把握出来たので,実際に表示してみる.

文字を表示する

まずは初期化する.

$ i2cset -y 1 0x3A 0x00 0x30 i    # function set
$ i2cset -y 1 0x3A 0x00 0x01 i    # clear display
$ i2cset -y 1 0x3A 0x00 0x02 i    # return home

適当な文字を表示する.

$ i2cset -y 1 0x3A 0x40 0xD4 i
$ i2cset -y 1 0x3A 0x40 0xC5 i
$ i2cset -y 1 0x3A 0x40 0xCB i
$ i2cset -y 1 0x3A 0x40 0xC9 i
$ i2cset -y 1 0x3A 0x40 0xD4 i
$ i2cset -y 1 0x3A 0x40 0xCF i
$ i2cset -y 1 0x3A 0x40 0xD5 i
$ i2cset -y 1 0x3A 0x40 0xA0 i
$ i2cset -y 1 0x3A 0x40 0xCE i
$ i2cset -y 1 0x3A 0x40 0xC1 i
$ i2cset -y 1 0x3A 0x40 0xA0 i
$ i2cset -y 1 0x3A 0x40 0xCD i
$ i2cset -y 1 0x3A 0x40 0xCF i
$ i2cset -y 1 0x3A 0x40 0xCA i
$ i2cset -y 1 0x3A 0x40 0xC9 i

いちいちコマンド覚えてられないのでスクリプトを書いた.需要があればどうぞ.

HeavyMoon/i2c-dev
i2c devices for raspberry pi. Contribute to HeavyMoon/i2c-dev development by creating an account on GitHub.

任意の文字列を簡単に表示出来る.

$ ./lcd.sh init
$ ./lcd.sh m "HeavyMoon       T=$(./htu21d.sh t) H=$(./htu21d.sh h)"
表示例

おわりに

適当な文字はなんて表示したかわかりますか?

コメント

タイトルとURLをコピーしました