×

java实现 串口通讯

前端技术网 前端技术网 发表于2024-01-14 03:23:18 浏览2035 评论0

抢沙发发表评论

一、在java的web程序中怎么使用串口通讯

最近在做java串口通讯,主要是用个人电脑通过串口从RS485读取数据,并通过crc循环冗余校验,把接收正确的数据解析,插入数据库mysql,并用SSH技术把数据库数据以表格以及图表形式显示

思路:

java实现 串口通讯

1.为了从RS485读取数据,由于暂时没有硬件设备,系统是win7,故采用Virtual Serial Port Drive(VSPD)这块虚拟串口软件代替。并下载sscom32.exe模拟串口通信软件。

2.要想实现串口通信,用Java实现串口通信(windows系统下),需要用到sun提供的串javacomm20-win32.zip。其中要用到三个文件,配置如下:

comm.jar放置到 JAVA_HOME/jre/lib/ext;

win32com.dll放置到 JAVA_HOME/bin;

javax.comm.properties两个地方都要放

jre/lib(也就是在JAVA文件夹下的jre),JAVA_HOME/jre/lib下

java实现 串口通讯

这个配置在我电脑上测试成功,也许不需要这样麻烦。注意的是,如果你使用myeclipse,因为它自带jre,你需要在它所在的jre相应位置放dll以及properties文件。

是不是感觉这个很麻烦,还有windows的限制。后来我们下载rxtx这款开源包代替了刚才的comm。不仅windows下可以,linux下也可以。使用方法很简单,配置如下:

RXTXcomm.jar放到JAVA_HOME/jre/lib/ext

rxtxSerial.dll放到JAVA_HOME/bin

如果你使用myeclipse工具,你需要把rxtxSerial.dll放到它自带的jre里。

3.新建eclipse工程,添加comm.jar或者RXTXcomm.jar包。因为javacomm20-win32.zip包里有样例SimpleRead.java,可以通过这个例子测试串口是否正确

4.接收数据正确后,根据传送接收双方的协议,采用CRC循环校验,根据传输的一方的校验函数判定是否是正确传输

5.把正确结束的数据解析,查看自己指定的通讯规则,然后解析

6.插入数据库,jdbc插入

7.数据统计,定时统计每小时,每天,每月,每年的平均值,采用quartz服务来实现。

8.建立web工程,采用hibernate3,spring3,dwr技术把数据库数据动态显示,图表采用jfreechart,以及AJAX的运用

二、用java从串口读取数据然后显示在网页上,能实现吗

用java从串口读取数据然后显示在网页上,能实现。

以下是对串口读写代码,来自网友百度知道网友。其它如何传递到网页自己搜索吧。

public static void process(){

try{

Enumeration portList= CommPortIdentifier.getPortIdentifiers();

while(portList.hasMoreElements())

{

CommPortIdentifier portId=(CommPortIdentifier) portList.nextElement();

if(portId.getPortType()== CommPortIdentifier.PORT_SERIAL)//如果端口类型是串口则判断名称

{

if(portId.getName().equals("COM1")){//如果是COM1端口则退出循环

break;

}else{

portId=null;

}

}

}

SerialPort serialPort=(SerialPort)portId.open("Serial_Communication", 1000);//打开串口的超时时间为1000ms

serialPort.setSerialPortParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);//设置串口速率为9600,数据位8位,停止位1们,奇偶校验无

InputStream in= serialPort.getInputStream();//得到输入流

OutputStream out= serialPort.getOutputStream();//得到输出流

//进行输入输出操作

//操作结束后

in.close();

out.close();

serialPort.close();//关闭串口

} catch(PortInUseException e){

e.printStackTrace();

} catch(UnsupportedCommOperationException e){

e.printStackTrace();

} catch(IOException e){

e.printStackTrace();

}

}

三、编程技巧:Java串口通信简介

嵌入式系统或传感器网络的很多应用和测试都需要通过PC机与嵌入式设备或传感器节点进行通信其中最常用的接口就是RS串口和并口(鉴于USB接口的复杂性以及不需要很大的数据传输量 USB接口用在这里还是显得过于奢侈况且目前除了SUN有一个支持USB的包之外我还没有看到其他直接支持USB的Java类库) SUN的CommAPI分别提供了对常用的RS串行端口和IEEE并行端口通讯的支持 RS C(又称EIA RS C以下简称RS)是在年由美国电子工业协会(EIA)联合贝尔系统调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准 RS是一个全双工的通讯协议它可以同时进行数据接收和发送的工作

