2012-07-19 54 views
0

我跟着Interfacing with Java tutorial,但遇到了一些測試問題。目前我的Arduino程序工作正常,當我嘗試手動輸入。Arduino與Java的接口問題

在Arduino的C代碼段:

char line[20]; 
int line_pos = 0; 
char action[10]; 
unsigned long duration; 
boolean data_ready = false; 

void setup() 
{ 
    Serial.begin(9600); 
    delay(1500); 
    Serial.println("Ready!"); 
} 

void loop() 
{ 
char state; 
if(Serial.available()>0) 
{ 
    delay(20); 
    state = Serial.read(); 

    if(state == '!') 
    { 
     data_ready = true; 
     line[line_pos] = state; 
     line_pos = 0; 
    } 
    else 
    { 
     line[line_pos] = state; 
     line_pos = line_pos + 1; 
    } 

    if(data_ready == true) 
    { 
     split(line); 
     Serial.print(action); 
     delay(20); 
     Serial.print("!"); 
     delay(20); 
     Serial.print(duration); 
     delay(20); 
     Serial.print("!"); 

     Serial.println("Data has been split"); 

     if(strcmp(action, "left") == 0) 
     { 
      Serial.println("Received left"); 
     } 
     else if(strcmp(action, "right") == 0) 
     { 
      Serial.println("Received rightt"); 
     } 
     else if(strcmp(action, "straight") == 0) 
     { 
      Serial.println("Received straight"); 
     } 

     memset(line, 0, 20); 
     data_ready = false; 
    } 
    } 
} 

void split(char input[20]) 
{ 
char *param, *ptr; 

param = strtok_r(input, "#", &ptr); 
strncpy(action, param, sizeof(action)); 
action[sizeof(action)-1] = '\0'; 

param = strtok_r(NULL, "!", &ptr); 
duration = strtoul(param, &param, 10); 
} 

當我輸入 「左#123」!我在COM中得到了如預期的那樣輸出。這裏沒有問題:

準備就緒! ! 留下123數據已拆分 接收的左

現在,這裏是我的Java代碼:

import java.io.InputStream; 
import java.io.OutputStream; 
import gnu.io.CommPortIdentifier; 
import gnu.io.SerialPort; 
import gnu.io.SerialPortEvent; 
import gnu.io.SerialPortEventListener; 
import java.util.Enumeration; 

