Raspberry LCD with Java

LCD 1602 點矩陣液晶

1602 LCD 是市面上最常看到的矩陣顯示器. 雖說只能顯示16*2=32個英文文字, 但對於一些只需顯示簡易訊息的工業機械控制已經是足夠超強的了. 且價格便宜, 不用台幣100元.

底下是1602A的正反面圖

lcd_1

lcd_2

I2C轉接板

由上可見, 共有16支針腳, 實在太恐怖了, 這線是要怎麼拉啊. 再說了, 樹莓派的針腳也才40針,  接了這塊後, 其他東西都不用搞了. 所以市面上就有出一塊I2C轉接板, 簡化成只有四支針腳

lcd_3

接線法

lcd_i2c

LCM1602 IIC V1 接腳 Raspberry Pi GPIO 腳位
GND 實體編號 6 (接地)
VCC 實體編號 4 (+5V)
SDA 實體編號 3
SCL 實體編號 5

開啟RaspBerry I2C 功能

1. 在樹莓派需執行 sudo raspi-config, 然後選取Interfacing Option

i2c_1

2. 選取 P5 I2C

i2c_2

3. 依序選取YES/Finish後,記得重新開機
sudo reboot

程式碼

講到使用Java撰寫樹莓派程式碼, 實在是少的可憐. 實在搞不懂大家為什麼要用效能奇差的Python去寫了.

下面的程式碼是完全以Java實作出來, 小編試了超久所得到的結果.

請注意下面的代碼中, 藍色的 0x3f 是I2C的位址, 需在樹莓派中使用由如下指令查詢
i2cdetect -y 1

下圖是執行後的結果, 位址為 0x3f

i2c_3

package i2cdemo;

import com.pi4j.component.lcd.LCDTextAlignment;
import com.pi4j.component.lcd.impl.I2CLcdDisplay;
import java.text.SimpleDateFormat;
import java.util.Date;
public class I2cDemo {
    public static final int LCD_ROW_1 = 0;
    public static final int LCD_ROW_2 = 1;
    public static final String DEMO_TITLE = "RaspberryPi 1602";
    public static void main(String[] args) throws Exception {
        // for 1602 LCD + PCF8574 I2C module
        I2CLcdDisplay lcd = new I2CLcdDisplay(2, 16, 1, 0x3f, 3, 0, 1, 2, 7, 6, 5, 4);

        lcd.write(LCD_ROW_1, DEMO_TITLE);
        Thread.sleep(3000);

        lcd.clear();
        Thread.sleep(1000);

        // show characters at specified positions
        lcd.setCursorHome();

        for (int column = 0; column < lcd.getColumnCount(); column++) { lcd.write((byte)0xFF); Thread.sleep(100); } for (int column = lcd.getColumnCount() - 1; column >= 0; column--) {
            lcd.write(LCD_ROW_2, column, (byte)0xFF);
            Thread.sleep(100);
        }

        lcd.setCursorHome();
        for (int column = 0; column < lcd.getColumnCount(); column++) { lcd.write(DEMO_TITLE.charAt(column)); Thread.sleep(100); } for (int column = lcd.getColumnCount() - 1; column >= 0; column--) {
            lcd.write(LCD_ROW_2, column, ' ');
            Thread.sleep(100);
        }

        // show text alignment
        lcd.writeln(LCD_ROW_2, "< LEFT", LCDTextAlignment.ALIGN_LEFT); Thread.sleep(2000); lcd.writeln(LCD_ROW_2, "RIGHT >", LCDTextAlignment.ALIGN_RIGHT);
        Thread.sleep(2000);

        lcd.writeln(LCD_ROW_2, "< CENTER >", LCDTextAlignment.ALIGN_CENTER);
        Thread.sleep(2000);

        // show clock
        SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
        while (true) {
            lcd.writeln(LCD_ROW_2, formatter.format(new Date()), LCDTextAlignment.ALIGN_CENTER);
            Thread.sleep(1000);
        }
    }
}

最後整個實驗照片如下

lcd_all

可攜式測距儀

將超音波測距模組所偵側到的資料, 顯示到LCD上, 就可以作成可攜式的測距儀了. 本程式亦會依距離遠近, 使蜂鳴器發出不同的聲音, 圖片及代碼如下

