一、首先搭建平台,我用的是eclipse+rxtx+SWT。
安装eclipse就是安装java包后,然后下载eclipse即可。因为eclipse是绿色的,不用安装,下载即可用。
下载rxtx。在网上下载rxtx包含串口开发的常用函数,是开源社区的一个产物,与sun公司的comm包相同,只是调用前的导入语句由import
javax.comm.*变为import
gnu.io.*而已.这个包包含一个jar包和几个用于windows平台的几个dll文件。
下载swt。同rxtx一样,包含一个jar包和几个dll文件。详见可到SWT网站查询。
安装rxtx和swt。把上面rxtx和swt涉及到的文件放到你的项目下,然后在该项目下添加外包jar包,关于添加外部jar包的详细的网上有很多.
二、支持图形化编辑
下载安装swt designer。
注册swt
designer,重启你的eclipse,在项目菜单里找到属性一项,然后在对话框里找到designer一项,里面有提示,根据提示一次填写,注意的是在想免费使用set
designer时,必须选中free
下的swt,同时你的Email必须填写,这样你的注册码才能收到。注册后,会提示你注册码已经发送到你的邮箱了。再次打开项目菜单的属性一项,同样是designer下,和上次填写注册信息一样,只是这此你不必填写信息了。直接把你的注册码写到注册码一项里,然后单击完成即可。
使用图形界面。打开你的项目下的源文件,工作区的左下角会有source/designer选项,单击designer就到了图形编辑状态,要回到非图形状态,同样到工作区的左下角,只是这此单击source选项。有时,左下角会找不到这样的切换选项,这时你选中你要打开的文件,然后右击,在弹出的菜单里由一项是“open
in
designer”,选中该项,你就会发现工作区的左下角由source/designer切换选项.
三、项目
和一般的java项目一样,编写你的文件。当然可以用图形界面编辑了。
源代码:
第一个是串口对象,支持串口的一些基本操作,
package one;
import java.io.*;
import java.util.*;
import gnu.io.*;
public class Comm implements SerialPortEventListener {
private volatile boolean usingOnePort =
false;// 宣告对象打开了(或者正在使用)一个串口
//
volatile,保证不同线程得到的值一致这里是监听器和readPort()函数读取
protected volatile boolean receiving =
false;// 处于接收串口信息状态
protected volatile boolean sentting = false;//
处于向串口发送信息状态
private CommPortIdentifier portId;//
硬件初始化
private SerialPort serialPort;//
软件和硬件的接口
private OutputStream out;//
向串口发送数据流
private InputStream in;//
接收串口数据流
private String commName = "COM2";
private int bPS = 9600;
private int dataBit = 7;//
和C51通信必须设为7位,不然输出不对
private int stopBit = 1;
private int parityBit = 0;
private PipedInputStream pipin;//
管道流,接收串口信息的
private PipedOutputStream pipout;
public void setName(String commname) {
commName=commname;
}
public void setBps(int bps) {
bPS = bps;
}
public void setDataBit(int databit) {
dataBit = databit;
}
public void setStopBit(int stopbit) {
stopBit = stopbit;
}
public void setParityBit(int paritybit) {
parityBit = paritybit;
}
public static String[] listPort() {
int i = 0;
String commList[] = new
String[15];// 假定最多为十五个串口
CommPortIdentifier commPort =
null;
Enumeration portList =
null;
portList =
CommPortIdentifier.getPortIdentifiers();
// iterate through the
ports.
while
(portList.hasMoreElements()) {
commPort =
(CommPortIdentifier) portList.nextElement();
if
(commPort.getPortType() == CommPortIdentifier.PORT_SERIAL) {
commList[i]
= commPort.getName();
//
System.out.print(commList[i] + " ");// 调试语句
i
+= 1;
}
}
// System.out.println();//
调试语句
return commList;
}
public boolean open() {
boolean ok = false;
try {//
打开硬件资源,获取并口
portId =
CommPortIdentifier.getPortIdentifier(commName);
} catch (NoSuchPortException e)
{
System.out.println("Get
portid err" + e.getMessage());
return
ok;
}
try {//
打开软件资源,设置进程名称和超时时间
serialPort =
(SerialPort) portId.open("comm", 1000);
} catch (PortInUseException e)
{
//
System.out.println("Port in used err " +
e.getMessage());//调试语句
return
ok;
}
//
很有意思这句,你不设置他也能正确收到信息,但是设置不正确就收不到信息
try {//
设置数据传输参数
serialPort.setSerialPortParams(bPS,
dataBit, stopBit, parityBit);
} catch
(UnsupportedCommOperationException e) {
System.out.println("Set
port params err " + e.getMessage());
return
ok;
}
try {// 创建输入流
in =
serialPort.getInputStream();
} catch (IOException e) {
System.out.println("Create
instream err " + e.getMessage());
return
ok;
}
try {// 创建输出流
out =
serialPort.getOutputStream();
} catch (IOException e) {
System.out.println("Create
outstream err " + e.getMessage());
return
ok;
}
// 创建管道流
pipin = new
PipedInputStream();
pipout = new
PipedOutputStream();
try {// 连接管道
pipin.connect(pipout);
} catch (IOException e1)
{
System.out.println("Connect
pipin and pipout err "
+
e1.getMessage());
return
ok;
}
try {// 监听串口
serialPort.addEventListener(this);
} catch
(TooManyListenersException e) {
System.out.println("SerialPort
addEventListener err"
+
e.getMessage());
return
ok;
}
serialPort.notifyOnDataAvailable(true);//
开启,是否监听有数据
usingOnePort = true;//
已经使用一个串口了
receiving = true;//
处于接收状态
sentting = true;//
处于发送状态
//
System.out.println(commName+" init is ok");// 调试语句
ok = true;
return ok;
}
private synchronized void read() {//
由打开串口后,增加的监听程序自动调用
final byte[] buf;//
缓冲区
int n;//
检测输入流是否真的有输入
if (usingOnePort) {//
usingOnePort针对增加监听时出错识别
try {
n
= in.available();
} catch
(IOException e) {
System.out.println("Check
inputstream available err "
+
e.getMessage());
return;
}
if
(receiving) {// 串口处于接收状态
if
(n > -1) {//
输入流有数据输入,全部读入到管道
buf
= new byte[n];
try
{// 数据读到缓存区
in.read(buf);
}
catch (IOException e) {
System.out.println("Start
read port err "
+
e.getMessage());
return;
}
if
(new String(buf).trim() != " ") {//
数据有效,非全为空格
try
{// 把数据写到到管道
pipout.write(buf);
pipout.flush();
}
catch (IOException e) {
System.out.println("Write
data to pip err "
+
e.getMessage());
}
}
}
else {// 没有数据输入,不再写入管道了
buf
= null;
return;
}
} else {//
非接受状态,跳过N个字节
try
{
in.skip(n);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
notifyAll();//
完成一次读取,释放该函数,其他程序可以调用了
return;
}
public String getMessage() {
int n = -1;
byte[] buf;
String msg = null;
if (usingOnePort) {//
正在使用一个串口
try {
n
= pipin.available();
} catch
(IOException e) {
System.out.println("Check
pipin has data or not err "
+
e.getMessage());
return
msg;
}
if (n
> -1) {// 管道里有数据
buf
= new byte[n];
try
{// 获取数据
pipin.read(buf);
}
catch (IOException e) {
System.out.println("Get
message form pipin err "
+
e.getMessage());
return
msg;
}
msg
= new String(buf);
if
(msg.trim() == " ")
msg
= null;
}
}
return msg;
}
public String getMessage(int[] num) {
num[0]=0;//表示接收多少个数据了
int n = -1;
byte[] buf;
String msg = null;
if (usingOnePort) {//
正在使用一个串口
try {
n
= pipin.available();
} catch
(IOException e) {
System.out.println("Check
pipin has data or not err "
+
e.getMessage());
return
msg;
}
if (n
> -1) {// 管道里有数据
num[0]=n;
buf
= new byte[n];
try
{// 获取数据
pipin.read(buf);
}
catch (IOException e) {
System.out.println("Get
message form pipin err "
+
e.getMessage());
return
msg;
}
msg
= new String(buf);
if
(msg.trim() == " "){
num[0]=0;
msg
= null;
}
}
}
return msg;
}
private synchronized boolean write(String msg)
{
boolean ok = false;
if (sentting
&& msg != null) {//
处于发送状态且发送字符为非空
try {
out.write(msg.getBytes());
out.flush();
} catch
(Exception e) {
System.out.println("Write
port err " + e.getMessage());
return
ok;
}
}
ok = true;
notifyAll();
// System.out.println("Writting
port");// 调试语句
return ok;
}
public boolean sentMessage(String msg) {
boolean ok = false;
if (usingOnePort) {//
正在使用一个串口
write(msg);
ok =
true;
}
return ok;
}
public boolean sentMessage(String msg,int[] num)
{
boolean ok = false;
if (usingOnePort) {//
正在使用一个串口
write(msg);
num[0]=msg.length();
ok =
true;
}
return ok;
}
public boolean close() {
boolean ok = false;
if (usingOnePort) {//
只有已经打开一个串口,在使用时,才能关闭串口
try {//
关闭输入输出流
in.close();
out.close();
} catch
(Exception e) {
System.out.println("Close
IO err " + e.getMessage());
return
ok;
}
try {//
关闭管道流
pipout.close();
pipin.close();
} catch
(IOException e1) {
System.out.println("Close
pipedIO err " + e1.getMessage());
return
ok;
}
serialPort.close();//
关闭串口
usingOnePort
= false;// 串口处于关闭状态
//
System.out.println("Close port");// 调试语句
ok =
true;
}
return ok;
}
public void serialEvent(SerialPortEvent e)
{
switch (e.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: {
//
System.out.println("Have Data");
read();
}
}
}
}
***************************************
下面是图形界面部分,包括界面和串口动态生成和关闭.
package one;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
public class CommTest {
private Display display;
private Shell shell;
private Comm comm;// 串口对象
private Thread commT;//
串口对象管理线程
//
五个串口参数,因串口对象是动态的存在
private volatile String commname = "COM2";//
串口参数必须在这个类里设置,不然不行
private volatile int bps = 9600;
private volatile int databit = 7;//
和C51通信必须设为7位,不然输出不对
private volatile int stopbit = 1;
private volatile int paritybit = 0;
private volatile int what2Do;//
串口关闭、打开或者保持不变标志等
//
以下四个为对串口对象的管理动作
private final int closeComm = 0;//
关闭串口
private final int openComm = 1;//
打开串口
private final int changePara = 2;//
改变串口参数
private final int keepStat = 3;//
保持当前状态
// 接收信息
private Text receiveText;//
接收信息文本框
private final int disLimit = 1000;//
接收信息显示1000自字符后,清屏
private volatile boolean disHex = false;//
十六进制显示接收的数据
// 发送信息
private Text sentText;//
发送信息文本框
private volatile boolean sentHexS = false;//
十六进制格式发送数据
private volatile boolean autoSentS = false;//
是否自动发送
private volatile long autoSentTime = 1000;//
自动发送时间间隔,1秒
// 信息保存
private volatile boolean autoSaveS = false;//
自动保存标志
private volatile String fileName =
"./comm.txt";// 保存路径(默认)
// 收、发信息量
private volatile int numReceived = 0;//
接收到串口数据的数目
private volatile int numSend = 0;//
发送数据的数目
public static void main(String[] args) {
try {
CommTest
window = new CommTest();
window.open();
} catch (Exception e) {
System.out.println("window
open err " + e.getMessage());
}
}
@SuppressWarnings("deprecation")
public void open() {
display =
Display.getDefault();// 打开显示SWT显示功能
createContents();//
创建窗口部件
shell.open();//
打开主窗口
shell.layout();//
主窗口布局
while (!shell.isDisposed()) {//
shell没有注销掉
if
(!display.readAndDispatch())
display.sleep();
}
comm.close();//
关闭串口
commT.stop();//
关闭串口管理线程
shell.dispose();//
关闭主窗口
display.dispose();//
关闭显示swt功能
}
protected void createContents() {
shell = new
Shell(display,SWT.MIN|SWT.CLOSE);// 由display生成shell
final GridLayout gridLayout =
new GridLayout();
gridLayout.numColumns =
2;
shell.setLayout(gridLayout);
shell.setSize(701, 532);
shell.setText("串口调试助手");
shell.setImage(new
Image(display, "./icon.gif"));// 设置窗口图像
createSetting();
createCommT();
createReceive();
createSent();
final Label label_4 = new
Label(shell, SWT.CENTER | SWT.BORDER);
label_4.setLayoutData(new
GridData(116, SWT.DEFAULT));
final Thread couter = new
Thread(new Runnable() {//
统计接收和发送到的数据数目
public
void run() {
while
(true) {
try
{
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
display.syncExec(new
Runnable() {
public
void run() {
label_4.setText("RX:"
+ numReceived
+
"\tTX:" + numSend);
}
});
}
}
});
couter.start();
label_4.addDisposeListener(new
DisposeListener() {
@SuppressWarnings("deprecation")
public void
widgetDisposed(DisposeEvent arg0) {
couter.stop();
}
});
final Label label_5 = new
Label(shell, SWT.NONE | SWT.CENTER);
label_5.setLayoutData(new
GridData(549, SWT.DEFAULT));
label_5.setText("串口调试助手(SWT)
\t版权所有:anyone \t作者:adlong");
}
private void createSetting() {
final Group group = new
Group(shell, SWT.NONE | SWT.CENTER);
final GridData gd_group = new
GridData(SWT.LEFT, SWT.TOP, false, false);
gd_group.heightHint =
160;
gd_group.widthHint = 110;
group.setLayoutData(gd_group);
final GridLayout gridLayout =
new GridLayout();
gridLayout.numColumns =
2;
group.setText("串口设置");
group.setLayout(gridLayout);
final Label Label = new
Label(group, SWT.NONE);
Label.setText("串口");
final Combo combo = new
Combo(group, SWT.NONE);
combo.setLayoutData(new
GridData(SWT.FILL, SWT.CENTER, true, false));
String[] list =
Comm.listPort();// 最大串口名称列表
int n = list.length;//
最大串口个数
for (int i = 0; i
< n - 1; i++)
if (list[i]
!= null)
combo.add(list[i]);
combo.select(1);//
默认选中第二项,与默认串口一致
combo.addSelectionListener(new
SelectionAdapter() {// 选择响应
public
void widgetSelected(SelectionEvent e) {
int
n = combo.getSelectionIndex();//
获取选中的选项位置值
commname
= combo.getItem(n);// 获取应该设置的值
what2Do
= changePara;
}
});
final Label label_1 = new
Label(group, SWT.NONE);
label_1.setText("波特率");
final Combo combo_1 = new
Combo(group, SWT.NONE);
combo_1.setLayoutData(new
GridData(SWT.FILL, SWT.CENTER, true, false));
combo_1.add("300");
combo_1.add("600");
combo_1.add("1200");
combo_1.add("2400");
combo_1.add("4800");
combo_1.add("9600");
combo_1.add("19200");
combo_1.add("38400");
combo_1.add("43000");
combo_1.add("56000");
combo_1.add("57600");
combo_1.add("115200");
combo_1.select(5);//
默认选中9600项,与默认波特率一致
combo_1.addSelectionListener(new
SelectionAdapter() {// 选择响应
public
void widgetSelected(SelectionEvent e) {
int
n = combo_1.getSelectionIndex();//
获取选中的选项位置值
bps
= Integer.valueOf(combo_1.getItem(n));//
获取应该设置的值
what2Do
= changePara;
}
});
final Label label_2 = new
Label(group, SWT.NONE);
label_2.setText("校验位");
final Combo combo_2 = new
Combo(group, SWT.NONE);
combo_2.setLayoutData(new
GridData(SWT.FILL, SWT.CENTER, true, false));
combo_2.add("无");
combo_2.add("奇校验");
combo_2.add("偶校验");
combo_2.select(0);//
默认选中校验位为0
combo_2.addSelectionListener(new
SelectionAdapter() {
public void
widgetSelected(SelectionEvent e) {
int
n = combo_2.getSelectionIndex();
paritybit
= n;
what2Do
= changePara;
}
});
final Label label_3 = new
Label(group, SWT.NONE);
label_3.setText("数据位");
final Combo combo_3 = new
Combo(group, SWT.NONE);
combo_3.setLayoutData(new
GridData(SWT.FILL, SWT.CENTER, true, false));
combo_3.add("6");
combo_3.add("7");
combo_3.add("8");
combo_3.select(1);//
默认值为7位
combo_3.addSelectionListener(new
SelectionAdapter() {
public void
widgetSelected(SelectionEvent e) {
int
n = combo_3.getSelectionIndex();
databit
= Integer.valueOf(combo_3.getItem(n));
what2Do
= changePara;
}
});
final Label label_4 = new
Label(group, SWT.NONE);
label_4.setText("停止位");
final Combo combo_4 = new
Combo(group, SWT.NONE);
combo_4.setLayoutData(new
GridData(SWT.FILL, SWT.CENTER, true, false));
combo_4.add("1");
combo_4.add("2");
combo_4.select(0);//
默认值为1位停止位
combo_4.addSelectionListener(new
SelectionAdapter() {
public void
widgetSelected(SelectionEvent e) {
int
n = combo_4.getSelectionIndex();
stopbit
= Integer.valueOf(combo_4.getItem(n));
what2Do
= changePara;
}
});
Canvas sign = new
Canvas(group, SWT.NONE);
sign.setLayoutData(new
GridData(33, 27));
final GC gc = new
GC(sign);
sign.addPaintListener(new
PaintListener() {//
软件打开时,红色,表示打开串口
public
void paintControl(PaintEvent e) {
gc.setBackground(display.getSystemColor(SWT.COLOR_RED));
gc.fillOval(0,
0, 25, 25);
}
});
final Button button = new
Button(group, SWT.NONE);
button.setLayoutData(new
GridData(56, SWT.DEFAULT));
button.setText("关闭串口");
button.addSelectionListener(new
SelectionAdapter() {
public void
widgetSelected(SelectionEvent e) {
if
(button.getText() == "关闭串口") {// 关闭串口
gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
button.setText("打开串口");
what2Do
= closeComm;
}
else {// 打开串口
button.setText("关闭串口");
gc.setBackground(display.getSystemColor(SWT.COLOR_RED));
what2Do
= openComm;
numReceived
= 0;// 计数清空
numSend
= 0;
}
gc.fillOval(0,
0, 25, 25);
}
});
}
private void createCommT() {//
comm的生成和消释都在此线程
commT = new Thread(new
Runnable() {
public void
run() {
boolean
ok = false;
comm
= new Comm();
comm.setName(commname);//
首次执行,创建串口对象
comm.setBps(bps);
comm.setDataBit(databit);
comm.setParityBit(paritybit);
comm.setStopBit(stopbit);
if
(comm.open())
ok
= true;
what2Do
= keepStat;// 保持状态不变
//
管理动态串口对象
while
(true) {
try
{
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
switch
(what2Do) {
case
changePara: {// 改变参数
comm.close();
ok
= false;
comm
= new Comm();
comm.setName(commname);
comm.setBps(bps);
comm.setDataBit(databit);
comm.setParityBit(paritybit);
comm.setStopBit(stopbit);
if
(comm.open())
ok
= true;
what2Do
= keepStat;// 保持状态不变
break;
}
case
closeComm: {// 关闭串口
comm.close();
ok
= false;
what2Do
= keepStat;
break;
}
case
openComm: {// 打开串口
comm
= new Comm();
comm.setName(commname);
comm.setBps(bps);
comm.setDataBit(databit);
comm.setParityBit(paritybit);
comm.setStopBit(stopbit);
if
(comm.open())
ok
= true;// 打开一个串口后,便能存取串口了
what2Do
= keepStat;
break;
}
case
keepStat:// 保持已有的状态
break;
}