浅谈java串口编程

日期:2013-10-18点击次数:10123

1. 什么是串口通信
       串口通信分很多种,像RS232,RS485,RS422,甚至usb等都是用串行接口协议,由于物联网以及系统集成的高速发展,和硬件的通信也越来越频繁,所以串口通信得到很广泛的应用,pc机刚刚兴起的时候,人们用一条串行线来共享两台pc机之间的数据,虽然串口协议很多,但是目前以RS232协议的居多,是一个全双工的通讯协议,它可以同时进行数据接收和发送的工作。RS232的端口通常有两种:9针(DB9)和25针(DB25)。

2. RS232常用针脚说明:

 常见的连接方式是三线连接方式,是将两个RS232设备的发送端(TXD)和接收端(RXD)及接地端(GND)互相连接,如下表:

如果这样连接,设备不生效,那是因为有些设备,内部将2,3对掉了,只要2,3,5(7)一一对应连接即可。
 

3.Java串口介绍

        3.1 常见的java串口包介绍:

        常见的Java串口包有SUN在1998年发布的串口通信API:comm2.0.jar(Windows下)、comm3.0.jar(Linux/Solaris);IBM的串口通信API以及一个开源的实现。鉴于在Windows下SUN的API比较常用以及IBM的实现和SUN的在API层面都是一样的,所以,这里就只介绍SUN的串口通信API在Windows平台下的使用, Java提供了 CommunicationAPI(包含于javax.comm包中)用于通过与机器无关的方式,控制各种外部设备。Communications API,是标准的Java的扩展部分,它在JavaAPI中是没有附带的.
 

        3.2 Java串口编程环境准备:
       到SUN的网站下载javacomm20-win32.zip,把压缩文件解压,按照其使用说明(Readme.html)的说法,要想使用串口包进行串口通信,除了设置好环境变量之外,还要将win32com.dll复制到<JDK>/bin目录下;将comm.jar复制到<JDK>/lib;把javax.comm.properties也同样拷贝到<JDK>/lib目录下。然而在真正运行使用串口包的时候,仅作这些是不够的。因为通常当运行“java MyApp”的时候,是由JRE下的虚拟机启动MyApp的。而我们只复制上述文件到JDK相应目录下,所以应用程序将会提示找不到串口。解决这个问题的方法很简单,我们只须将上面提到的文件放到JRE相应的目录下就可以了。

        3.3 Communications API 简介      
       Communications API 的核心是抽象的CommPort类,CommPort是用于描述一个被底层系统支持的端口的抽象类。它包含一些高层的IO控制方法,这些方法对于所有不同的通讯端口来说是通用的。CommPort有两个子类:SerialPort类和ParallePort类其中,SerialPort类是用于串口通信的类,ParallePort类是用于并行口通信的类。CommPort类还提供了常规的通信模式和方法,例如:getInputStream( )方法和getOutputStream( )方法,专用于与端口上的设备进行通信。

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

        3.5 SerialPort类

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

        3.5.1 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 无检验
 

        3.5.2 SerialPort对象的关于串口参数的函数

        getBaudRate() 得到波特率
        getParity() 得到检验类型
        getDataBits() 得到数据位数
        getStopBits() 得到停止位数
        setSerialPortParams(int, int, int, int)设置串口参数依次为(波特率,数据位,停止位,奇偶检验)
 

        3.5.3 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 输出缓冲区空
 

        3.5.4 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位
 

        3.5.5 SerialPort中的其他常用方法

        close() 关闭串口
        getOutputStream() 得到OutputStream类型的输出流
        getInputStream() 得到InputStream类型的输入流
       
        3.6 Java串口API方法介绍

           3.6.1 列举系统所有可用端口,并打印

Enumeration En = Commportidentifier.Getportidentifiers();
Commportidentifier Portid;
While (En.Hasmoreelements())
{

Portid = (Commportidentifier) En.Nextelement();
 

      /*如果端口类型是串口,则打印出其端口信息*/

If (Portid.Getporttype() == Commportidentifier.Port_Serial)
{

 System.Out.Println(Portid.Getname());
}
}

 