請注意幾個事項
1. 不可以使用 GpioInterrupt.addListener來偵測Echo針腳的變化. 因為addListener不是RTOS(即時系統),  從偵測事件到開始執行,  可能過了好幾百萬微秒. 而這幾百萬微秒對敏感的音速或光速而言, 都跑了好幾百公尺, 甚至是好幾百公里了. 
2. 寫入LCD會耗費極大的時間, 所以只能有一個執行緒控制LCD.  若將時間及距離用不同的執行緒寫入LCD, 將會錯亂. 

package lcdsonicspeaker;

import com.pi4j.component.lcd.LCDTextAlignment;
import com.pi4j.component.lcd.impl.I2CLcdDisplay;
import com.pi4j.wiringpi.Gpio;
import com.pi4j.wiringpi.GpioInterrupt;
import com.pi4j.wiringpi.GpioInterruptEvent;
import com.pi4j.wiringpi.GpioInterruptListener;
import java.text.SimpleDateFormat;
import java.util.Date;

public class LcdSonicSpeaker {
    public static final int LCD_ROW_1 = 0;
    public static final int LCD_ROW_2 = 1;
    public static final int GPIO_SPEAKER = 0;
    public static final int GPIO_TRIGGER = 4;
    public static final int GPIO_ECHO = 5;
    public static long startTime, endTime;
    public static I2CLcdDisplay lcd;
    public static double distance=1000;
    public static void main(String[] args) {
        try{
            lcd= new I2CLcdDisplay(2, 16, 1, 0x3f, 3, 0, 1, 2, 7, 6, 5, 4);
        }
        catch(Exception e){}
        lcd.clear();
        if (Gpio.wiringPiSetup() == -1) {
            System.out.println(" ==>> GPIO SETUP FAILED");
            return;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        
        //啟動LCD
        //請注意~~~寫入LCD會耗費極大的時間, 所以只能有一個執行緒控制LCD
        //使用一個執行緒寫入時間, 又啟用另一個執行緒寫入距離, 將會錯亂
        //所以時間及距離, 必需在同一個執行緒中完成寫入LCD
        new Thread(()->{
            while(true){
                lcd.writeln(LCD_ROW_1,String.format("Thomas %s", sdf.format(new Date())) , LCDTextAlignment.ALIGN_LEFT);
                lcd.writeln(LCD_ROW_2,String.format("%.1f cm", distance) , LCDTextAlignment.ALIGN_CENTER);
                try{Thread.sleep(100);}catch(InterruptedException e){}
            }
        }).start();
        
        //啟動蜂鳴器
        Gpio.pinMode(GPIO_SPEAKER, Gpio.OUTPUT);
        Gpio.digitalWrite(GPIO_SPEAKER, false);
        new Thread(()->{
            int delay=0;
            while(true){
                if(distance<=10)delay=0;
                else if(distance<=20)delay=100;
                else if(distance<=50)delay=220;
                else if(distance<=100)delay=340;
                else if(distance<=150)delay=460;
                else if(distance<=200)delay=580;
                if(distance<=10){
                    Gpio.digitalWrite(GPIO_SPEAKER, true);
                    try{Thread.sleep(500);}catch(InterruptedException e){}
                }
                else if(distance<=200){ 
                    Gpio.digitalWrite(GPIO_SPEAKER, true); 
                    try{Thread.sleep(delay);}catch(InterruptedException e){} 
                    Gpio.digitalWrite(GPIO_SPEAKER, false); 
                    try{Thread.sleep(200);}catch(InterruptedException e){} 
                } 
                else{ 
                    Gpio.digitalWrite(GPIO_SPEAKER, false); 
                    try{Thread.sleep(200);}catch(InterruptedException e){} 
                } 
            }
        }).start(); 
        //啟動超音波
        Gpio.pinMode(GPIO_TRIGGER, Gpio.OUTPUT);
        Gpio.pinMode(GPIO_ECHO, Gpio.INPUT);
        new Thread(()->{
            while(true){
                Gpio.digitalWrite(GPIO_TRIGGER, true);
                try{Thread.sleep(10);}catch(InterruptedException e){}
                Gpio.digitalWrite(GPIO_TRIGGER, false);

                while(Gpio.digitalRead(GPIO_ECHO)==0){}

                startTime= System.nanoTime();
                while(Gpio.digitalRead(GPIO_ECHO)==1){}
                endTime= System.nanoTime();
                distance=(endTime-startTime)/1000.0/2 * 0.034;
                try{Thread.sleep(100);}catch(InterruptedException e){}
            }
        }).start();
        while(true){
            try{Thread.sleep(500);}catch(InterruptedException e){}
        }
    }
}

lcd_ultrasonic

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *