2015年3月5日 星期四

用Java與Arduino的序列阜溝通(使用RXTX)

最近在玩Arduino,研究如何使用Java利用序列阜跟Arduino溝通,找到了幾篇蠻不錯實用的資料:

基本上有兩種常用的方法:
  1. 使用Java Communications,它原本是Sun公司維護的,不過似乎現在已經沒有人再做了,在Oracle網站上只能找到API的說明書但卻沒有下載點。
  2. 使用RXTX,語法跟Java Communications很像但寫法有一點不一樣,使用RXTX可以讓Java使用Serial port(序列阜),達到經由Serial port來傳送資料給Arduino或從Arduino接收資料。
  3. 2016/11/27 更新,第三種方法,使用Ardulink,請參考Ardulink - Arduino的Java控制方案
在這裡,我使用第二種方法,也就是RXTX,RXTX可以在這裡下載,也可從它的RXTX Wiki上進去找,其中也有很多有用的資料,下載完以後,裡面會有兩個dll檔及jar檔,jar的使用方式就跟其它jar使用方式一樣,在編譯器中Add JAR就好,而兩個dll檔,需將它們放到兩處地方:

  1. 為了開發,要放在Java JDK安裝目錄下的bin資料夾下面,參考自
  2. 放在C:\Windows\System32下(當然,是指在Windows平台下)。

上面的提到的資料中,第二個資料是RXTX官方的例子,使用了兩個thread分別執行Serial port的輸入及輸出,使用者可以即時看到接收到的資料和即是的打上資料送出去,需要注意的是,其中這行
serialPort.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
中的57600是Serial port的通訊速率( baud rate),需要自行修改成與Arduino板子中程式所定的通訊速率一樣,例如Arduino程式的
Serial.begin(9600)
中的9600,不然在接收和傳送訊息時會有問題。
因為覺得官方的例子優雅又實用,為了怕以後忘記,特轉載在最底下(57600已改成9600),可配合我寫的Arduino程式(SerialLightLevelControl)用Serial port的方式用電腦打數字進Console中控制LED燈的亮暗程度。


SerialLightLevelControl:
byte ledPin = 6;>

int lightLevel = 0;

char inputLightLevel[4];

byte i;

char tempChr;

byte maxDigit = 3;  //Because atoi() can only hadle number with digit less than 3;

byte maxAnalogOutput=255;



void setup() {

  Serial.begin(9600);

  Serial.println("LED ready.");

}



void loop() {

  //Check if Serial port has message in.

  if (Serial.available()) {

    i = 0; //count reset;

    while ((tempChr = Serial.read()) != '\n') {

      if (tempChr >= '0' && tempChr <= '9' && i < maxDigit) {  //check whether message is a number or not.

        inputLightLevel[i] = tempChr;

        i++;

      }

    }

    inputLightLevel[i] = '\0';

    lightLevel = atoi(inputLightLevel);    //Use atoi() to transfer string or char[] to number.

    if (lightLevel > maxAnalogOutput) lightLevel = maxAnalogOutput;

    Serial.print("Light level : ");

    Serial.println(lightLevel);

  }

  analogWrite(ledPin, lightLevel);

}

RXTX的官方範例:
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class TwoWaySerialComm
{
    public TwoWaySerialComm()
    {
        super();
    }
    
    void connect ( String portName ) throws Exception
    {
        CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
        if ( portIdentifier.isCurrentlyOwned() )
        {
            System.out.println("Error: Port is currently in use");
        }
        else
        {
            CommPort commPort = portIdentifier.open(this.getClass().getName(),2000);
            
            if ( commPort instanceof SerialPort )
            {
                SerialPort serialPort = (SerialPort) commPort;
                serialPort.setSerialPortParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
                
                InputStream in = serialPort.getInputStream();
                OutputStream out = serialPort.getOutputStream();
                
                (new Thread(new SerialReader(in))).start();
                (new Thread(new SerialWriter(out))).start();

            }
            else
            {
                System.out.println("Error: Only serial ports are handled by this example.");
            }
        }     
    }
    
    /** */
    public static class SerialReader implements Runnable 
    {
        InputStream in;
        
        public SerialReader ( InputStream in )
        {
            this.in = in;
        }
        
        public void run ()
        {
            byte[] buffer = new byte[1024];
            int len = -1;
            try
            {
                while ( ( len = this.in.read(buffer)) > -1 )
                {
                    System.out.print(new String(buffer,0,len));
                }
            }
            catch ( IOException e )
            {
                e.printStackTrace();
            }            
        }
    }

    /** */
    public static class SerialWriter implements Runnable 
    {
        OutputStream out;
        
        public SerialWriter ( OutputStream out )
        {
            this.out = out;
        }
        
        public void run ()
        {
            try
            {                
                int c = 0;
                while ( ( c = System.in.read()) > -1 )
                {
                    this.out.write(c);
                }                
            }
            catch ( IOException e )
            {
                e.printStackTrace();
            }            
        }
    }
    
    public static void main ( String[] args )
    {
        try
        {
            (new TwoWaySerialComm()).connect("COM3");
        }
        catch ( Exception e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

1 則留言 :

  1. 你好:

    我用你提供的程式Arduino , Java , RXTX
    1 LED沒會亮,我認為是Arduino無法跑到analogWrite(ledPin, lightLevel)
    2 Arduino的con無法開啟,可能是Java占用吧

    回覆刪除