CommPortIdentifier类的getPortIdentifiers方法可以找到系统所有的串口,每个串口对应一个CommPortIdentifier类的实例。
        3.6.2 打开端口

 Try{
Commport Serialport = Portid.Open("My App", 60);
/* 从端口中读取数据*/
 Inputstream Input = Serialport.Getinputstream();
Input.Read(...);
/*
往端口中写数据*/
Outputstream Output = Serialport.Getoutputstream();
Output.Write(...)

 ...
}Catch(Portinuseexception Ex)
{ ... }
 CommPortIdentifier的open方法可以返回一个CommPort对象。open方法有两个参数,第一个是String,通常设置为你的应用程序的名字。第二个参数是时间,即开启端口超时的毫秒数。当端口被另外的应用程序占用时,将抛出PortInUseException异常。CommPortIdentifier类和CommPort类是一一对应的关系,CommPortIdentifier主要负责端口的初始化和开启,以及管理它们的占有权。而CommPort则是跟实际的输入和输出功能有关的。通过CommPort的getInputStream()可以取得端口的输入流,它是java.io.InputStream接口的一个实例。我们可以用标准的InputStream的操作接口来读取流中的数据,就像通过FileInputSteam读取文件的内容一样。相应的,CommPort的getOutputStream可以获得端口的输出流,这样就可以往串口输出数据了。
 

        3.6.3 关闭端口

        使用完的端口,必须记得将其关闭,这样可以让其它的程序有机会使用它,不然其它程序使用该端口时可能会抛出端口正在使用中的错误。很奇怪的是,CommPortIdentifier类只提供了开启端口的方法,而要关闭端口,则要调用CommPort类的close()方法。
 

        3.6.4 通信方式

        CommPort的输入流的读取方式与文件的输入流有些不一样,你可能永远不知这个InputStream何时结束,除非对方的OutputStream向你发送了一个特定数据表示发送结束,你收到这个特定字符后,再行关闭你的InputStream。而comm.jar提供了两种灵活的方式让你读取数据。

        3.6.4.1 轮询方式(Polling)


 Public Class Testport Extend Thread
{
...
Inputstream Input = Serialport.Getinputstream();
Stringbuffer Buf = New Stringbuffer();
Boolean Stopped = False;
...
Public Void Run()
{
Try {
While( !Stopped )
Int ch = Input.Read();
If ( ch==''q'' || ch==''Q'' )
{
/* 结束读取,关闭端口...*/
Stopped = True;
...
}
Else
{

Buf.Append((Char)ch);
...
}
}Catch (Interruptedexception E) { }}
}


 

       3.6.4.2 .监听方式(listening)
 首先你必须先取得CommPortIdentifier类的一个实例,
Commport Serialport = Portid.Open("My App", 60);
从而取得SerialPort,再调用它的addEventListener方法为它添加监听器,
Serialport.Addeventlistener(New Myportlistener());
SerialPort的监听器必须继承于SerialPortEventListener接口。当有任何SerialPort的事件发生时,将自动调用监听器中的serialEvent方法。Serial Event有以下几种类型:
BI - 通讯中断.
CD - 载波检测.
CTS - 清除发送.
DATA_AVAILABLE - 有数据到达.
DSR - 数据设备准备好.
FE - 帧错误.
OE - 溢位错误.
OUTPUT_BUFFER_EMPTY - 输出缓冲区已清空.
PE - 奇偶校验错.
RI -  振铃指示.
监听方式小例子:
Public Void Myportlistener Implements Serialporteventlistener
{
Public Void Serialevent(Serialportevent Evt)
{ Switch (Evt.Geteventtype())
{ Case Serialportevent.Cts :
System.Out.Println("Cts Event Occured.");
Break; Case Serialportevent.Cd :
System.Out.Println("Cd Event Occured.");
Break; Case Serialportevent.Bi :
System.Out.Println("Bi Event Occured.");
Break; Case Serialportevent.Dsr :
System.Out.Println("Dsr Event Occured.");
Break; Case Serialportevent.Fe :
System.Out.Println("Fe Event Occured.");
Break; Case Serialportevent.Oe :
System.Out.Println("Oe Event Occured.");
Break; Case Serialportevent.Pe :
System.Out.Println("Pe Event Occured.");
Break; Case Serialportevent.Ri :
System.Out.Println("Ri Event Occured.");
Break; Case Serialportevent.Output_Buffer_Empty :
System.Out.Println("Output_Buffer_Empty Event Occured.");
Break; Case Serialportevent.Data_Available :
System.Out.Println("Data_Available Event Occured.");
Int ch;
Stringbuffer Buf = New Stringbuffer();
 Inputstream Input = Serialport.Getinputstream;
Try {
While ( (ch=Input.Read()) > 0) {
Buf.Append((Char)ch);
}
System.Out.Print(Buf);
} Catch (Ioexception E) {}
Break;
}}
}

       3.7 Java串口编程主要步骤:

 *获得串口标识