public class SerialTest implements SerialPortEventListener { 
    SerialPort serialPort; 
     /** The port we're normally going to use. */ 
    private static final String PORT_NAMES[] = { 
      "/dev/tty.usbserial-A9007UX1", // Mac OS X 
      "/dev/ttyUSB0", // Linux 
     "COM3", // Windows 
     }; 
/** Buffered input stream from the port */ 
private InputStream input; 
/** The output stream to the port */ 
private OutputStream output; 
/** Milliseconds to block while waiting for port open */ 
private static final int TIME_OUT = 2000; 
/** Default bits per second for COM port. */ 
private static final int DATA_RATE = 9600; 

private String display = ""; 

public void initialize() { 
    CommPortIdentifier portId = null; 
    Enumeration portEnum = CommPortIdentifier.getPortIdentifiers(); 

    // iterate through, looking for the port 
    while (portEnum.hasMoreElements()) { 
     CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement(); 
     for (String portName : PORT_NAMES) { 
      if (currPortId.getName().equals(portName)) { 
       portId = currPortId; 
       break; 
      } 
     } 
    } 

    if (portId == null) { 
     System.out.println("Could not find COM port."); 
     return; 
    } 

    try { 
     // open serial port, and use class name for the appName. 
     serialPort = (SerialPort) portId.open(this.getClass().getName(), 
       TIME_OUT); 

     // set port parameters 
     serialPort.setSerialPortParams(DATA_RATE, 
       SerialPort.DATABITS_8, 
       SerialPort.STOPBITS_1, 
       SerialPort.PARITY_NONE); 

     // open the streams 
     input = serialPort.getInputStream(); 
     output = serialPort.getOutputStream(); 

     // add event listeners 
     serialPort.addEventListener(this); 
     serialPort.notifyOnDataAvailable(true); 
    } catch (Exception e) { 
     System.err.println(e.toString()); 
    } 
} 

/** 
* This should be called when you stop using the port. 
* This will prevent port locking on platforms like Linux. 
*/ 
public synchronized void close() { 
    if (serialPort != null) { 
     serialPort.removeEventListener(); 
     serialPort.close(); 
    } 
} 

/** 
* Handle an event on the serial port. Read the data and print it. 
*/ 
public synchronized void serialEvent(SerialPortEvent oEvent) { 
    if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { 
     try { 
      int available = input.available(); 
      byte chunk[] = new byte[available]; 
      input.read(chunk, 0, available); 

      System.out.println(display); 

      display += (new String(chunk)).trim(); 
      if(display.contains("!")) 
      { 
       display = display.substring(0, display.indexOf("!")); 

       if(display.equals("Ready")) 
       { 
        String reply = "left#123!"; 
        byte reply_byte[] = new byte[reply.length()]; 
        reply_byte = reply.getBytes("UTF-16LE"); 
        output.write(reply_byte); 
       } 

       display = ""; 
      } 

     } catch (Exception e) { 
      System.err.println(e.toString()); 
     } 
    } 
    // Ignore all the other eventTypes, but you should consider the other ones. 
} 

public static void main(String[] args) throws Exception { 
    SerialTest main = new SerialTest(); 
    main.initialize(); 
    System.out.println("Started"); 
} 
} 

下面是Java代碼控制檯打印出:

雷亞 升數據 Datahas Datahasbee Datahasbeen sp Datahasbeen拆分

串行輸入似乎不流暢地讀取,但在重複部分。任何人都可以幫助我診斷問題並給我一個解決方案嗎?

回答

1

這裏至少有兩點值得注意,但這是基於我對Java以外語言的體驗,所以它可能不會以完全相同的方式表現。

首先,事件看起來像是在少量字符後被觸發,也許你的Arduino發送速度不夠快,一次只能顯示一次。這將導致您的Java代碼重複輸出,因爲您正在打印display,然後將新的chunk添加到它。如果你沒有找到感嘆號,它永遠不會被清除。你可能會更好打印chunk來看看你收到了什麼。

第二個是你可能只接收新數據的事件,所以如果新數據在事件被觸發和你打電話給input.read()之間,那麼另一個事件不會被觸發。您最好在您的事件處理程序中有一個循環,但仍有數據可用,例如:

public synchronized void serialEvent(SerialPortEvent oEvent) { 
    if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { 
     try { 
      int available = input.available(); 
      while (available > 0) 
      { 
       byte chunk[] = new byte[available]; 
       input.read(chunk, 0, available); 

       System.out.println(new String(chunk)); 

       // Perform your packet processing here 

       // See if there is any more data that came in while we were 
       // processing the event 
       available = input.available(); 
      } 

     } catch (Exception e) { 
      System.err.println(e.toString()); 
     } 
    } 
    // Ignore all the other eventTypes, but you should consider the other ones. 
} 
+0

謝謝。如何在處理事件時檢查是否有新數據進入?我怎麼知道這個新數據是不是重複舊數據? – ask 2012-07-20 02:19:02

+0

@ask:使用循環檢查新數據,調用'input.available()'並處理,直到它讀取爲零。它不會重複舊數據,因爲當您調用'input.read()'時,您讀取的字節數將從輸入中提取,因此下次不會讀取它們。 – tinman 2012-07-20 07:57:04

+0

得到它的工作。但是使用了一個if語句,而不是一個while循環。每當一個字節到達時,就會調用serialEvent函數。 – ask 2012-07-31 04:53:37