Java使用Rxtx编写串口助手
Java使用Rxtx编写串口助手
最近由于一些需要,了解了一下如何使用java来操作串口,花费了好几天时间,所以现在单独整理出来一篇文章,方便大家的同时也方便自己,整个程序的界面是用java的SWT写的。
环境搭建
相关环境:
- window 7 64位;
- jdk 1.8;
- eclipse 2019-12;
- Rxtx版本:rxtx-2.2-20081207-win-x64;
- 如何获取Rxtx
下载链接:http://fizzed.com/oss/rxtx-for-java
- 如何使用Rxtx
解压压缩包,找到Rxtxcomm.jar和rxtxserial.dll文件,并将Rxtxcomm.jar放到jdk的安装目录下,即<JAVA_HOME>\jre\lib\ext,然后将 rxtxSerial.dll文件放到下面的目录里 —> <JAVA_HOME>\jre\bin,重启eclipse即可使用
7. 虚拟串口工具VSPD
下载地址: https://www.cr173.com/soft/21406.html
下载的时候不要下载错,点击普通下载地址,注意观察文件名后缀是.zip格式的
这个工具会直接虚拟出串口,每次虚拟一队,一个发送的数据,另一个可以接收到,所以我在程序中,直接默认打开COM4口接受数据,所以在运行代码选择端口时,请选择COM3。另外,请先虚拟端口,在运行我所给的代码,不然会报异常。
8. 相关注意事项
注意win10系统,Rxtx 64位基本是用不了的,或者说可能有哪些配置我还没有找到,但是Rxtx32位是可以使用的。
代码相关
咱这个人不喜欢啰唆,下面直接上代码。
代码分为三块:界面类MainFrame、串口操作类serialPortManage、和程序启动SerialPort。结构如下图所示:
界面类MainFrame:
package com.lyrics.SerialAssistant.ui;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
import javax.swing.JOptionPane;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Button;
import com.lyrics.SerialAssistant.util.serialPortManage;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
/**
* 串口相关操作方法的实现与封装
*
* @author LyRics1996
* @since 2020-01-04
*/
public class MainFrame {
protected Shell shlSerialAssistant;
private Text textDisplay;
private Text textDatebitSet;
private Text textCheckbitSet;
private Text textStopbitSet;
private Text textSendData;
serialPortManage com=new serialPortManage(); // 就是界面选择打开的端口
serialPortManage com2=new serialPortManage(); // 我将此端口直接设置为"COM4"
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 设置日期格式
/**
* Open the window.
* @wbp.parser.entryPoint
*/
public void open() {
Display display = Display.getDefault();
createContents();
shlSerialAssistant.open();
shlSerialAssistant.layout();
while (!shlSerialAssistant.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/**
* Create contents of the window.
*/
protected void createContents() {
// 创造顶层容器
shlSerialAssistant = new Shell();
shlSerialAssistant.setSize(454, 304);
shlSerialAssistant.setText("Serial Asssistant");
// 创建文本类控件
textDisplay = new Text(shlSerialAssistant, SWT.BORDER | SWT.MULTI);
textDisplay.setBounds(10, 10, 271, 168);
textSendData = new Text(shlSerialAssistant, SWT.BORDER);
textSendData.setBounds(89, 237, 222, 23);
textDatebitSet = new Text(shlSerialAssistant, SWT.BORDER);
textDatebitSet.setText("8");
textDatebitSet.setBounds(355, 67, 73, 23);
textCheckbitSet = new Text(shlSerialAssistant, SWT.BORDER);
textCheckbitSet.setText("0");
textCheckbitSet.setToolTipText("");
textCheckbitSet.setBounds(355, 104, 73, 23);
textStopbitSet = new Text(shlSerialAssistant, SWT.BORDER);
textStopbitSet.setText("1");
textStopbitSet.setToolTipText("");
textStopbitSet.setBounds(355, 143, 73, 23);
// 创建标签类控件
Label lblBaudrate = new Label(shlSerialAssistant, SWT.NONE);
lblBaudrate.setBounds(287, 23, 61, 17);
lblBaudrate.setText("Baud rate:");
Label lblDataBite = new Label(shlSerialAssistant, SWT.NONE);
lblDataBite.setBounds(287, 67, 61, 17);
lblDataBite.setText("Data bit:");
Label lblCheckBite = new Label(shlSerialAssistant, SWT.NONE);
lblCheckBite.setBounds(287, 110, 61, 17);
lblCheckBite.setText("Check bit:");
Label lblStopBit = new Label(shlSerialAssistant, SWT.NONE);
lblStopBit.setBounds(287, 149, 61, 17);
lblStopBit.setText("Stop bit:");
Label lblSerialPort = new Label(shlSerialAssistant, SWT.NONE);
lblSerialPort.setBounds(20, 196, 63, 17);
lblSerialPort.setText("Serial Port:");
Label lblSendData = new Label(shlSerialAssistant, SWT.NONE);
lblSendData.setBounds(20, 240, 63, 17);
lblSendData.setText("Send Data:");
// 创建Combo类控件
Combo comboBaudrateSelect = new Combo(shlSerialAssistant, SWT.NONE);
comboBaudrateSelect.setItems(new String[] {"9600", "115200"});
comboBaudrateSelect.setBounds(355, 20, 74, 25);
comboBaudrateSelect.setText("9600");
Combo comboSeralPort = new Combo(shlSerialAssistant, SWT.NONE);
comboSeralPort.setBounds(89, 192, 88, 25);
addListPort(comboSeralPort);
// 创建按钮类控件
Button btnOpenPort = new Button(shlSerialAssistant, SWT.NONE);
btnOpenPort.setBounds(231, 191, 80, 27);
btnOpenPort.setText("Open Port");
Button btnClosePort = new Button(shlSerialAssistant, SWT.NONE);
btnClosePort.setBounds(336, 191, 80, 27);
btnClosePort.setText("Close Port");
Button btnSendData = new Button(shlSerialAssistant, SWT.NONE);
btnSendData.setBounds(336, 235, 80, 27);
btnSendData.setText("Send Data");
// 添加监听事件
btnOpenPort.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
com.setBaudrate(Integer.parseInt(comboBaudrateSelect.getText()));
com.setDatabit(Integer.parseInt(textDatebitSet.getText()));
com.setCheckbit(Integer.parseInt(textCheckbitSet.getText()));
com.setStopbit(Integer.parseInt(textStopbitSet.getText()));
if(!com.openPort(comboSeralPort.getText())) {
JOptionPane.showMessageDialog(null, "open port failed! This device not exist or using","warning", JOptionPane.INFORMATION_MESSAGE);
return;
}
JOptionPane.showMessageDialog(null, "open port successed!","warning", JOptionPane.INFORMATION_MESSAGE);
}
});
btnClosePort.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
com.close();
JOptionPane.showMessageDialog(null, "close port successed!","warning", JOptionPane.INFORMATION_MESSAGE);
}
});
btnSendData.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String message = textSendData.getText();
com2.openPort("COM4");
com2.startRead(1);
com.write(message);
textDisplay.append(df.format(new Date())+"\r\n");
textDisplay.append(comboSeralPort.getText()+':'+message);
textDisplay.append("\r\n");
textDisplay.append(df.format(new Date())+"\r\n");
textDisplay.append("COM4"+':'+com2.getReadStr());
textDisplay.append("\r\n");
}
});
}
/**
* 打开软件时,comboSeralPort控件中列出所有的端口
*
* @author LyRics1996
* @since 2020-01-04
*/
@SuppressWarnings("unchecked")
private void addListPort(Combo comboSeralPort) {
Vector<String> port=new Vector<String>();
port=com.listPort();
for(int i=0;i<port.size();i++)
{
comboSeralPort.add(port.elementAt(i));
}
comboSeralPort.setText(port.elementAt(0));
}
}
串口操作类serialPortManage
package com.lyrics.SerialAssistant.util;
import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;
import java.util.Vector;
/**
* 串口相关操作方法的实现与封装
*
* @author LyRics1996
* @since 2020-01-04
*/
public class serialPortManage implements Runnable, SerialPortEventListener
{
private int baudrate=9600;
private int databit=8;
private int checkbit=0;
private int stopbit=1;
private int m_iWaitTime = 2000;
private String readStr = "";
private int m_iThreadTime = 0;
private CommPortIdentifier m_commPort;
private SerialPort m_serialPort;
private InputStream m_inputStream;
private OutputStream m_outputStream;
public void setBaudrate(int baudrate) {
this.baudrate = baudrate;
}
public void setDatabit(int databit) {
this.databit = databit;
}
public void setCheckbit(int checkbit) {
this.checkbit = checkbit;
}
public void setStopbit(int stopbit) {
this.stopbit = stopbit;
}
public String getReadStr() {
return readStr;
}
/**
* 列出当前电脑所有端口
*
* @author LyRics1996
* @since 2020-01-04
*/
@SuppressWarnings("rawtypes")
public Vector listPort()
{
Vector<String> listPort=new Vector<String>();
CommPortIdentifier commPortIdentifier;
Enumeration enumeration = CommPortIdentifier.getPortIdentifiers();
while (enumeration.hasMoreElements())
{
commPortIdentifier = (CommPortIdentifier)enumeration.nextElement();
if (commPortIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
{
listPort.addElement(commPortIdentifier.getName());
}
}
return listPort;
}
/**
* 传入端口名,例如"COM1",打开端口
*
* @author LyRics1996
* @since 2020-01-04
*/
@SuppressWarnings("rawtypes")
public boolean openPort(String sPortName)
{
m_commPort = null;
CommPortIdentifier commPortIdentifier;
Enumeration enumeration = CommPortIdentifier.getPortIdentifiers();
while (enumeration.hasMoreElements())
{
commPortIdentifier = (CommPortIdentifier)enumeration.nextElement();
if (commPortIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL
&& commPortIdentifier.getName().equals(sPortName))
{
m_commPort = commPortIdentifier;
try {
m_serialPort = (SerialPort)m_commPort.open(null, m_iWaitTime);
} catch (PortInUseException e) {
return false;
}
try {
m_serialPort.setSerialPortParams(baudrate, databit, stopbit, checkbit);
} catch (UnsupportedCommOperationException e) {
e.printStackTrace();
}
addListener();
return true;
}
}
return false;
}
/**
* 检查端口连接情况
*
* @author LyRics1996
* @since 2020-01-04
*/
public void checkPort()
{
if (m_commPort == null)
{
throw new RuntimeException("请选择端口");
}
if (m_serialPort == null)
{
throw new RuntimeException("serialPort对象为null");
}
}
/**
* 发送数据
*
* @author LyRics1996
* @since 2020-01-04
*/
public void write(String sMessage)
{
checkPort();
try
{
m_outputStream = new BufferedOutputStream(m_serialPort.getOutputStream());
}
catch (IOException e)
{
throw new RuntimeException("获取端口的OutputStream出错" + e.getMessage());
}
try
{
m_outputStream.write(sMessage.getBytes());
}
catch (IOException e)
{
throw new RuntimeException("向端口发送信息时出错:" + e.getMessage());
}
finally
{
try
{
m_outputStream.close();
}
catch (Exception e)
{
}
}
}
/**
* 添加监听,该方法在打开端口时自动被调用
*
* @author LyRics1996
* @since 2020-01-04
*/
public void addListener()
{
try
{
m_serialPort.addEventListener(this);
}
catch (TooManyListenersException e)
{
throw new RuntimeException(e.getMessage());
}
}
/**
* 开始监听数据
*
* @author LyRics1996
* @since 2020-01-04
*/
public void startRead(int iTime)
{
checkPort();
try
{
m_inputStream = new BufferedInputStream(m_serialPort.getInputStream());
}
catch (IOException e)
{
throw new RuntimeException("获取端口的InputStream出错:" + e.getMessage());
}
m_serialPort.notifyOnDataAvailable(true);
if (iTime > 0)
{
m_iThreadTime = iTime * 1000;
Thread thread = new Thread(this);
thread.start();
}
}
/**
* 关闭端口
*
* @author LyRics1996
* @since 2020-01-04
*/
public void close()
{
m_serialPort.close();
m_serialPort = null;
m_commPort = null;
}
/**
* run
*
* @author LyRics1996
* @since 2020-01-04
*/
@Override
public void run()
{
try
{
Thread.sleep(m_iThreadTime);
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 串口相关事件
*
* @author LyRics1996
* @since 2020-01-04
*/
@Override
public void serialEvent(SerialPortEvent arg0)
{
switch (arg0.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[1024];
readStr = "";
try
{
while (m_inputStream.available() > 0)
{
m_inputStream.read(readBuffer);
readStr += new String(readBuffer).trim();
}
}
catch (IOException e)
{
}
}
}
}
程序启动SerialPort
package com.lyrics.SerialAssistant;
import com.lyrics.SerialAssistant.ui.MainFrame;
/**
* SerialPort
*
* @author LyRics1996
* @since 2020-01-04
*/
public class SerialPort {
public static void main(String[] args) {
try {
MainFrame window = new MainFrame();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
首先打开串口虚拟工具,虚拟出com3和com4
运行代码,程序员运行界面如图所示
选中COM3端口,点击OpenPort按钮,在senddata中输入要发送的数据,例如:LyRics1966,我们可以看到COM3将数据发送出去,COM4将数据接收并显示到界面上。
写在最后
本次的代码只是粗略的实现基础功能,很多地方写的也不够严谨,也没有将功能模块区分的更加清楚,所以有些不尽如人意是肯定的,请大家多多包涵,本篇文章也只是希望诸位能够借鉴后直接调通代码,不要在调通代码这一步就浪费了很多时间。