Edited at

RaspBerryPi3でIIC/I2C 1602シリアル液晶モジュールに文字を表示する (Pi4j)

More than 1 year has passed since last update.

\def\textlarge#1{%

{\rm\Large #1}
}
\def\textsmall#1{%
{\rm\scriptsize #1}
}


1、RaspBerryPi3を購入

  最近、遅ればせながら「RaspBerry Pi 3 Model B」と入門キット※1を購入しました。

 Pi4Jを使ってセット内の「IIC/I2C 1602シリアル液晶モジュール」へ文字を表示しようとして

 なかなかうまくいかず、大変だったので情報を残します。

 注意

 ・英数字しか表示出来ません。

 ・私は電子機器については電圧=抵抗×電流がわかる程度の全くの素人です。

$\textsmall{  ※1「Kuman 35個 Raspberry Piに適用 初心者 電子工作 1602液晶ディスプレイ+温度/湿度センサ+BMP180デジタル気圧センサー}$

$\textsmall{   +HC-SR501赤外線モーションセンサモジュール 子供遊び Raspberry Pi 3 2 model B A A+ + に対応 電子工作入門キット ラズベリーパイ K71」}$


2、Pi4JでLCDに文字を表示する

 本題に入ります。普段javaを使用しているのでPi4Jで表示処理を行います。


 (1)IIC/I2C 1602シリアル液晶モジュール

  液晶画面(QC1602Aだと思われる)とI2C通信モジュール(PCF8574と思われる)で構成されている。

  ①液晶画面(QC1602Aだと思われる)

   表

   image.png

   裏

   image.png

  ②I2C通信モジュール(PCF8574と思われる)

  image.png


 (2)ラズパイとLCDの接続

  下記のように接続します。

  ①全体画像

  image.png

  ②詳細画像

  image.png


 (3)ラズパイの設定

  I2C通信を有効にします。

  image.png


 (4)デバイスアドレスを取得

  ラズパイのターミナルで下記コマンドを実行します。

  ①コマンド:sudo i2cdetect 1

  image.png

  ②結果よりデバイスアドレス「3f」が取得できました。

    0 1 2 3 4 5 6 7 8 9 a b c d e f

   00: -- -- -- -- -- -- -- -- -- -- -- -- --

   10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

   20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

   30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 3f

   40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

   50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

   60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

   70: -- -- -- -- -- -- -- --


 (5)実行プログラム

  下記のソースを実行することで文字が表示されます。

  ①デバイスアドレスは各自修正が必要な場所が1つあります。

   (3)で取得したデバイスアドレスに修正します。

   例:デバイスアドレスが3fの場合I2C_ADDRを0x3fとする

    private final static int I2C_ADDR = 0x3f; // I2C address

  ②データはENABLE項目を使用して3回送ることが仕様上必要らしい

   つまり4bit通信の場合、6回送信する

     上位4bit送信1回目(ENABLE=Low)

     上位4bit送信2回目(ENABLE=High)

     上位4bit送信3回目(ENABLE=Low)

     下位4bit送信1回目(ENABLE=Low)

     下位4bit送信2回目(ENABLE=High)

     下位4bit送信3回目(ENABLE=Low)

  ③dev.writeで送信しているデータの構造

   image.png

   D:データ

    例、送信したいデータ0001ならD0=0、D1=0、D2=0、D3=1

   BL:バックライト

    1はバックライトON、0はOFF

   Rs:送信モード

    0はコマンド送信、1はデータ送信


I2CLcdDisplay.java

import com.pi4j.io.i2c.I2CBus;

import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;
/**
* LCDへ文字表示(英数字)
* @author pi
*
*/

