Java串口编程

一年半前在jbuilder2006下写过串口通信程序,最近做一个GPS-SMS项目,用到串口通信,在JBUILDER 配置了comm.jar却发现找不到端口,经过几番查找才发现自己配置的路径错了,浪费了不少时间,有必要记下来,防止下次出错,此次还暴露了自己看文章一目十行,走马观花的毛病。

Javax.comm是Sun公司提供的,用于开发平台独立的通讯应用程序的扩展API。(ps:这里javax的x很准确地表明了它是一个扩展包,而不是核心包(core package),但由于历史原因,javax下的并不都是扩展包,比如swing包已经是Java核心架构的一部分了,不过为了与Java1.1编码兼容,仍使用javax.swing。)javax.comm可以访问RS232接口(串口)及有限制地访问IEEE-1284(并口)。

下载
    需要到其官方主页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。
API
在javax.comm下有13个类和接口,分别是
4个接口
CommDriver 可负载设备(the loadable device)驱动程序接口的一部分
CommPortOwnershipListener 传递各种通讯端口的所有权事件
ParallelPortEventListener 传递并行端口事件
SerialPortEventListener 传递串行端口事件
6个类
CommPort 通讯端口
CommPortIdentifier通讯端口管理
ParallelPort 并行通讯端口
ParallelPortEvent 并行端口事件
SerialPort RS-232串行通讯端口
SerialPortEvent 串行端口事件
3个异常类
NoSuchPortException 当驱动程序不能找到指定端口时抛出
PortInUseException 当碰到指定端口正在使用中时抛出
UnsupportedCommOperationException 驱动程序不允许指定操作时抛出
实例
同API一起下载的还有一个examples文件,里面有6个程序。首先看最简单的读、写程序。
读串口的例程

view plaincopy to clipboardprint?
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();  
        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"))  
{  
                    SimpleRead reader = new SimpleRead();  
                }  
            }  
        }  
    }  
    public SimpleRead() {  
        try {  
            serialPort = (SerialPort) portId.open("SimpleReadApp", 2000);  
        } catch (PortInUseException e) {}  
        try {  
            inputStream = serialPort.getInputStream();  
        } catch (IOException e) {}  
    try {  
            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:  
        case SerialPortEvent.OE:  
        case SerialPortEvent.FE:  
        case SerialPortEvent.PE:  
        case SerialPortEvent.CD:  
        case SerialPortEvent.CTS:  
        case SerialPortEvent.DSR:  
        case SerialPortEvent.RI:  
        case SerialPortEvent.OUTPUT_BUFFER_EMPTY:  
            break;  
        case SerialPortEvent.DATA_AVAILABLE:  
            byte[] readBuffer = new byte[20];  
            try {  
                while (inputStream.available() > 0) {  
                    int numBytes = inputStream.read(readBuffer);  
                }  
                System.out.print(new String(readBuffer));  
            } catch (IOException e) {}  
            break;  
        }  
    }  
}
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();
        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"))
{
                    SimpleRead reader = new SimpleRead();
                }
            }
        }
    }
    public SimpleRead() {
        try {
            serialPort = (SerialPort) portId.open("SimpleReadApp", 2000);
        } catch (PortInUseException e) {}
        try {
            inputStream = serialPort.getInputStream();
        } catch (IOException e) {}
    try {
            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:
        case SerialPortEvent.OE:
        case SerialPortEvent.FE:
        case SerialPortEvent.PE:
        case SerialPortEvent.CD:
        case SerialPortEvent.CTS:
        case SerialPortEvent.DSR:
        case SerialPortEvent.RI:
        case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
            break;
        case SerialPortEvent.DATA_AVAILABLE:
            byte[] readBuffer = new byte[20];
            try {
                while (inputStream.available() > 0) {
                    int numBytes = inputStream.read(readBuffer);
                }
                System.out.print(new String(readBuffer));
            } catch (IOException e) {}
            break;
        }
    }
}
(PS:不推荐Thread的这种用法,详见《Core Java VolumeII》)
写串口的例程
    把字符串"Hello, world!\n"写到系统的第一个串口
view plaincopy to clipboardprint?
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) {}  
                }  
            }  
        }  
    }  
}
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数据流对象,控制缓冲区大小,调整输入的处理。

============================================================
view plaincopy to clipboardprint?
public SerialReader(HashMap params) {  
serialParams = params;  
init();  


}  

private void init() {  
try {  
// 参数初始化  
int timeout = Integer.parseInt(serialParams.get(PARAMS_TIMEOUT).toString());  
int rate = Integer.parseInt(serialParams.get(PARAMS_RATE).toString());  
int dataBits = Integer.parseInt(serialParams.get(PARAMS_DATABITS).toString());  
int stopBits = Integer.parseInt(serialParams.get(PARAMS_STOPBITS).toString());  
int parity = Integer.parseInt(serialParams.get(PARAMS_PARITY).toString());  
delayRead = Integer.parseInt(serialParams.get(PARAMS_DELAY).toString());  

String port = serialParams.get(PARAMS_PORT).toString();  

// 打开端口  
portId = CommPortIdentifier.getPortIdentifier(port);  
serialPort = (SerialPort) portId.open("SerialReader", timeout);  
inputStream = serialPort.getInputStream();  
serialPort.addEventListener(this);  
serialPort.notifyOnDataAvailable(true);  
serialPort.setSerialPortParams(rate, dataBits, stopBits, parity);  

} catch (PortInUseException e) {  
System.out.println("端口已经被占用!");  
e.printStackTrace();  
} catch (TooManyListenersException e) {  
System.out.println("端口监听者过多!");  
e.printStackTrace();  
} catch (UnsupportedCommOperationException e) {  
System.out.println("端口操作命令不支持!");  
e.printStackTrace();  
} catch (NoSuchPortException e) {  
System.out.println("端口不存在!");  
e.printStackTrace();  
} catch (IOException e) {  
e.printStackTrace();  
}  
Thread readThread = new Thread(this);  
readThread.start();  
}  


public void run() {  
try {  
Thread.sleep(100);  
} catch (InterruptedException e) {  
}  
}  


public void serialEvent(SerialPortEvent event) {  
try {  
// 等待1秒钟让串口把数据全部接收后在处理  
Thread.sleep(delayRead);  
System.out.print("serialEvent[" + event.getEventType() + "]    ");  
} catch (InterruptedException e) {  
e.printStackTrace();  
}  

switch (event.getEventType()) {  

case SerialPortEvent.BI: // 10  
case SerialPortEvent.OE: // 7  
case SerialPortEvent.FE: // 9  
case SerialPortEvent.PE: // 8  
case SerialPortEvent.CD: // 6  
case SerialPortEvent.CTS: // 3  
case SerialPortEvent.DSR: // 4  
case SerialPortEvent.RI: // 5  
case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2  
break;  
case SerialPortEvent.DATA_AVAILABLE: // 1  
try {  
   // 多次读取,将所有数据读入  
   // while (inputStream.available() > 0) {  
   // numBytes = inputStream.read(readBuffer);  
   // }  
   numBytes = inputStream.read(readBuffer);  
   changeMessage(readBuffer, numBytes);  
} catch (IOException e) {  
   e.printStackTrace();  
}  
break;  
}  
}  

// 通过observer pattern将收到的数据发送给observer  
// 将buffer中的空字节删除后再发送更新消息,通知观察者  
public void changeMessage(byte[] message, int length) {  
setChanged();  
byte[] temp = new byte[length];  
System.arraycopy(message, 0, temp, 0, length);  
// System.out.println("msg[" + numBytes + "]: [" + new String(temp) + "]");  
notifyObservers(temp);  
}  

static void listPorts() {  
Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();  
while (portEnum.hasMoreElements()) {  
CommPortIdentifier portIdentifier = (CommPortIdentifier) portEnum.nextElement();  
System.out.println(portIdentifier.getName() + " - "
    + getPortTypeName(portIdentifier.getPortType()));  
}  
}  

static String getPortTypeName(int portType) {  
switch (portType) {  
case CommPortIdentifier.PORT_I2C:  
return "I2C";  
case CommPortIdentifier.PORT_PARALLEL:  
return "Parallel";  
case CommPortIdentifier.PORT_RAW:  
return "Raw";  
case CommPortIdentifier.PORT_RS485:  
return "RS485";  
case CommPortIdentifier.PORT_SERIAL:  
return "Serial";  
default:  
return "unknown type";  
}  
}  


public static HashSet<CommPortIdentifier> getAvailableSerialPorts() {  
HashSet<CommPortIdentifier> h = new HashSet<CommPortIdentifier>();  
Enumeration thePorts = CommPortIdentifier.getPortIdentifiers();  
while (thePorts.hasMoreElements()) {  
CommPortIdentifier com = (CommPortIdentifier) thePorts.nextElement();  
switch (com.getPortType()) {  
case CommPortIdentifier.PORT_SERIAL:  
   try {  
    CommPort thePort = com.open("CommUtil", 50);  
    thePort.close();  
    h.add(com);  
   } catch (PortInUseException e) {  

    System.out.println("Port, " + com.getName() + ", is in use.");  

   } catch (Exception e) {  
    System.out.println("Failed to open port " + com.getName() + e);  
   }  
}  
}  
return h;  
}  
public SerialReader(HashMap params) {
serialParams = params;
init();


}

private void init() {
try {
   // 参数初始化
   int timeout = Integer.parseInt(serialParams.get(PARAMS_TIMEOUT).toString());
   int rate = Integer.parseInt(serialParams.get(PARAMS_RATE).toString());
   int dataBits = Integer.parseInt(serialParams.get(PARAMS_DATABITS).toString());
   int stopBits = Integer.parseInt(serialParams.get(PARAMS_STOPBITS).toString());
   int parity = Integer.parseInt(serialParams.get(PARAMS_PARITY).toString());
   delayRead = Integer.parseInt(serialParams.get(PARAMS_DELAY).toString());

   String port = serialParams.get(PARAMS_PORT).toString();

   // 打开端口
   portId = CommPortIdentifier.getPortIdentifier(port);
   serialPort = (SerialPort) portId.open("SerialReader", timeout);
   inputStream = serialPort.getInputStream();
   serialPort.addEventListener(this);
   serialPort.notifyOnDataAvailable(true);
   serialPort.setSerialPortParams(rate, dataBits, stopBits, parity);

} catch (PortInUseException e) {
   System.out.println("端口已经被占用!");
   e.printStackTrace();
} catch (TooManyListenersException e) {
   System.out.println("端口监听者过多!");
   e.printStackTrace();
} catch (UnsupportedCommOperationException e) {
   System.out.println("端口操作命令不支持!");
   e.printStackTrace();
} catch (NoSuchPortException e) {
   System.out.println("端口不存在!");
   e.printStackTrace();
} catch (IOException e) {
   e.printStackTrace();
}
Thread readThread = new Thread(this);
readThread.start();
}


public void run() {
try {
   Thread.sleep(100);
} catch (InterruptedException e) {
}
}


public void serialEvent(SerialPortEvent event) {
try {
   // 等待1秒钟让串口把数据全部接收后在处理
   Thread.sleep(delayRead);
   System.out.print("serialEvent[" + event.getEventType() + "]    ");
} catch (InterruptedException e) {
   e.printStackTrace();
}

switch (event.getEventType()) {

case SerialPortEvent.BI: // 10
case SerialPortEvent.OE: // 7
case SerialPortEvent.FE: // 9
case SerialPortEvent.PE: // 8
case SerialPortEvent.CD: // 6
case SerialPortEvent.CTS: // 3
case SerialPortEvent.DSR: // 4
case SerialPortEvent.RI: // 5
case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2
   break;
case SerialPortEvent.DATA_AVAILABLE: // 1
   try {
    // 多次读取,将所有数据读入
    // while (inputStream.available() > 0) {
    // numBytes = inputStream.read(readBuffer);
    // }
    numBytes = inputStream.read(readBuffer);
    changeMessage(readBuffer, numBytes);
   } catch (IOException e) {
    e.printStackTrace();
   }
   break;
}
}

// 通过observer pattern将收到的数据发送给observer
// 将buffer中的空字节删除后再发送更新消息,通知观察者
public void changeMessage(byte[] message, int length) {
setChanged();
byte[] temp = new byte[length];
System.arraycopy(message, 0, temp, 0, length);
// System.out.println("msg[" + numBytes + "]: [" + new String(temp) + "]");
notifyObservers(temp);
}

static void listPorts() {
Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
while (portEnum.hasMoreElements()) {
   CommPortIdentifier portIdentifier = (CommPortIdentifier) portEnum.nextElement();
   System.out.println(portIdentifier.getName() + " - "
     + getPortTypeName(portIdentifier.getPortType()));
}
}

static String getPortTypeName(int portType) {
switch (portType) {
case CommPortIdentifier.PORT_I2C:
   return "I2C";
case CommPortIdentifier.PORT_PARALLEL:
   return "Parallel";
case CommPortIdentifier.PORT_RAW:
   return "Raw";
case CommPortIdentifier.PORT_RS485:
   return "RS485";
case CommPortIdentifier.PORT_SERIAL:
   return "Serial";
default:
   return "unknown type";
}
}


public static HashSet<CommPortIdentifier> getAvailableSerialPorts() {
HashSet<CommPortIdentifier> h = new HashSet<CommPortIdentifier>();
Enumeration thePorts = CommPortIdentifier.getPortIdentifiers();
while (thePorts.hasMoreElements()) {
   CommPortIdentifier com = (CommPortIdentifier) thePorts.nextElement();
   switch (com.getPortType()) {
   case CommPortIdentifier.PORT_SERIAL:
    try {
     CommPort thePort = com.open("CommUtil", 50);
     thePort.close();
     h.add(com);
    } catch (PortInUseException e) {

     System.out.println("Port, " + com.getName() + ", is in use.");

    } catch (Exception e) {
     System.out.println("Failed to open port " + com.getName() + e);
    }
   }
}
return h;
}

}

---------- 3 -----------------

view plaincopy to clipboardprint?
package serial;  

import java.util.Observable;  
import java.util.Observer;  

class CommDataObserver implements Observer {  
String name;  

public CommDataObserver(String name) {  
this.name = name;  
}  

public void update(Observable o, Object arg) {  
System.out.println("[" + name + "] GetMessage:\n [" + new String((byte[]) arg) + "]");  
}  
}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wind520/archive/2009/01/19/3837036.aspx

你可能感兴趣的:(Java串口编程)