常见的Java串口包

目前常见的Java串口包有SUN在年发布的串口通信API m jar(Windows下) m jar(Linux/Solaris);IBM的串口通信API以及一个开源的实现鉴于在Windows下SUN的API比较常用以及IBM的实现和SUN的在API层面都是一样的那个开源的实现又不像两家大厂的产品那样让人放心这里就只介绍SUN的串口通信API在Windows平台下的使用

串口包的安装(Windows下)

到SUN的网站下载javam win zip包含的东西如下所示

按照其使用说明(l)的说法要想使用串口包进行串口通信除了设置好环境变量之外还要将win dll**到 \bin目录下;将m jar**到 \lib;把m properties也同样拷贝到 \lib目录下然而在真正运行使用串口包的时候仅作这些是不够的因为通常当运行 java MyApp的时候是由JRE下的虚拟机启动MyApp的而我们只**上述文件到JDK相应目录下所以应用程序将会提示找不到串口解决这个问题的方法很简单我们只须将上面提到的文件放到JRE相应的目录下就可以了

值得注意的是在网络应用程序中使用串口API的时候还会遇到其他更复杂问题有兴趣的话你可以查看CSDN社区中关于网页上Applet用javam读取客户端串口的问题的帖子

串口API概览

m CommPort

这是用于描述一个被底层系统支持的端口的抽象类它包含一些高层的IO控制方法这些方法对于所有不同的通讯端口来说是通用的 SerialPort和ParallelPort都是它的子类前者用于控制串行端口而后者用于控这并口二者对于各自底层的物理端口都有不同的控制方法这里我们只关心SerialPort

m CommPortIdentifier

这个类主要用于对串口进行管理和设置是对串口进行访问控制的核心类主要包括以下方法

l确定是否有可用的通信端口

l为IO操作打开通信端口

l决定端口的所有权

l处理端口所有权的争用

l管理端口所有权变化引发的事件(Event)

m SerialPort

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

串口API实例

大段的文字怎么也不如一个小例子来的清晰下面我们就一起看一下串口包自带的例子 SerialDemo中的一小段代码来加深对串口API核心类的使用方法的认识

列举出本机所有可用串口

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());}

以上代码可以列举出当前系统所有可用的串口名称我的机器上输出的结果是和

串口参数的配置

串口一般有如下参数可以在该串口打开以前配置进行配置

包括波特率输入/输出流控制数据位数停止位和齐偶校验

SerialPortsPort; try{ sPort setSerialPortParams(BaudRate Databits Stopbits Parity);//设置输入/输出控制流 sPort setFlowControlMode(FlowControlIn|FlowControlOut);}catch(UnsupportedCommOperationExceptione){}

串口的读写

对串口读写之前需要先打开一个串口

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的最高位是则转成int类型时将用来占位这样原本是的byte类型的数变成int型就成了这是很严重的问题应该注意避免

串口通信的通用模式及其问题

终于唠叨完我最讨厌的基础知识了下面开始我们本次的重点串口应用的研究由于向串口写数据很简单所以这里我们只关注于从串口读数据的情况通常串口通信应用程序有两种模式一种是实现SerialPortEventListener接口监听各种串口事件并作相应处理;另一种就是建立一个独立的接收线程专门负责数据的接收由于这两种方法在某些情况下存在很严重的问题(至于什么问题这里先卖个关子J)所以我的实现是采用第三种方法来解决这个问题

事件监听模型

现在我们来看看事件监听模型是如何运作的

l首先需要在你的端口控制类(例如SManager)加上 implements SerialPortEventListener

l在初始化时加入如下代码

try{ SerialPortsPort addEventListener(SManager);}catch(TooManyListenersExceptione){ sPort close(); thrownewSerialConnectionException( toomanylistenersadded);} sPort notifyOnDataAvailable(true);

l覆写public void serialEvent(SerialPortEvent e)方法在其中对如下事件进行判断

BI通讯中断

CD载波检测

CTS清除发送

DATA_AVAILABLE有数据到达

DSR数据设备准备好

FE帧错误

OE溢位错误

OUTPUT_BUFFER_EMPTY输出缓冲区已清空

PE奇偶校验错

RI振铃指示

一般最常用的就是DATA_AVAILABLE串口有数据到达事件也就是说当串口有数据到达时你可以在serialEvent中接收并处理所收到的数据然而在我的实践中遇到了一个十分严重的问题

首先描述一下我的实验我的应用程序需要接收传感器节点从串口发回的查询数据并将结果以图标的形式显示出来串口设定的波特率是川口每隔毫秒返回一组数据(大约是字节左右)周期(即持续时间)为秒实测的时候在一个周期内应该返回多个字节而用事件监听模型我最多只能收到不到字节不知道这些字节都跑哪里去了也不清楚到底丢失的是那部分数据值得注意的是这是我将serialEvent()中所有处理代码都注掉只剩下打印代码所得的结果数据丢失的如此严重是我所不能忍受的于是我决定采用其他方法

串口读数据的线程模型

这个模型顾名思义就是将接收数据的操作写成一个线程的形式:

publicvoidstartReadingDataThread(){ ThreadreadDataProcess=newThread(newRunnable(){ publicvoidrun(){ while(newData!=){ try{ newData=is read(); System out println(newData);//其他的处理过程………}catch(IOExceptionex){ System err println(ex); return;}} readDataProcess start();}

在我的应用程序中我将收到的数据打包放到一个缓存中然后启动另一个线程从缓存中获取并处理数据两个线程以生产者—消费者模式协同工作数据的流向如下图所示

这样我就圆满解决了丢数据问题然而没高兴多久我就又发现了一个同样严重的问题虽然这回不再丢数据了可是原本一个周期(秒)之后传感器节电已经停止传送数据了但我的串口线程依然在努力的执行读串口操作在控制台也可以看见收到的数据仍在不断的打印原来由于传感器节点发送的数据过快而我的接收线程处理不过来所以InputStream就先把已到达却还没处理的字节缓存起来于是就导致了明明传感器节点已经不再发数据了而控制台却还能看见数据不断打印这一奇怪的现象唯一值得庆幸的是最后收到数据确实是左右字节没出现丢失现象然而当处理完最后一个数据的时候已经快分半钟了这个时间远远大于节点运行周期这一延迟对于一个实时的显示系统来说简直是灾难!

后来我想是不是由于两个线程之间的同步和通信导致了数据接收缓慢呢?于是我在接收线程的代码中去掉了所有处理代码仅保留打印收到数据的语句结果依然如故看来并不是线程间的通信阻碍了数据的接收速度而是用线程模型导致了对于发送端数据发送速率过快的情况下的数据接收延迟这里申明一点就是对于数据发送速率不是如此快的情况下前面者两种模型应该还是好用的只是特殊情况还是应该特殊处理

第三种方法

痛苦了许久(Boss天天催我L)之后偶然的机会我听说TinyOS中(又是开源的)有一部分是和我的应用程序类似的串口通信部分于是我下载了它的 x版的Java代码部分参考了它的处理方法解决问题的方法说穿了其实很简单就是从根源入手根源不就是接收线程导致的吗那好我就干脆取消接收线程和作为中介的共享缓存而直接在处理线程中调用串口读数据的方法来解决问题(什么为什么不把处理线程也一并取消?都取消应用程序界面不就锁死了吗?所以必须保留)于是程序变成了这样

publicbyte[]getPack(){ while(true){//PacketLength为数据包长度 byte[]msgPack=newbyte[PacketLength]; for(inti=;i<PacketLength;i++){ if((newData=is read())!=){ msgPack[i]=(byte)newData; System out println(msgPack[i]);}} returnmsgPack;}}

在处理线程中调用这个方法返回所需要的数据序列并处理之这样不但没有丢失数据的现象行出现也没有数据接收延迟了这里唯一需要注意的就是当串口停止发送数据或没有数据的时候is read()一直都返回如果一旦在开始接收数据的时候发现就不要理它继续接收直到收到真正的数据为止

结束语

lishixinzhi/Article/program/Java/hx/201311/26605

文章到此结束,希望我们对于java实现 串口通讯的问题能够给您带来一些启发和解决方案。如果您需要更多信息或者有其他问题,请随时联系我们。