*打开串口
*设置串行端口的通信参数
*获得输入输出流
*进行读写操作

       3.7.1 获得串口标识

 Commportidentifier Portid=Null;
Try{
 Portid= Commportidentifier.Getportidentifier(“Com3”);
}Catch(Nosuchportexception E){
 E.Printstacktrace();
}
       3.7.2 打开串口

 Try{
  Port=(Serialport)Portid.Open(“My App”,5000);
}Catch(Portinuseexception E){
 E.Printstacktrace();
}

       3.7.3 设置串行端口的通信参数

 Try{
 Port.Setserialportparams(9600,Serialport.Databits_8, Serialport.Stipbits_1, Serialport.Parity_None);
 Port.Setflowcontrolmode(Serialport.Flowcontrol_None);
}Catch(Unsupportedcommoperationexception E){
 E. Printstacktrace();
}

      3.7.4 获得输入输出流
 Bufferedreader Reader;
Bufferedoutputstream Writer;
Try{
 Reader=New Bufferedreader(New Inputstreamreader(Port.Getinputstream));
 Writer=New Bufferedoutputstream (Port.Getinputstream);
}Catch(Ioexception E){
 E. Printstacktrace();
 }

      3.7.5 进行读写操作
 读操作:
 Try{
  Writer.Write(“写内容…..”);
Writer.Flush();
}Catch(Ioexception E){
Port.Close();
E. Printstacktrace();
}
读操作
 步骤如下:
 *必须继承SerialEvent:ostener 接口
 *为SerialPort添加监听Listener
 *实现该接口的serialEvent(SerialPortEvent event)方法。
*通过BufferedReader 的read()方法逐步byte读取,也可以readLine()读取。
 Public  Class Serialportread Implements Serialporteventlistener{
Bufferedreader Reader;
Bufferedoutputstream Writer;
Commport Port;
Try{
  Port.Addeventlistener(This);
}Catch(Toomanylistenersexception E){
     E. Printstacktrace();
}
Port.Notifyondataavailable(True);
Try{
  Reader =New Bufferedreader(New Inputstreamreader(Port.Getinputstream()));
  Writer=New Bufferedoutputstream(Port.Getoutputstream());
}Catch(Ioexception E){
     E. Printstacktrace();
}
Public Void Serialevent( Serialportevent Event){
  Switch( Event.Geteventtype()){
    Case Serial Portevent.Output_Buffer_Empty:
    Break;
   Case Serial Portevent.Data_Available:
   Stringwriter Strwriter=New Stringwriter;
   Char[] C=New Char[20];
   Int Newdata=0;
   Int I=0;
   While(True){
    Try{
      Newdata=Reader.Read()
 If(Newdata==-1||Newdata==0x0d){
         Break;
}
C[I]=(Char)Newdata;
If(I>100){
Break;
}
}Catch(Ioexception E){
  Return;
}
I++
}
 Try{
  Strwriter.Write(C);
  Strwriter.Flush();
Buffer= Strwriter.Tostring();
Strwriter.Close();
Rettext=Buffer;
Reader.Close();
Port.Close();
}Catch(Exception E){
}
Setreadfinishflg(True);
Break;
}
}
}
 以上是java串口编程的一些小小心得体会,代码是伪代码,不一定能运行,但是步骤就是这几个步骤。





                                                                                                                      软件部        左顶

姓名:
性别:
电话:
E-mail
问题:
问题描述: