Java Embedded (8)Raspberry Pi GPIO 的基礎應用與實作(下) by Michael | CodeData
top

Java Embedded (8)Raspberry Pi GPIO 的基礎應用與實作(下)

分享:

Java Embedded (7)Raspberry Pi GPIO 的基礎應用與實作(上) << 前情

8-1 認識開關零件

前一章已經討論GPIO的基本概念,還有輸出的基本應用與實作。GPIO還可以連接很多可以其它的零件與設備,例如開關或是各種感應器。以行動電話來說,它有可以讓你控制音量與電源的開關,通常也有偵測環境光源亮度與接近的感應器,行動電話根據這些設備與零件的資訊執行相關的動作,例如調整音量的大小,還有根據環境光源的亮度自動調整螢幕的亮度。

Raspberry Pi的GPIO可以像之前討論的作法,把指定的針腳設定為輸出的用途,用來點亮LED或控制其它設備。也可以把指定的針腳設定為輸入的用途,用來讀取開關的狀態,或是感應器回傳的資訊。這一章的內容討論GPIO在輸入方面的基本應用。你要準備這些零件:

  • LED一個
  • 開關兩個
  • 杜邦線(公-母)五條
  • 麵包板連接線(公-公)兩條
  • 電阻(220 ohm)一個
  • 電阻(1K ohm)兩個
  • 電阻(10K ohm)兩個
  • 麵包板一個

這些零件會用在接下來幾個不同階段的練習,剛開始的時候不會用到全部的零件,最後的練習會連接好所有的零件,搭配寫好的應用程式,執行比較複雜一些的工作。

在開始討論之前,可以先認識開關這種零件,生活中的各種裝置都很容易看到它,雖然樣子有很大的差異,不過一個最基本的開關零件會像這樣:

JavaEmbedded_08_01

開關零件當然會有一個可以讓使用者按下與放開的開關,最簡單的開關零件,它的下方會有兩個針腳,按下開關的時候,這兩個針腳會是相通的狀態,放開開關的時候,兩個針腳就不會相通。開關零件有很多種規格,有四個或六個針腳的,不過功用是一樣的,建議購買兩個針腳的開關零件會比較簡單一些。有些比較大形的開關是用來連接電線的,選擇可以直接插在麵包板上的針腳會比較方便。

你可以先瞭解下面這個線路圖,為了讓線路圖看起來比較清楚一些,所以開關沒有插在麵包板上。連接好這個線路與零件以後,按下開關的時候可以點亮LED,放開開關就會關閉LED:

JavaEmbedded_08_02

瞭解開關零件的基本作用以後,後續的討論內容會使用這樣的圖形說明開關零件的連接方式,開關上的小圓圈表示針腳插在麵包板的位置,完成後的功能跟上面線路圖是一樣的:

JavaEmbedded_08_03

另外有一種常見的開關零件是「Tactile push siwtch」,通常稱為輕觸開關或微動開關,下列這個說明的圖形,為了方便說明針腳的功能,所以為它們編製1到4的號碼。1、3和2、4永遠保持連接的狀態,在沒有按下開關的時候,1和2號針腳,還有3和4號針腳都沒有連接:

JavaEmbedded_08_08

按下開關的時候,1和2號針腳,還有3和4號針腳就會連接。依照下面圖型的說明,其實所有針腳都會連接。如果是一般的應用,使用1、2或3、4號針腳就可以了:

JavaEmbedded_08_09

你可以選擇兩個或四個針腳的開關零件,依照上面的說明連接正確的針腳就可以了。

8-2 使用GPIO讀取輸入資訊

Raspberry Pi的GPIO針腳都可以設定為輸入或輸出,之前用來控制LED的作法是輸出的應用。接下來把GPIO針腳設定為輸入,用來讀取開關的狀態。設定為輸入的針腳,可以偵測是否有3.3v的電壓,或是沒有電壓的狀態。

8-2-1 GPIO輸入針腳的連接方式

連接到GPIO輸入針腳的線路連接方式,分為「Pull Down Resistor」與「Pull Up Resistor」兩種。雖然後面的應用都是以Pull Down Resistor為主,不過還是完整的認識它們的作法,就可以應付以後各種不一樣的應用。以使用GPIO讀取開關訊號的應用來說,下面的圖形採用Pull Down Resistor連接方式。開關的兩個針腳連接GPIO的3.3V與接地,並且在接地連接可以保護Raspberry Pi的10K Ohm電阻。再從接地的線路連接到針腳編號12號,並連接1K Ohm電阻。在沒有按下開關的時候,針腳編號12號(GPIO_01)接收到「低電壓」的訊號:

JavaEmbedded_08_10

按下開關以後,針腳編號12號(GPIO_01)接收到「高電壓」的訊號:

JavaEmbedded_08_11