public class I2CLcdDisplay {
private final static int I2C_ADDR = 0x3f; // I2C address
private final static int LCD_LINE_1 = 0x80;//1行目指定用
private final static int LCD_LINE_2 = 0xc0;//2行目指定用
private final static int LCD_CHR = 0x01; // データ送信モード
private final static int LCD_CMD = 0x00; // コマンド送信モード
private final static int LCD_ON = 0x08; //バックライトON
private final static int ENABLE = 0x04; //Enable bit
private final static int LCD_WIDTH = 16; // 印字マックス桁数
private static final int sleep = 2; //2ms待つ

private static I2CDevice dev = null;

public static void main(String[] args) throws Exception{
try{
System.out.println("表示処理開始");
I2CBus bus = I2CFactory.getInstance(I2CBus.BUS_1); //
dev = bus.getDevice(I2C_ADDR); //Address

lcdInit();
Thread.sleep(sleep);

lcd_string("TEST1",LCD_LINE_1);
Thread.sleep(sleep);
lcd_string("test2",LCD_LINE_2);
Thread.sleep(sleep);

System.out.println("表示処理終了");
}catch(Exception e){
e.printStackTrace();
}
}

/**
* LCD初期設定
* @throws Exception
*/

public static void lcdInit() throws Exception{
lcd_byte((byte)0x33,LCD_CMD); // 110011 Initialise
lcd_byte((byte)0x32,LCD_CMD); // 110010 Initialise
lcd_byte((byte)0x28,LCD_CMD); // 101000 Data length, number of lines, font size
lcd_byte((byte)0x08, LCD_CMD); // don't shift, hide cursor
lcd_byte((byte)0x01,LCD_CMD); // 000001 Clear display
lcd_byte((byte)0x06,LCD_CMD); // 000110 Cursor move direction
lcd_byte((byte)0x0C,LCD_CMD); // 001100 Display On,Cursor Off, Blink Off

Thread.sleep(sleep);
}

/**
* コマンド送信
* @param bInput コマンド
* @param mode 送信モード
* @throws Exception
*/

private static void lcd_byte(byte bInput,int mode) throws Exception{
int bits_high = mode | (bInput & 0xf0) | LCD_ON; // |:OR &:AND
int bits_low = mode | ((bInput<<4) & 0xf0) | LCD_ON; // |:OR &:AND

dev.write(0x13,(byte) bits_high);
lcd_toggle_enable((byte)bits_high);
dev.write(0x13,(byte) bits_low);
lcd_toggle_enable((byte)bits_low);
}

/**
*ENABLE項目を使って2、3回目のデータを送信
*1回目Low、2回目High、3回目Lowと3回送ることで送信データが確定できる仕様らしい
* @param bInput
* @throws Exception
*/

private static void lcd_toggle_enable(byte bInput) throws Exception{
Thread.sleep(sleep);
dev.write(0x13,(byte)( bInput | ENABLE));
Thread.sleep(sleep);
dev.write(0x13,(byte)( bInput & ~ENABLE));

Thread.sleep(sleep);
}
/**
* 文字データ送信
* @param strInput
* @param line
* @throws Exception
*/

private static void lcd_string(String strInput , int line) throws Exception{
int length = 0;
if(LCD_WIDTH>=strInput.length()){
length=strInput.length();
}else{
length=LCD_WIDTH;
}
lcd_byte((byte)line, LCD_CMD);
for(int i=0;i<length;i++){
lcd_byte((byte)strInput.charAt(i), LCD_CHR);
}
}
}



 (6)実行結果

  2行の文字を表示します。

  image.png

  

  ちなみに印字がとても$\textlarge{薄い}$場合があります。

  実行して表示されてないと思っても角度を変えてみるとうっすら表示されているかもしれません。

  下記つまみを回すことで濃さを調節できます。

  image.png


3、おわりに

 Pi4JでLCDを印字する情報がほとんどなくて手探りでなんとか表示にたどり着きました。

 他言語で成功した先人の方々のおかげです。感謝です!!!

 今後Pi4Jで挑戦する方がこれを参考にうまく表示できることを願います。

参考サイト

[1]1602 I2C Serial LCD Moduleをラズベリーパイ3(Raspberry Pi 3)で使う

 $\textsmall{Pythonのプログラムを参考にjavaに置き換えることができました。}$

[2]キャラクタLCDモジュールの使いかた

 $\textsmall{I2C通信のイメージがわかりやすくまとめられていました。上のソースは4bitモードでやっているみたいです。}$

[3]I2CエキスパンダPCF8574を使ったキャラクタLCD表示のテスト(2)

なぜ同じコマンド、データを3回送信しているのか分かりました。

[4]LCDモジュール データシート