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

```math
\def\textlarge#1{%
  {\rm\Large #1}
}
\def\textsmall#1{%
  {\rm\scriptsize #1}
}
```
#**１、RaspBerryPi3を購入**
　　最近、遅ればせながら「RaspBerry Pi 3 Model B」と[入門キット※1](https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwidnK_Bm5jWAhVIyrwKHYTXCQgQFggnMAA&url=https%3A%2F%2Fwww.amazon.co.jp%2FKuman-Raspberry-1602%25E6%25B6%25B2%25E6%2599%25B6%25E3%2583%2587%25E3%2582%25A3%25E3%2582%25B9%25E3%2583%2597%25E3%2583%25AC%25E3%2582%25A4-BMP180%25E3%2583%2587%25E3%2582%25B8%25E3%2582%25BF%25E3%2583%25AB%25E6%25B0%2597%25E5%259C%25A7%25E3%2582%25BB%25E3%2583%25B3%25E3%2582%25B5%25E3%2583%25BC-HC-SR501%25E8%25B5%25A4%25E5%25A4%2596%25E7%25B7%259A%25E3%2583%25A2%25E3%2583%25BC%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%25B3%25E3%2582%25BB%25E3%2583%25B3%25E3%2582%25B5%25E3%2583%25A2%25E3%2582%25B8%25E3%2583%25A5%25E3%2583%25BC%25E3%2583%25AB%2Fdp%2FB01LZ4AZUX&usg=AFQjCNGa4JXocNCbJf54e6eounq35hL17w)を購入しました。
　Pi4Jを使ってセット内の「IIC/I2C 1602シリアル液晶モジュール」へ文字を表示しようとして
　なかなかうまくいかず、大変だったので情報を残します。

　注意
　・英数字しか表示出来ません。
　・私は電子機器については電圧=抵抗×電流がわかる程度の全くの素人です。

$\textsmall{　　※1「Kuman 35個 Raspberry Piに適用 初心者 電子工作 1602液晶ディスプレイ+温度/湿度センサ+BMP180デジタル気圧センサー}$
$\textsmall{　　　+HC-SR501赤外線モーションセンサモジュール 子供遊び Raspberry Pi 3 2 model B A A+ + に対応 電子工作入門キット ラズベリーパイ K71」}$
#**２、Pi4JでLCDに文字を表示する**
　本題に入ります。普段javaを使用しているのでPi4Jで表示処理を行います。
##　(1)IIC/I2C 1602シリアル液晶モジュール
　　液晶画面（QC1602Aだと思われる）とI2C通信モジュール（PCF8574と思われる）で構成されている。

　　①液晶画面（QC1602Aだと思われる）
　　　表
　　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/164812/eef5c0b9-6ad2-47c0-ad64-48debe824f99.png)
　　　裏
　　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/164812/dbcf7577-40cc-6c5f-c897-458a1e243b4e.png)

　　②I2C通信モジュール（PCF8574と思われる）
　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/164812/5bfb31d3-e2c2-2606-0119-bd8778a8e481.png)

##　(2)ラズパイとLCDの接続
　　下記のように接続します。
　　①全体画像
　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/164812/047dc5ec-a2b3-db6a-c854-c041978f7ffc.png)
　　②詳細画像
　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/164812/2c055de4-4031-2c48-e558-67b1aaa8f88e.png)

##　(3)ラズパイの設定
　　I2C通信を有効にします。
　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/164812/39cbfb3f-63da-7635-5d20-c33a1d4f80e0.png)

##　(4)デバイスアドレスを取得
　　ラズパイのターミナルで下記コマンドを実行します。
　　①コマンド：sudo i2cdetect 1
　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/164812/5c6c6902-559d-aa8f-449b-7c28eb578296.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)で取得したデバイスアドレスをソースに修正します。
　　　例:デバイスアドレスが<font color="Red">3f</font>の場合I2C_ADDRを0x<font color="Red">3f</font>とする
　　　　private final static int I2C_ADDR = 0x<font color="Red">3f</font>;  // 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で送信しているデータの構造
　　![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164812/fc0ceff6-345f-6178-b38e-9f8328abaa38.png)

　　　D：データ
　　　　例、送信したいデータ0001ならD0=0、D1=0、D2=0、D3=1
　　　BL：バックライト
　　　　１はバックライトON、0はOFF
　　　E：ENABLE
　　　　1回目=0、2回目=1、3回目=0
　　　　この項目をLow、Hight、Lowに変化させて同じデータを3回送ることで1通信が完了する仕様らしい
　　　Rs：送信モード
　　　　０はコマンド送信、１はデータ送信

```java: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項目を使って２、３回目のデータを送信
     *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](https://qiita-image-store.s3.amazonaws.com/0/164812/9fdc861e-35b3-863a-69dd-0755e82df068.png)
　　
　　ちなみに印字がとても<font size="30" color="#C0C0C0">$\textlarge{薄い}$</font>場合があります。
　　実行して表示されてないと思っても角度を変えてみるとうっすら表示されているかもしれません。
　　下記つまみを回すことで濃さを調節できます。
　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/164812/203025c3-d434-0889-47df-1eac518d56bb.png)

#**３、おわりに**
　Pi4JでLCDを印字する情報がほとんどなくて手探りでなんとか表示にたどり着きました。
　他言語で成功した先人の方々のおかげです。感謝です！！！
　今後Pi4Jで挑戦する方がこれを参考にうまく表示できることを願います。


参考サイト
[1][1602 I2C Serial LCD Moduleをラズベリーパイ3（Raspberry Pi 3）で使う](https://terutakke.com/diary/1602-i2c-serial-lcd-modul/)
　$\textsmall{Pythonのプログラムを参考にjavaに置き換えることができました。}$
[2][キャラクタLCDモジュールの使いかた](http://elm-chan.org/docs/lcd/hd44780_j.html)
　$\textsmall{I2C通信のイメージがわかりやすくまとめられていました。上のソースは4bitモードでやっているみたいです。}$
[3][I2CエキスパンダPCF8574を使ったキャラクタLCD表示のテスト(2)](http://edycube.blog2.fc2.com/blog-entry-692.html)
なぜ同じコマンド、データを3回送信しているのか分かりました。
[4][LCDモジュール　データシート](https://www.openhacks.com/uploadsproductos/eone-1602a1.pdf)