下面的圖形採用Pull Up Resistor連接方式,開關的兩個針腳連接GPIO的3.3V與接地,在3.3V連接可以保護Raspberry Pi的10K Ohm電阻。從3.3V的線路連接到針腳編號12號,並連接1K Ohm電阻。在沒有按下開關的時候,針腳編號12號(GPIO_01)接收到「高電壓」的訊號:

JavaEmbedded_08_12

按下開關以後,針腳編號12號(GPIO_01)接收到「低電壓」的訊號:

JavaEmbedded_08_13

8-2-2 實作讀取開關的應用程式

瞭解GPIO輸入的連接線路方式以後,依照下面的線路圖連接好開關零件,從Raspberyy Pi連接的3.3V電源,在按下按紐的時候會傳送到GPIO_01針腳:

JavaEmbedded_08_04

接下來寫一個簡單的應用程式,程式執行以後,使用者按下開關的時候,會一秒鐘顯示一次「Hello!」訊息,直到放開才會停止:

package mygpio02;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.RaspiPin;

public class MyGPIO02 {

    public static void main(String[] args) {

        System.out.println("MyGPIO02 start...");

        // 建立GPIO控制物件
        final GpioController gpio = GpioFactory.getInstance();

        // 建立控制GPIO_01輸入的物件
        // 第二個參數必須依照線路的連接方式,選擇
        //     「PinPullResistance.PULL_DOWN」或
        //     「PinPullResistance.PULL_UP」
        final GpioPinDigitalInput pin01 = 
                gpio.provisionDigitalInputPin(RaspiPin.GPIO_01, 
                        PinPullResistance.PULL_DOWN);

        int count = 0;

        while (true) {
            // 如果GPIO_01接收到3.3V的電壓
            if (pin01.isHigh()) {
                System.out.println("Hello! " + ++count);
            }

            delay(500);
        }

    }

    private static void delay(int ms) {
        try {
            Thread.sleep(ms);
        }
        catch (InterruptedException e) {
            System.out.println(e.toString());
        }
    }

}

執行這個程式以後,試試看按下與放開開關,不過這個程式並不會停止,如果在連線到Raspberry Pi的視窗執行,可以使用鍵盤按下「Ctrl + C」停止程式;如果在NetBeans使用遠端執行的方式,可以選擇停止開關:

JavaEmbedded_08_05

這是執行應用程式以後顯示的訊息,訊息顯示的次數可能會不一樣:

MyGPIO02 start...
Hello! 1
Hello! 2
Hello! 3
Hello! 4
Hello! 5
Hello! 6
BUILD STOPPED (total time: 34 seconds)

8-2-3 比較不好的連接方式

在需要連接開關的時候,你可能會在網路的資源或書籍,看到這種比較簡單的Pull Down Resister連接方式,把3.3V連接到開關的針腳後,再把GPIO輸入針腳連接到開關的另一個針腳,按下開關的時後讓3.3V傳送到指定的輸入針腳:

JavaEmbedded_08_14

你可以把線路改為上面線路圖的連接方式後,執行之前採用Pull Down Resister作法的應用程式(GPIODemo06),同樣可以正常運作。一般的Raspberry Pi使用者,經常使用這種比較簡化的連接方式,在長時間運作或連接的零件與設備比較多的時候,系統的穩定性就會比較差。在應用程式的測試階段,可以稍微偷懶一些,不過在製作正式的產品時,就不要採用這種簡化的作法。

為了不讓線路圖太複雜,後面的說明會採用這種比較偷懶的方式,建議你依照正式的作法連接線路。

8-4 讀取兩個開關零件

接下來再加入一個連接到GPIO_02的按鈕零件,這個按鈕用來結束應用程式,改良上一個程式的寫法,按下開關的時候離開無窮迴圈。參考下面的線路圖,連接好所有的零件:

JavaEmbedded_08_06

這個按鈕零件可以用來結束應用程式,建立一個新的應用程式,大部份是剛才討論的程式碼,加入判斷第二個按鈕是否按下,如果按下按鈕就會結束應用程式:

package mygpio03;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.RaspiPin;

public class MyGPIO03 {

    public static void main(String[] args) {

        System.out.println("MyGPIO03 start...");

        // 建立GPIO控制物件
        final GpioController gpio = GpioFactory.getInstance();

        // 建立控制GPIO_01輸入的物件
        final GpioPinDigitalInput pin01 = 
                gpio.provisionDigitalInputPin(RaspiPin.GPIO_01, 
                        PinPullResistance.PULL_DOWN);

        // 建立控制GPIO_02輸入的物件
        final GpioPinDigitalInput pin02 = 
                gpio.provisionDigitalInputPin(RaspiPin.GPIO_02, 
                        PinPullResistance.PULL_DOWN);        

        int count = 0;

        while (true) {
            // 如果GPIO_02接收到3.3V的電壓
            if (pin02.isHigh()) {
                break;
            }

            // 如果GPIO_01接收到3.3V的電壓
            if (pin01.isHigh()) {
                System.out.println("Hello! " + ++count);
            }

            delay(500);
        }

        System.out.println("MyGPIO03 bye...");
    }

