java串口通訊API說明 java串口通訊2008/09/22 20:24
| java串口通訊API說明 java串口通訊
Java提供了 CommunicationAPI(包含於javax.comm包中)用於通過與機器無關的方式,控制各種外部裝置。Communications API,是標準的Java的擴充部分,它在JavaAPI中是沒有附帶的。因此,必須先在SUN公司網站的Java網站(www.java.sun.com)上下載這個擴充類庫。 1.1Communications API 簡介 Communications API 的核心是抽象的CommPort類及其兩個子類:SerialPort類和ParallePort類。其中,SerialPort類是用於串口通訊的類,ParallePort類是用於並行口通訊的類。CommPort類還提供了常規的通訊模式和方法,例如:getInputStream( )方法和getOutputStream( )方法,專用於與連接埠上的裝置進行通訊。 然而,這些類的構造方法都被有意的設定為非公有的(non-public)。所以,不能直接構造對象,而是先通過靜態CommPortIdentifer.getPortIdentifiers()獲得連接埠列表;再從這個連接埠列表中選擇所需要的連接埠,並調用CommPortIdentifer對象的Open( )方法,這樣,就能得到一個CommPort對象。當然,還要將這個CommPort對象的類型轉換為某個非抽象的子類,表明是特定的通訊裝置。該子類可以是SerialPort類和ParallePort類中的一個。下面將分別對CommPort類,CommPortIdentifier類,串口類SerialPort進行詳細的介紹。 1.2 CommPortIdentifier類 CommPortIdentifier類的方法如下: 方法 說明 addPortName(String, int, CommDriver) 添加連接埠名到連接埠列表裡 addPortOwnershipListener(CommPortOwnershipListener) 添加連接埠擁有的監聽器 removePortOwnershipListener(CommPortOwnershipListener) 移除連接埠擁有的監聽器 getCurrentOwner() 得到當前佔有連接埠的對象或應用程式 getName() 得到連接埠名稱 getPortIdentifier(CommPort) 得到參數開啟的連接埠的CommPortIdentifier類型對象 getPortIdentifier(String) 得到以參數命名的連接埠的CommPortIdentifier類型對象 getPortIdentifiers() 得到系統中的連接埠列表 getPortType() 得到連接埠的類型 isCurrentlyOwned() 判斷當前連接埠是否被佔用 open(FileDescriptor) 用檔案描述的類型開啟連接埠 open(String, int) 開啟連接埠,兩個參數:程式名稱,延遲時間(毫秒數) 1.3 SerialPort類 SerialPort關於串口參數的靜態成員變數 成員變數 說明 成員變數 說明 成員變數 說明 DATABITS_5 資料位元為5 STOPBITS_2 停止位為2 PARITY_ODD 奇檢驗 DATABITS_6 資料位元為6 STOPBITS_1 停止位為1 PARITY_MARK 標記檢驗 DATABITS_7 資料位元為7 STOPBITS_1_5 停止為1.5 PARITY_NONE 空格檢驗 DATABITS_8 資料位元為8 PARITY_EVEN 偶檢驗 PARITY_SPACE 無檢驗 SerialPort對象的關於串口參數的函數 方法 說明 方法 說明 getBaudRate() 得到傳輸速率 getParity() 得到檢驗類型 getDataBits() 得到資料位元數 getStopBits() 得到停止位元 setSerialPortParams(int, int, int, int) 設定串口參數依次為(傳輸速率,資料位元,停止位,奇偶檢驗) SerialPort關於事件的靜態成員變數 成員變數 說明 成員變數 說明 BI Break interrupt中斷 FE Framing error錯誤 CD Carrier detect載波偵聽 OE Overrun error錯誤 CTS Clear to send清除以傳送 PE Parity error奇偶檢驗錯誤 DSR Data set ready資料備妥 RI Ring indicator響鈴偵測 DATA_AVAILABLE 串口中的可用資料 OUTPUT_BUFFER_EMPTY 輸出緩衝區空 SerialPort中關於事件的方法 方法 說明 方法 說明 方法 說明 isCD() 是否有載波 isCTS() 是否清除以傳送 isDSR() 資料是否備妥 isDTR() 是否資料端備妥 isRI() 是否響鈴偵測 isRTS() 是否要求傳送 addEventListener(SerialPortEventListener) 向SerialPort對象中添加串口事件監聽器 removeEventListener() 移除SerialPort對象中的串口事件監聽器 notifyOnBreakInterrupt(boolean) 設定中斷事件true有效,false無效 notifyOnCarrierDetect(boolean) 設定載波監聽事件true有效,false無效 notifyOnCTS(boolean) 設定清除發送事件true有效,false無效 notifyOnDataAvailable(boolean) 設定串口有資料的事件true有效,false無效 notifyOnDSR(boolean) 設定資料備妥事件true有效,false無效 notifyOnFramingError(boolean) 設定發生錯誤事件true有效,false無效 notifyOnOutputEmpty(boolean) 設定發送緩衝區為空白事件true有效,false無效 notifyOnParityError(boolean) 設定發生奇偶檢驗錯誤事件true有效,false無效 notifyOnRingIndicator(boolean) 設定響鈴偵測事件true有效,false無效 getEventType() 得到發生的事件類型傳回值為int型 sendBreak(int) 設定中斷過程的時間,參數為毫秒值 setRTS(boolean) 設定或清除RTS位 setDTR(boolean) 設定或清除DTR位 SerialPort中的其他常用方法 方法 說明 close() 關閉串口 getOutputStream() 得到OutputStream類型的輸出資料流 getInputStream() 得到InputStream類型的輸入資料流 |
四:執行個體
一:下載
需要到其官方首頁http://java.sun.com/products/javacomm/下載這個API,目前的最新版本是3.0。不過可惜的是,Sun目前沒有推出此API在Windows平台下的3.0版本,首頁上列出的三個版本,分別是運行在x86和Sparc結構下的Solaris系統,以及x86下的Linux系統。要下載Windows版本只能去尋找較老的版本了。我所找到的2個網址是http://llk.media.mit.edu/projects/cricket/software/javaSerial.zip(兩個檔案夾裡面有所需的3個檔案),http://mdubuc.freeshell.org/Jolt/javacomm20-win32.zip和(完整的2.0版本,還有examples)。
二:安裝
這裡的所謂安裝就是把三個重要的檔案放到指定的目錄下。
將下載的檔案解壓縮後,在/javacomm20-win32/commapi目錄下有必需的三個檔案comm.jar,javax.comm. properties和win32comm.dll。將檔案comm.jar拷貝到%JAVA_HOME%/jre/lib/ext;檔案javax.comm. properties拷貝到%JAVA_HOME%/jre/lib; 檔案win32comm.dll拷貝到%JAVA_HOME%/bin。注意%JAVA_HOME%是jdk的路徑,而非jre。
首先看最簡單的讀、寫程式。
讀串口的常式
import java.io.*;
import java.util.*;
import javax.comm.*;
public class SimpleRead implements Runnable, SerialPortEventListener {
static CommPortIdentifier portId;
//枚舉類
static Enumeration portList;
InputStream inputStream;
SerialPort serialPort;
Thread readThread;
public static void main(String[] args) {
portList = CommPortIdentifier.getPortIdentifiers();
/*不帶參數的getPortIdentifiers方法獲得一個枚舉對象,該對象又包含了系統中管理每個連接埠的CommPortIdentifier對象。
注意這裡的連接埠不僅僅是指串口,也包括並口。這個方法還可以帶參數。getPortIdentifiers(CommPort)獲得與已經被應
用程式開啟的連接埠相對應的CommPortIdentifier對象。getPortIdentifier(String portName)擷取指定連接埠名(比如“COM1”)
的CommPortIdentifier對象。*/
while (portList.hasMoreElements()) {
portId = (CommPortIdentifier) portList.nextElement();
/*getPortType方法返回連接埠類型*/
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
/* 找Windows下的第一個串口*/
if (portId.getName().equals("COM1")) {
/*找Unix-like系統下的第一個串口*/
//if (portId.getName().equals("/dev/term/a")) {
SimpleRead reader = new SimpleRead();
}
}
}
}
public SimpleRead() {
try {
/* open方法開啟通訊連接埠,獲得一個CommPort對象。它使程式獨佔連接埠。如果連接埠正被其他應用程式佔用,將使用
CommPortOwnershipListener事件機制,傳遞一個PORT_OWNERSHIP_REQUESTED事件。每個連接埠都關聯一個
InputStream和一個OutputStream。如果連接埠是用open方法開啟的,那麼任何的getInputStream都將返回
相同的資料流對象,除非有close被調用。有兩個參數,第一個為應用程式名稱;第二個參數是在連接埠開啟
時阻塞等待的毫秒數。 */
serialPort = (SerialPort) portId.open("SimpleReadApp", 2000);
} catch (PortInUseException e) {}
try {
/*擷取連接埠的輸入資料流對象*/
inputStream = serialPort.getInputStream();
} catch (IOException e) {}
try {
/*註冊一個SerialPortEventListener事件來監聽串口事件*/
serialPort.addEventListener(this);
} catch (TooManyListenersException e) {}
/*資料可用*/
serialPort.notifyOnDataAvailable(true);
try {
/*設定串口初始化參數,依次是傳輸速率,資料位元,停止位和校正*/
serialPort.setSerialPortParams(9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {}
readThread = new Thread(this);
readThread.start();
}
public void run() {
try {
Thread.sleep(20000);
} catch (InterruptedException e) {}
}
//串口事件
public void serialEvent(SerialPortEvent event) {
switch(event.getEventType()) {
case SerialPortEvent.BI:/*Break interrupt,通訊中斷*/
case SerialPortEvent.OE:/*Overrun error,溢位錯誤*/
case SerialPortEvent.FE:/*Framing error,傳幀錯誤*/
case SerialPortEvent.PE:/*Parity error,校正錯誤*/
case SerialPortEvent.CD:/*Carrier detect,偵測載波*/
case SerialPortEvent.CTS:/*Clear to send,清除發送*/
case SerialPortEvent.DSR:/*Data set ready,資料裝置就緒*/
case SerialPortEvent.RI:/*Ring indicator,響鈴指示*/
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:/*Output buffer is empty,輸出緩衝區清空*/
break;
case SerialPortEvent.DATA_AVAILABLE:/*Data available at the serial port,連接埠有可用資料。讀到緩衝數組,輸出到終端*/
byte[] readBuffer = new byte[20];
char[] readChar = new char[20];
String readStr="";
int numBytes=0;
try {
while (inputStream.available() > 0) {
numBytes= inputStream.read(readBuffer);
}
for(int iii=0;iii<numBytes;iii++){
readStr=readStr + Byte.toString(readBuffer[iii]);
}
System.out.println(readStr.length());
System.out.println(readStr);
} catch (IOException e) {}
break;
}
}
}
寫串口的常式
import java.io.*;
import java.util.*;
import javax.comm.*;
public class SimpleWrite {
static Enumeration portList;
static CommPortIdentifier portId;
static String messageString = "Hello, world!/n";
static SerialPort serialPort;
static OutputStream outputStream;
public static void main(String[] args) {
portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
portId = (CommPortIdentifier) portList.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
if (portId.getName().equals("COM1")) {
//if (portId.getName().equals("/dev/term/a")) {
try {
serialPort = (SerialPort)
portId.open("SimpleWriteApp", 2000);
} catch (PortInUseException e) {}
try {
outputStream = serialPort.getOutputStream();
} catch (IOException e) {}
try {
serialPort.setSerialPortParams(9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {}
try {
outputStream.write(messageString.getBytes());
} catch (IOException e) {}
}
}
}
}
}
上面兩個常式都經過了簡化,在開啟連接埠,並且傳輸結束後沒有關閉資料流和串口。在常式中我們看
到CommPortIdentifier提供了開啟通訊連接埠的方法open,但卻沒有相應關閉連接埠的方法,關閉連接埠需要調
用javax.comm.CommPort類的close()。CommPort是這個包中的一個進階抽象,它定義了連接埠可作的各種事
情:擷取I/O資料流對象,控制緩衝區大小,調整輸入的處理。