【Java上位机】(一)串口通信

来源:互联网 发布:软件测试平台 编辑:程序博客网 时间:2024/06/05 09:46

一、串口通信简介

在开发嵌入式系统时常需要PC与单片机通信,其中串口通信最为常用。常见的串行接口有RS-232、USB等。USB的复杂性在简单的通信中显得过于奢侈,所以由美国电子工业协会(EIA)在1970年联合贝尔及众多计算机厂家共同制定的用于串行通信的标准RS-232被广泛用于单片机与PC通信,RS-232是一个全双工的通讯协议,它可以同时进行数据接收和发送的工作。

1 常见的Java串口通信包

Sun公司曾推出过comm2.0.jar和comm3.0.jar。但是由于其不支持64位系统,以及长时间没有更新,所以现在常用RXTX串口通信包。它不仅支持64位多平台系统,而且其API与comm。

2 RXTX串口通信包的安装

下载串口通信包RXTX。•复制 rxtxParallel.dll 到 c:/Program Files/Java/jre1.6.0_01/bin/•复制 rxtxSerial.dll 到 c:/Program Files/Java/jre1.6.0_01/bin/•复制 RXTXcomm.jar 到 c:/Program Files/Java/jre1.6.0_01/lib/ext/

二、串口API方法及属性概览

接口:

CommDriver可负载设备(the loadable device)驱动程序接口的一部分CommPortOwnershipListener传递各种通讯端口的所有权事件ParallelPortEventListener传递并行端口事件SerialPortEventListener传递串行端口事件

类:

CommPort通讯端口CommPortIdentifier通讯端口管理ParallelPort并行通讯端口ParallelPortEvent并行端口事件SerialPortRS-232串行通讯端口SerialPortEvent 串行端口事件

异常类:

NoSuchPortException当驱动程序不能找到指定端口时抛出PortInUseException当碰到指定端口正在使用中时抛出UnsupportedCommOperationException驱动程序不允许指定操作时抛出

类的详细介绍:

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) 打开端口,两个参数:程序名称,延迟时间(毫秒数)

SerialPort类

这个类用于描述一个RS-232串行通信端口的底层接口,它定义了串口通信所需的最小功能集。通过它,用户可以直接对串口进行读、写及设置工作。

SerialPort类中关于串口参数的静态成员变量说明:
DATABITS_5 数据位为5DATABITS_6 数据位为6DATABITS_7 数据位为7 DATABITS_8 数据位为8 PARITY_NONE 空格检验 PARITY_ODD 奇检验 PARITY_EVEN 偶检验 PARITY_MARK 标记检验 PARITY_SPACE 无检验 STOPBITS_1 停止位为1 STOPBITS_2 停止位为2 STOPBITS_1_5 停止位为1.5
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类型的输入流

三、样例代码