    private static void delay(int ms) {
        try {
            Thread.sleep(ms);
        }
        catch (InterruptedException e) {
            System.out.println(e.toString());
        }
    }

}

執行這個程式,試試按下與放開連接到GPIO01的按鈕,最後按下連接到GPIO02的按鈕,就可以結束應用程式。這是執行應用程式以後顯示的訊息,Hello訊息的次數可能會不一樣:

MyGPIO03 start...
Hello! 1
Hello! 2
Hello! 3
Hello! 4
Hello! 5
MyGPIO03 bye...

8-5 監聽GPIO輸入事件

如果你已經熟悉Java程式設計,剛才用來監控開關的程式寫法,其實會耗用很多資源。在設計圖形使用者介面應用程式的時候,需要在使用者選擇開關或其它元件時執行一些特定的工作,都會採用註冊監聽(listener)物件的作法,Pi4J在GPIO輸入的應用也提供監聽的功能,你可以為指定的GPIO針腳註冊一個「GpioPinListenerDigital」監聽物件,針腳的狀態改變時,就可以自動執行指定的工作。

接下來的範例不需要修改線路圖,不過應用程式的部份,使用兩個監聽類別監控GPIO01與GPIO02的狀態,修改後的程式碼在執行以後,顯示Hello訊息的部份會不太一樣,按下開關一次會顯示一次訊息,因為監聽類別只能偵測到狀態改變的事件。這是把改為使用GPIO監聽類別作法的程式碼:

package mygpio04;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPin;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;

public class MyGPIO04 {

    public static void main(String[] args) {

        System.out.println("MyGPIO04 start...");

        // 建立GPIO控制物件
        final GpioController gpio = GpioFactory.getInstance();

        // 建立控制GPIO_01輸入的物件
        final GpioPinDigitalInput pin01 = 
                gpio.provisionDigitalInputPin(RaspiPin.GPIO_01, 
                        PinPullResistance.PULL_DOWN);

        // 建立控制GPIO_02輸入的物件
        final GpioPinDigitalInput pin02 = 
                gpio.provisionDigitalInputPin(RaspiPin.GPIO_02, 
                        PinPullResistance.PULL_DOWN);

        // 宣告與建立GPIO_01使用的監聽物件
        GpioPinListenerDigital pin01Listener = new GpioPinListenerDigital() {

            private int count = 0;

            @Override
            public void handleGpioPinDigitalStateChangeEvent(
                    GpioPinDigitalStateChangeEvent event) {

                // 如果GPIO_01接收到3.3V的電壓
                if (event.getState().isHigh()) {
                    System.out.println("Hello! " + ++count);
                }

            }

        };

        // 註冊GPIO_01的監聽物件
        pin01.addListener(pin01Listener);


        // 宣告與建立GPIO_02使用的監聽物件
        GpioPinListenerDigital pin02Listener = new GpioPinListenerDigital() {

            @Override
            public void handleGpioPinDigitalStateChangeEvent(
                    GpioPinDigitalStateChangeEvent event) {
                // 讀取發生事件的GPIO針腳與狀態
                GpioPin pin = event.getPin();
                PinState state = event.getState();
                System.out.println("handleGpioPinDigitalStateChangeEvent: ");
                System.out.println("\t" + pin.getName());
                System.out.println("\t" + state.getName());

                // 如果GPIO_02接收到3.3V的電壓
                if (state.isHigh()) {
                    gpio.shutdown();
                    System.out.println("MyGPIO04 bye...");
                    System.exit(0);
                }

            }

        };

        // 註冊GPIO_02的監聽物件
        pin02.addListener(pin02Listener);

        // 記得要加入這個迴圈,不然程式執行以後就結束了
        while (true) {
            delay(500);
        }

    }

    private static void delay(int ms) {
        try {
            Thread.sleep(ms);
        }
        catch (InterruptedException e) {
            System.out.println(e.toString());
        }
    }

}

執行這個程式,試試按下與放開連接到GPIO01的開關,最後按下連接到GPIO02的開關,同樣可以結束應用程式。這是執行應用程式以後顯示的訊息,Hello訊息的次數可能會不一樣:

MyGPIO04 start...
Hello! 1
Hello! 2
Hello! 3
Hello! 4
Hello! 5
Hello! 6
handleGpioPinDigitalStateChangeEvent: 
    GPIO 2
    HIGH
MyGPIO04 bye...

課程相關的檔案都可以GitHub瀏覽與下載。

http://github.com/macdidi5/JavaEmbedded

後續 >> Java Embedded (9)GPIO的進階應用 – 超音波測距模組

分享:
按讚!加入 CodeData Facebook 粉絲群

相關文章

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

熱門論壇文章

熱門技術文章