志在指尖
用双手敲打未来

java 串口(java串口通信代码)

java串口

最近一门课要求编写一个上位机串口通讯工具,我根据Java编写了一个带有图形界面的简略串口通讯工具,下面详述一下过程,供我们参考^_^
一:
首要,你需要下载一个额外的支撑Java串口通讯操作的jar包,由于java.comm比较老了,并且不支撑64位体系,这儿引荐Rxtx这个jar包(32位/64位均支撑)。
官方下载地址:http://fizzed.com/oss/rxtx-for-java(注:可能需要FQ才干下载)
不能FQ的童鞋,能够在这儿下载:
二:
下载解压jar包并在JavaBuildPath下引入:
捕获
注:如果运转过程中抛出java.lang.UnsatisfiedLinkError过错或gnu.io下的类找不到,请将rxtx解压包中的rxtxParallel.dll,rxtxSerial.dll这两个文件仿制到C:\Windows\System32目录下即可处理该过错。
三:
关于该jar包的运用,我写了一个SerialTool.java类,该类供给关于串口通讯的各简略服务,代码如下(留意该类位于serialPort包里):
packageserialPort;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.util.ArrayList;importjava.util.Enumeration;importjava.util.TooManyListenersException;importgnu.io.CommPort;importgnu.io.CommPortIdentifier;importgnu.io.NoSuchPortException;importgnu.io.PortInUseException;importgnu.io.SerialPort;importgnu.io.SerialPortEventListener;importgnu.io.UnsupportedCommOperationException;importserialException.*;/***串口服务类,供给翻开、封闭串口,读取、发送串口数据等服务(采用单例规划方式)
*@authorzhong
**/publicclassSerialTool{privatestaticSerialToolserialTool=null;static{//在该类被ClassLoader加载时就初始化一个SerialTool目标if(serialTool==null){
serialTool=newSerialTool();
}
}//私有化SerialTool类的结构办法,不允许其他类生成SerialTool目标privateSerialTool(){}/***获取供给服务的SerialTool目标
*@returnserialTool*/publicstaticSerialToolgetSerialTool(){if(serialTool==null){
serialTool=newSerialTool();
}returnserialTool;
}/***查找所有可用端口
*@return可用端口称号列表*/publicstaticfinalArrayListfindPort(){//获得当时所有可用串口EnumerationportList=CommPortIdentifier.getPortIdentifiers();
ArrayListportNameList=newArrayList<>();//将可用串口名增加到List并回来该Listwhile(portList.hasMoreElements()){
StringportName=portList.nextElement().getName();
portNameList.add(portName);
}returnportNameList;
}/***翻开串口
*@paramportName端口称号
*@parambaudrate波特率
*@return串口目标
*@throwsSerialPortParameterFailure设置串口参数失败
*@throwsNotASerialPort端口指向设备不是串口类型
*@throwsNoSuchPort没有该端口对应的串口设备
*@throwsPortInUse端口已被占用*/publicstaticfinalSerialPortopenPort(StringportName,intbaudrate)throwsSerialPortParameterFailure,NotASerialPort,NoSuchPort,PortInUse{try{//通过端口名识别端口CommPortIdentifierportIdentifier=CommPortIdentifier.getPortIdentifier(portName);//翻开端口,并给端口名字和一个timeout(翻开操作的超时时刻)CommPortcommPort=portIdentifier.open(portName,2000);//判断是不是串口if(commPortinstanceofSerialPort){
SerialPortserialPort=(SerialPort)commPort;try{//设置一下串口的波特率等参数serialPort.setSerialPortParams(baudrate,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
}catch(UnsupportedCommOperationExceptione){thrownewSerialPortParameterFailure();
}//System.out.println(“Open”+portName+”sucessfully!”);returnserialPort;
}else{//不是串口thrownewNotASerialPort();
}
}catch(NoSuchPortExceptione1){thrownewNoSuchPort();
}catch(PortInUseExceptione2){thrownewPortInUse();
}
}/***封闭串口
*@paramserialport待封闭的串口目标*/publicstaticvoidclosePort(SerialPortserialPort){if(serialPort!=null){
serialPort.close();
serialPort=null;
}
}/***往串口发送数据
*@paramserialPort串口目标
*@paramorder待发送数据
*@throwsSendDataToSerialPortFailure向串口发送数据失败
*@throwsSerialPortOutputStreamCloseFailure封闭串口目标的输出流犯错*/publicstaticvoidsendToPort(SerialPortserialPort,byte[]order)throwsSendDataToSerialPortFailure,SerialPortOutputStreamCloseFailure{
OutputStreamout=null;try{
out=serialPort.getOutputStream();
out.write(order);
out.flush();
}catch(IOExceptione){thrownewSendDataToSerialPortFailure();
}finally{try{if(out!=null){
out.close();
out=null;
}
}catch(IOExceptione){thrownewSerialPortOutputStreamCloseFailure();
}
}
}/***从串口读取数据
*@paramserialPort当时已树立衔接的SerialPort目标
*@return读取到的数据
*@throwsReadDataFromSerialPortFailure从串口读取数据时犯错
*@throwsSerialPortInputStreamCloseFailure封闭串口目标输入流犯错*/publicstaticbyte[]readFromPort(SerialPortserialPort)throwsReadDataFromSerialPortFailure,SerialPortInputStreamCloseFailure{
InputStreamin=null;byte[]bytes=null;try{
in=serialPort.getInputStream();intbufflenth=in.available();//获取buffer里的数据长度while(bufflenth!=0){
bytes=newbyte[bufflenth];//初始化byte数组为buffer中数据的长度in.read(bytes);
bufflenth=in.available();
}
}catch(IOExceptione){thrownewReadDataFromSerialPortFailure();
}finally{try{if(in!=null){
in.close();
in=null;
}
}catch(IOExceptione){thrownewSerialPortInputStreamCloseFailure();
}
}returnbytes;
}/***增加监听器
*@paramport串口目标
*@paramlistener串口监听器
*@throwsTooManyListeners监听类目标过多*/publicstaticvoidaddListener(SerialPortport,SerialPortEventListenerlistener)throwsTooManyListeners{try{//给串口增加监听器port.addEventListener(listener);//设置当有数据到达时唤醒监听接纳线程port.notifyOnDataAvailable(true);//设置当通讯中断时唤醒中断线程port.notifyOnBreakInterrupt(true);
}catch(TooManyListenersExceptione){thrownewTooManyListeners();
}
}
注:该类办法中throw的Exception都是我自定义的Exception,之所以这么做是为了方便在主程序中进行相应处理,下面贴其中一个Exception出来给我们做下说明:
(留意我所有自定义的Exception都放在serialException包里)
packageserialException;publicclassSerialPortParameterFailureextendsException{/****/privatestaticfinallongserialVersionUID=1L;publicSerialPortParameterFailure(){}
@OverridepublicStringtoString(){return”设置串口参数失败!翻开串口操作未完成!”;
}
}
每个自定义的Exception类我都重写了它的toString()办法,便于主程序捕捉到该Exception后打印对应的过错信息
其中在serialException包里还有一个专门将接纳到的Exception目标内的过错信息提取出来转换成字符串并回来的类,代码如下:
packageserialException;importjava.io.IOException;importjava.io.PrintWriter;importjava.io.StringWriter;/***负责将传入的Exception中的过错信息提取出来并转换成字符串;
*@authorzhong
**/publicclassExceptionWriter{/***将Exception中的过错信息封装到字符串中并回来该字符串
*@parame包括过错的Exception
*@return过错信息字符串*/publicstaticStringgetErrorInfoFromException(Exceptione){
StringWritersw=null;
PrintWriterpw=null;try{
sw=newStringWriter();
pw=newPrintWriter(sw);
e.printStackTrace(pw);return”\r\n”+sw.toString()+”\r\n”;
}catch(Exceptione2){return”犯错啦!未获取到过错信息,请查看后重试!”;
}finally{try{if(pw!=null){
pw.close();
}if(sw!=null){
sw.close();
}
}catch(IOExceptione1){
e1.printStackTrace();
}
}
}
}
四:
主程序类的运用,Client.java里含有程序的入口地址(main办法),它的作用是显现一个欢迎界面并调用DataView.java这个类进行实践的串口数据显现。
Client.java代码如下:
packageserialPort;importjava.awt.Color;importjava.awt.FlowLayout;importjava.awt.Font;importjava.awt.Frame;importjava.awt.Graphics;importjava.awt.GridLayout;importjava.awt.Image;importjava.awt.Label;importjava.awt.Panel;importjava.awt.Toolkit;importjava.awt.event.KeyAdapter;importjava.awt.event.KeyEvent;importjava.awt.event.WindowAdapter;importjava.awt.event.WindowEvent;importjavax.swing.JOptionPane;importserialException.ExceptionWriter;/***主程序
*@authorzhong
**/publicclassClientextendsFrame{/****/privatestaticfinallongserialVersionUID=1L;/***程序界面宽度*/publicstaticfinalintWIDTH=800;/***程序界面高度*/publicstaticfinalintHEIGHT=620;/***程序界面呈现方位(横坐标)*/publicstaticfinalintLOC_X=200;/***程序界面呈现方位(纵坐标)*/publicstaticfinalintLOC_Y=70;
Colorcolor=Color.WHITE;
ImageoffScreen=null;//用于双缓冲//设置window的icon(这儿我自定义了一下Windows窗口的icon图标,由于真实觉得哪个小咖啡图标不好看==)ToolkittoolKit=getToolkit();
Imageicon=toolKit.getImage(Client.class.getResource(“computer.png”));//持有其他类DataViewdataview=newDataView(this);//主界面类(显现监控数据主面板)/***主办法
*@paramargs//*/publicstaticvoidmain(String[]args){newClient().launchFrame();
}/***显现主界面*/publicvoidlaunchFrame(){this.setBounds(LOC_X,LOC_Y,WIDTH,HEIGHT);//设定程序在桌面呈现的方位this.setTitle(“CDIO工程项目”);//设置程序标题this.setIconImage(icon);this.setBackground(Color.white);//设置布景色this.addWindowListener(newWindowAdapter(){//增加对窗口状态的监听publicvoidwindowClosing(WindowEventarg0){//当窗口封闭时System.exit(0);//退出程序}
});this.addKeyListener(newKeyMonitor());//增加键盘监听器this.setResizable(false);//窗口大小不可更改this.setVisible(true);//显现窗口newThread(newRepaintThread()).start();//开启重画线程}/***画出程序界面各组件元素*/publicvoidpaint(Graphicsg){
Colorc=g.getColor();
g.setFont(newFont(“微软雅黑”,Font.BOLD,40));
g.setColor(Color.black);
g.drawString(“欢迎运用上位机实时监控体系”,45,190);
g.setFont(newFont(“微软雅黑”,Font.ITALIC,26));
g.setColor(Color.BLACK);
g.drawString(“Version:1.0PoweredBy:ZhongLei”,280,260);
g.setFont(newFont(“微软雅黑”,Font.BOLD,30));
g.setColor(color);
g.drawString(“————点击Enter键进入主界面————”,100,480);//使文字”————点击Enter键进入主界面————”是非闪烁if(color==Color.WHITE)color=Color.black;elseif(color==color.BLACK)color=Color.white;
}/***双缓冲方法重画界面各元素组件*/publicvoidupdate(Graphicsg){if(offScreen==null)offScreen=this.createImage(WIDTH,HEIGHT);
GraphicsgOffScreen=offScreen.getGraphics();
Colorc=gOffScreen.getColor();
gOffScreen.setColor(Color.white);
gOffScreen.fillRect(0,0,WIDTH,HEIGHT);//重画布景画布this.paint(gOffScreen);//重画界面元素gOffScreen.setColor(c);
g.drawImage(offScreen,0,0,null);//将新画好的画布“贴”在原画布上}/**内部类方式完成对键盘事件的监听*/privateclassKeyMonitorextendsKeyAdapter{publicvoidkeyReleased(KeyEvente){intkeyCode=e.getKeyCode();if(keyCode==KeyEvent.VK_ENTER){//当监听到用户敲击键盘enter键后履行下面的操作setVisible(false);//隐去欢迎界面dataview.setVisible(true);//显现监测界面dataview.dataFrame();//初始化监测界面}
}
}/**重画线程(每隔250毫秒重画一次)*/privateclassRepaintThreadimplementsRunnable{publicvoidrun(){while(true){
repaint();try{
Thread.sleep(250);
}catch(InterruptedExceptione){//重画线程犯错抛出反常时创建一个Dialog并显现反常详细信息Stringerr=ExceptionWriter.getErrorInfoFromException(e);
JOptionPane.showMessageDialog(null,err,”过错”,JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
}
}
}
运转截图:
注:实践运转过程中最下面的“点击Enter键进入主界面”有一个一闪一闪的作用(是通过每隔一段时刻重画一次界面,让这句话以白黑两色反复替换呈现完成的),双缓冲方法利于处理重画时界面闪烁的问题(如果不运用双缓冲方法的话相当于每次重画时是在旧界面上一点一点画上新东西,而双缓冲实质上是通过先在内存中直接画好一张新界面图,然后一次性直接用新界面覆盖掉旧界面)java

java串口通信代码

1.串口通讯指串口按位(bit)发送和接纳字节。尽管比按字节(byte)的并行通讯慢,可是串口能够在运用一根线发送数据的一起用另一根线接纳数据。
2.串口是计算机上一种非常通用的设备通讯协议(不要与通用串行总线UniversalSerialBus或者USB混杂)
3.地,串口用于ASCII码字符的传输。通讯运用3根线完成:(1)地线,(2)发送,(3)接纳。因为串口通讯是异步的,端口能够在一根线上发送数据一起在另一根线上接纳数据。其他线用于握手,可是不是有必要的。串口通讯最重要的参数是比特率、数据位、中止位和奇偶校验。关于两个进行通讯的端口,这些参数有必要匹配
4.-232(ANSI/EIA-232规范)是IBM-PC及其兼容机上的串行衔接规范、RS-422(EIARS-422-AStandard)是Apple的Macintosh计算机的串口衔接规范。RS-485(EIA-485规范)是RS-422的改进。
说到开源,恐怕很少有人不挑大指称誉。学生经过开源代码学到了常识,程序员经过开源类库获得了别人的成功经验及能够按时完成手头的工程,商家经过开源软件赚到了钱……,总归是大快人心。但是开源软件或类库的首要缺陷便是大多缺乏具体的阐明文档和运用的比如,或者便是软件代码随意你用,便是文档,比如和后期服务收钱。这也难怪,究竟就像某个著名NBA球员说的那样:“我还要养家,所以千万美元以下的合同别找我谈,不然我宁可失业”。是啊,支撑开源的人也要养家,收点钱也不过火。要想既不花钱又学到常识就只能借助网络和了,我仅仅想抛砖引玉,为开源事业做出点菲薄共献,能为你的工程处理哪怕一个小问题,也就足够了。
尽管我的这个系列介绍的东西不是什么Web结构,也不是什么开源服务器,可是我信任,作为一个程序员,什么样的问题都会遇到。有时分越是简单的问题反而越棘手;越是小的地方就越是找不到称手的家伙。只要你不是整天只与“架构”、“构件”、“结构”打交道的话,信任我所说的东西你一定会用到。
1串口通讯简介
1.1常见的Java串口包
1.2串口包的装置(Windows下)
2串口API概览
2.1javax.comm.CommPort
2.2javax.comm.CommPortIdentifier
2.3javax.comm.SerialPort
2.4串口API实例
2.4.1列举出本机一切可用串口
2.4.2串口参数的装备
2.4.3串口的读写
3串口通讯的通用形式及其问题
3.1事情监听模型
3.2串口读数据的线程模型
3.3第三种办法
4结束语
1串口通讯简介
嵌入式体系或传感器网络的很多运用和测试都需求经过PC机与嵌入式设备或传感器节点进行通讯。其间,最常用的接口便是RS-232串口和并口(鉴于USB接口的复杂性以及不需求很大的数据传输量,USB接口用在这儿仍是显得过于奢侈,何况现在除了SUN有一个支撑USB的包之外,我还没有看到其他直接支撑USB的Java类库)。SUN的CommAPI分别提供了对常用的RS232串行端口和IEEE1284并行端口通讯的支撑。RS-232-C(又称EIARS-232-C,以下简称RS232)是在1970年由美国电子工业协会(EIA)联合贝尔体系、调制解调器厂家及计算机终端生产厂家共同拟定的用于串行通讯的规范。RS232是一个全双工的通讯协议,它能够一起进行数据接纳和发送的作业。
1.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平台下的运用。
1.2串口包的装置(Windows下)
到SUN的网站下载javacomm20-win32.zip,包括的东西如下所示:
java串口通讯编程实例
按照其运用阐明(Readme.html)的说法,要想运用串口包进行串口通讯,除了设置好环境变量之外,还要将win32com.dll仿制到《JDK》/bin目录下;将comm.jar仿制到《JDK》/lib;把javax.comm.properties也相同拷贝到《JDK》/lib目录下。但是在真实运转运用串口包的时分,仅作这些是不行的。因为一般当运转“javaMyApp”的时分,是由JRE下的虚拟机发动MyApp的。而咱们只仿制上述文件到JDK相应目录下,所以运用程序将会提示找不到串口。处理这个问题的办法很简单,咱们只须将上面说到的文件放到JRE相应的目录下就能够了。
值得留意的是,在网络运用程序中运用串口API的时分,还会遇到其他更复杂问题。有兴趣的话,你能够检查CSDN社区中“关于网页上Applet用javacomm20读取客户端串口的问题”的帖子。
2串口API概览
2.1javax.comm.CommPort
这是用于描绘一个被底层体系支撑的端口的抽象类。它包括一些高层的IO操控办法,这些办法关于一切不同的通讯端口来说是通用的。SerialPort和ParallelPort都是它的子类,前者用于操控串行端口而后者用于控这并口,二者关于各自底层的物理端口都有不同的操控办法。这儿咱们只关心SerialPort。
2.2javax.comm.CommPortIdentifier
这个类首要用于对串口进行办理和设置,是对串口进行访问操控的中心类。首要包括以下办法
l确认是否有可用的通讯端口
l为IO操作翻开通讯端口
l决议端口的一切权
l处理端口一切权的争用
l办理端口一切权变化引发的事情(Event)
2.3javax.comm.SerialPort
这个类用于描绘一个RS-232串行通讯端口的底层接口,它界说了串口通讯所需的最小功用集。经过它,用户能够直接对串口进行读、写及设置作业。
2.4串口API实例
大段的文字怎样也不如一个小比如来的明晰,下面咱们就一起看一下串口包自带的比如—SerialDemo中的一小段代码来加深对串口API中心类的运用办法的认识。
2.4.1列举出本机一切可用串口
voidlistPortChoices(){
CommPortIdentifierportId;
Enumerationen=CommPortIdentifier.getPortIdentifiers();
//iteratethroughtheports.
while(en.hasMoreElements()){
portId=(CommPortIdentifier)en.nextElement();
if(portId.getPortType()==CommPortIdentifier.PORT_SERIAL){
System.out.println(portId.getName());
}
}
portChoice.select(parameters.getPortName());
}
以上代码能够列举出当前体系一切可用的串口称号,我的机器上输出的成果是COM1和COM3。
2.4.2串口参数的装备
串口一般有如下参数能够在该串口翻开以前装备进行装备:
java串口通讯编程实例
包括波特率,输入/输出流操控,数据位数,中止位和齐偶校验。
SerialPortsPort;
try{
sPort.setSerialPortParams(BaudRate,Databits,Stopbits,Parity);
//设置输入/输出操控流
sPort.setFlowControlMode(FlowControlIn|FlowControlOut);
}catch(UnsupportedCommOperationExceptione){}
2.4.3串口的读写
对串口读写之前需求先翻开一个串口:
CommPortIdentifierportId=CommPortIdentifier.getPortIdentifier(PortName);
try{
SerialPortsPort=(SerialPort)portId.open(“串口一切者称号”,超时等待时刻);
}catch(PortInUseExceptione){//假如端口被占用就抛出这个异常
thrownewSerialConnectionException(e.getMessage());
}
//用于对串口写数据
OutputStreamos=newBufferedOutputStream(sPort.getOutputStream());
os.write(intdata);
//用于从串口读数据
InputStreamis=newBufferedInputStream(sPort.getInputStream());
intreceivedData=is.read();
读出来的是int型,你能够把它转换成需求的其他类型。
这儿要留意的是,因为Java言语没有无符号类型,即一切的类型都是带符号的,在由byte到int的时分应该尤其留意。因为假如byte的最高位是1,则转成int类型时将用1来占位。这样,原本是10000000的byte类型的数变成int型就成了1111111110000000,这是很严峻的问题,应该留意防止。
3串口通讯的通用形式及其问题
终于啰嗦完我最讨厌的基础常识了,下面开端咱们本次的重点–串口运用的研讨。因为向串口写数据很简单,所以这儿咱们只重视于从串口读数据的状况。一般,串口通讯运用程序有两种形式,一种是完成SerialPortEventListener接口,监听各种串口事情并作相应处理;另一种便是建立一个独立的接纳线程专门负责数据的接纳。因为这两种办法在某些状况下存在很严峻的问题(至于什么问题这儿先卖个关子J),所以我的完成是选用第三种办法来处理这个问题。
3.1事情监听模型
现在咱们来看看事情监听模型是怎么运作的

l首先需求在你的端口操控类(例如SManager)加上“implementsSerialPortEventListener”
l在初始化时参加如下代码:
try{
SerialPortsPort.addEventListener(SManager);
}catch(TooManyListenersExceptione){
sPort.close();
thrownewSerialConnectionException(“toomanylistenersadded”);
}
sPort.notifyOnDataAvailable(true);
l覆写publicvoidserialEvent(SerialPortEvente)办法,在其间对如下事情进行判别:
BI-通讯中断。
CD-载波检测。
CTS-铲除发送。
DATA_AVAILABLE-有数据抵达。
DSR-数据设备准备好。
FE-帧过错。
OE-溢位过错。
OUTPUT_BUFFER_EMPTY-输出缓冲区已清空。
PE-奇偶校验错。
RI-振铃指示。
一般最常用的便是DATA_AVAILABLE–串口有数据抵达事情。也便是说当串口有数据抵达时,你能够在serialEvent中接纳并处理所收到的数据。但是在我的实践中,遇到了一个非常严峻的问题。
首先描绘一下我的试验:我的运用程序需求接纳传感器节点从串口发回的查询数据,并将成果以图标的方式显现出来。串口设定的波特率是115200,川口每隔128毫秒回来一组数据(大约是30字节左右),周期(即持续时刻)为31秒。实测的时分在一个周期内应该回来4900多个字节,而用事情监听模型我最多只能收到不到1500字节,不知道这些字节都跑哪里去了,也不清楚到底丢掉的是那部分数据。值得留意的是,这是我将serialEvent()中一切处理代码都注掉,只剩下打印代码所得的成果。数据丢掉的如此严峻是我所不能忍受的,所以我决议选用其他办法。
3.2串口读数据的线程模型
这个模型顾名思义,便是将接纳数据的操作写成一个线程的方式:
publicvoidstartReadingDataThread(){
ThreadreadDataProcess=newThread(newRunnable(){
publicvoidrun(){
while(newData!=-1){
try{
newData=is.read();
System.out.println(newData);
//其他的处理过程
………。
}catch(IOExceptionex){
System.err.println(ex);
return;
}
}
readDataProcess.start();
}
在我的运用程序中,我将收到的数据打包放到一个缓存中,然后发动另一个线程从缓存中获取并处理数据。两个线程以生产者—顾客形式协同作业,数据的流向如下图所示:
java串口通讯编程实例
这样,我就圆满处理了丢数据问题。但是,没快乐多久我就又发现了一个相同严峻的问题:尽管这回不再丢数据了,可是原本一个周期(31秒)之后,传感器节电现已中止传送数据了,但我的串口线程仍然在尽力的执行读串口操作,在操控台也能够看见收到的数据仍在不断的打印。原来,因为传感器节点发送的数据过快,而我的接纳线程处理不过来,所以InputStream就先把已抵达却还没处理的字节缓存起来,所以就导致了明明传感器节点现已不再发数据了,而操控台却还能看见数据不断打印这一古怪的现象。仅有值得庆幸的是最后收到数据确实是4900左右字节,没呈现丢掉现象。但是当处理完最后一个数据的时分现已快1分半钟了,这个时刻远远大于节点运转周期。这一推迟关于一个实时的显现体系来说简直是灾难!
后来我想,是不是因为两个线程之间的同步和通讯导致了数据接纳缓慢呢?所以我在接纳线程的代码中去掉了一切处理代码,仅保存打印收到数据的句子,成果仍然如故。看来并不是线程间的通讯阻止了数据的接纳速度,而是用线程模型导致了关于发送端数据发送速率过快的状况下的数据接纳推迟。这儿申明一点,便是关于数据发送速率不是如此快的状况下前面者两种模型应该仍是好用的,仅仅特别状况仍是应该特别处理。
3.3第三种办法
痛苦了许久(Boss天天催我L)之后,偶然的时机,我听说TinyOS中(又是开源的)有一部分是和我的运用程序类似的串口通讯部分,所以我下载了它的1.x版的Java代码部分,参考了它的处理办法。处理问题的办法说穿了其实很简单,便是从本源入手。本源不便是接纳线程导致的吗,那好,我就干脆撤销接纳线程和作为中介的同享缓存,而直接在处理线程中调用串口读数据的办法来处理问题(什么,为什么不把处理线程也同时撤销?—-都撤销运用程序界面不就锁死了吗?所以有必要保存)所以程序变成了这样:
publicbyte[]getPack(){
while(true){
//PacketLength为数据包长度
byte[]msgPack=newbyte[PacketLength];
for(inti=0;i《PacketLength;i++){
if((newData=is.read())!=-1){
msgPack[i]=(byte)newData;
System.out.println(msgPack[i]);
}
}
returnmsgPack;
}
}
在处理线程中调用这个办法回来所需求的数据序列并处理之,这样不光没有丢掉数据的现象行呈现,也没有数据接纳推迟了。这儿仅有需求留意的便是当串口中止发送数据或没有数据的时分is.read()一直都回来-1,假如一旦在开端接纳数据的时分发现-1就不要理它,继续接纳,直到收到真实的数据为止。
4结束语
本文介绍了串口通讯的基本常识,以及常用的几种形式。经过实践,提出了一些问题,并在最后加以处理。值得留意的是关于榜首种办法,我曾将传感器发送的时刻由128毫秒增加到512毫秒,仍然有很严峻的数据丢掉现象发生,所以假如你的运用程序需求很精密的成果,传输数据的速率又很快的话,就最好不要用榜首种办法。关于第二种办法,因为是线程导致的问题,所以关于不同的机器应该会有不同的体现,关于那些处理多线程比较好的机器来说,应该会好一些。可是我的机器是Inter奔四3.0双核CPU+512DDR内存,这样都推迟这么凶猛,还得多强的CPU才行啊?所以关于数据量比较大的传输来说,仍是用第三种办法吧。不过这个国际问题是很多的,并且未知的问题比已知的问题多的多,说不定还有什么其他问题存在,欢迎你经过下面的联系方式和我一起研讨。

未经允许不得转载:IT技术网站 » java 串口(java串口通信代码)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载