import gnu.io.CommPortIdentifier;import gnu.io.NoSuchPortException;import gnu.io.PortInUseException;import gnu.io.SerialPort;import gnu.io.SerialPortEvent;import gnu.io.SerialPortEventListener;import gnu.io.UnsupportedCommOperationException;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.util.Enumeration;import java.util.Timer;import java.util.TimerTask;import java.util.TooManyListenersException;import javax.print.attribute.standard.PrinterMessageFromOperator;import com.sun.glass.ui.TouchInputSupport;public class SerialRead implements SerialPortEventListener{    protected static CommPortIdentifier portid = null;  //通讯端口标识符    protected static SerialPort comPort = null;         //串行端口    protected int BAUD = 9600;  //波特率    protected int DATABITS = SerialPort.DATABITS_8;;  //数据位    protected int STOPBITS = SerialPort.STOPBITS_1;  //停止位    protected int PARITY = SerialPort.PARITY_NONE;  //奇偶检验    private static OutputStream oStream;    //输出流    private static InputStream iStream;     //输入流    /**     * 读取所有串口名字     */     private void listPortChoices() {         CommPortIdentifier portId;         Enumeration en = CommPortIdentifier.getPortIdentifiers();         // iterate through the ports.         while (en.hasMoreElements()) {             portId = (CommPortIdentifier) en.nextElement();             if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {                 System.out.println(portId.getName());             }         }     }     /**      * 设置串口号      */     private void setSerialPortNumber(String port) {         try {             portid = CommPortIdentifier.getPortIdentifier(port);             if(portid.isCurrentlyOwned()){                 System.out.println("端口在使用");             }else{                 comPort = (SerialPort) portid.open(this.getClass().getName(), 1000);             }         } catch (PortInUseException e) {             System.out.println("端口被占用");             e.printStackTrace();         } catch (NoSuchPortException e) {             System.out.println("端口不存在");             e.printStackTrace();         }         try {            iStream = comPort.getInputStream(); //从COM1获取数据            oStream = comPort.getOutputStream();         } catch (IOException e) {                e.printStackTrace();        }        try {            comPort.addEventListener(this);       //给当前串口增加一个监听器            comPort.notifyOnDataAvailable(true);  //当有数据是通知        } catch (TooManyListenersException e) {            e.printStackTrace();        }        try {            //设置串口参数依次为(波特率,数据位,停止位,奇偶检验)            comPort.setSerialPortParams(this.BAUD, this.DATABITS, this.STOPBITS, this.PARITY);        } catch (UnsupportedCommOperationException e) {            System.out.println("端口操作命令不支持");            e.printStackTrace();        }        try {            //# testData            String testData = "1";            oStream.write(testData.getBytes());           // iStream.close();           // comPort.close();        } catch (IOException e) {            e.printStackTrace();        }     }    @Override    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:// 当有可用数据时读取数据,并且给串口返回数据                try {                    StringBuilder buf = new StringBuilder(128);                    while(iStream.available() > 0) {                        System.out.println("接收数据:"+((byte) iStream.read()));                    }                } catch (IOException e) {                }                break;        }    }}

四、总结

在编写单片机端的时候,发送指令之后要加一个延时,等待底层数据传输完后再读取,否则数据会不完整。

Java在串口通信上位机中并不常用,但因其跨平台的通用性,在一些工程应用中也有Java的一席之地。

  由于Sun没有为Linux提供JavaComm的参考实现,人们为java和linux开发了RxTx。后来RxTx被移植到了其他平台。最新版本的RxTx已知可运行在100种以上平台,包括Linux,Windows, Mac OS, Solaris 和其他操作系统。 RxTx可以独立于JavaComm API使用,也可以作为所谓的JavaCommAPI服务者。如果采用后者还需要一个称为JCL的封装包。JCL和RxTx通常与Linux/Java发行版打包在一起,或者JCL完全与代码集成在一起。所以,在一个个地下载他们之前,看一看Linux发行版的CD是值得的。

  由于Sun对JavaComm的有限的支持和不适当的文档,放弃JavaCommAPI,转而直接使用RxTx而不是通过JCL封装包似乎成为了一种趋势。然而RxTx的文档是很稀少的。特别是RxTx开发者喜欢将他们的版本和包内容弄得一团糟(例如使用或未使用集成的JCL)。从1.5版本开始,RxTx包含了公共JavaComm类的替代类。由于法律原因,他们没有在java.comm包中,而是在gnu.io包下。然而现存的两个版本的打包内容有很大差别。

  ·RxTx 2.1  这个版本的RxTx包含了一个完整的代替java.comm的gnu.io包。它应该源自于RxTx 1.5,这是支持gnu.io的起始版本。

  ·RxTx 2.0, 为了能在JavaComm通用版本下有不同的提供者,不同于JavaComm包下的那个。然而,如果你只想用gnu.io替换包,那么你只需要将一个JavaComm应用转换成RxTx应用。

  使用RxTx 2.0作为JavaComm接口的实现将应用移植到RxTx 2.1环境上 上面的第一项在前面已经解释,第二项也相当简单。对于需要将JavaComm应用移植到RxTx 2.1上来的人,只需要将应用源代码中所有对“java.comm”包的引用换成“gnu.io”包,如果原始的JavaComm应用编写恰当,这里就没有其他的事情需要去做。

  在Unix平台上,RxTx2.1甚至提供了工具“contrib/ChangePackage.sh”去在源代码树形结构中执行全局的替换,这样的替换在其他的平台很容易使用支持重构功能的IDE(集成开发环境)来完成。

0 0