Java串口编程...【Pnoker】

一年半前在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个程序。首先看最简单的读、写程序。
读串口的例程

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(); 
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL)/*getPortType方法返回 端口类型*/ { 
                // if (portId.getName().equals("COM1"))/* 找Windows下的第一个串口*/ { 
                if (portId.getName().equals("/dev/term/a"))/*找Unix-like系统下的第一个串口*/ 
{ 
                    SimpleRead reader = new SimpleRead(); 
                } 
            } 
        } 
    } 
    public SimpleRead() { 
        try { 
            serialPort = (SerialPort) portId.open("SimpleReadApp", 2000);/* open方法打开通讯 端口,获得一个CommPort对象。它使程序独占端口。如果端口正被其他应用程序占用,将使用 CommPortOwnershipListener事件机制,传递一个PORT_OWNERSHIP_REQUESTED事件。每个端口都关联一个 InputStream 何一个OutputStream。如果端口是用open方法打开的,那么任何的getInputStream都将返回 相同的数据流对象,除非有close被调用。有两个参数,第一个为应用程序名;第二个参数是在端口打开 时阻塞等待的毫秒数。*/ 
        } catch (PortInUseException e) {} 
        try { 
            inputStream = serialPort.getInputStream();/*获取端口的输入流对象*/ 
        } catch (IOException e) {} 
    try { 
            serialPort.addEventListener(this);/*注册一个SerialPortEventListener事件来监听串 口事件*/ 
    } 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]; 
            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”写到系统的第一个串口

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数据流对象,控制缓冲区大小,调整输入的处理。

你可能感兴趣的:(java,编程,windows,swing,JBuilder)