使用Java实现简单串口通信
最近一门课要求编写一个上位机串口通信工具,我基于Java编写了一个带有图形界面的简单串口通信工具,下面详述一下过程,供大家参考 ^_^
一:
首先,你需要下载一个额外的支持Java串口通信操作的jar包,由于java.comm比较老了,而且不支持64位系统,这里推荐Rxtx这个jar包(32位/64位均支持)。
官方下载地址:http://fizzed.com/oss/rxtx-for-java (注:可能需要翻墙才能下载)
不能翻墙的童鞋,可以在这里下载:
http://files.cnblogs.com/files/Dreamer-1/mfz-rxtx-2.2-20081207-win-x86.zip (32位)
http://files.cnblogs.com/files/Dreamer-1/mfz-rxtx-2.2-20081207-win-x64.zip (64位)
二:
下载解压jar包并在 Java Build Path 下引入:
注:如果运行过程中抛出 java.lang.UnsatisfiedLinkError 错误或 gnu.io 下的类找不到,请将rxtx解压包中的 rxtxParallel.dll,rxtxSerial.dll 这两个文件复制到 C:\Windows\System32 目录下即可解决该错误。
三:
关于该jar包的使用,我写了一个SerialTool.java类,该类提供关于串口通信的各简单服务,代码如下(注意该类位于 serialPort 包里):
package serialPort; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TooManyListenersException; import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import serialException.*; /**
* 串口服务类,提供打开、关闭串口,读取、发送串口数据等服务(采用单例设计模式)
* @author zhong
*
*/
public class SerialTool { private static SerialTool serialTool = null; static {
//在该类被ClassLoader加载时就初始化一个SerialTool对象
if (serialTool == null) {
serialTool = new SerialTool();
}
} //私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象
private SerialTool() {} /**
* 获取提供服务的SerialTool对象
* @return serialTool
*/
public static SerialTool getSerialTool() {
if (serialTool == null) {
serialTool = new SerialTool();
}
return serialTool;
} /**
* 查找所有可用端口
* @return 可用端口名称列表
*/
public static final ArrayList<String> findPort() { //获得当前所有可用串口
Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portNameList = new ArrayList<>(); //将可用串口名添加到List并返回该List
while (portList.hasMoreElements()) {
String portName = portList.nextElement().getName();
portNameList.add(portName);
} return portNameList; } /**
* 打开串口
* @param portName 端口名称
* @param baudrate 波特率
* @return 串口对象
* @throws SerialPortParameterFailure 设置串口参数失败
* @throws NotASerialPort 端口指向设备不是串口类型
* @throws NoSuchPort 没有该端口对应的串口设备
* @throws PortInUse 端口已被占用
*/
public static final SerialPort openPort(String portName, int baudrate) throws SerialPortParameterFailure, NotASerialPort, NoSuchPort, PortInUse { try { //通过端口名识别端口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); //打开端口,并给端口名字和一个timeout(打开操作的超时时间)
CommPort commPort = portIdentifier.open(portName, 2000); //判断是不是串口
if (commPort instanceof SerialPort) { SerialPort serialPort = (SerialPort) commPort; try {
//设置一下串口的波特率等参数
serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {
throw new SerialPortParameterFailure();
} //System.out.println("Open " + portName + " sucessfully !");
return serialPort; }
else {
//不是串口
throw new NotASerialPort();
}
} catch (NoSuchPortException e1) {
throw new NoSuchPort();
} catch (PortInUseException e2) {
throw new PortInUse();
}
} /**
* 关闭串口
* @param serialport 待关闭的串口对象
*/
public static void closePort(SerialPort serialPort) {
if (serialPort != null) {
serialPort.close();
serialPort = null;
}
} /**
* 往串口发送数据
* @param serialPort 串口对象
* @param order 待发送数据
* @throws SendDataToSerialPortFailure 向串口发送数据失败
* @throws SerialPortOutputStreamCloseFailure 关闭串口对象的输出流出错
*/
public static void sendToPort(SerialPort serialPort, byte[] order) throws SendDataToSerialPortFailure, SerialPortOutputStreamCloseFailure { OutputStream out = null; try { out = serialPort.getOutputStream();
out.write(order);
out.flush(); } catch (IOException e) {
throw new SendDataToSerialPortFailure();
} finally {
try {
if (out != null) {
out.close();
out = null;
}
} catch (IOException e) {
throw new SerialPortOutputStreamCloseFailure();
}
} } /**
* 从串口读取数据
* @param serialPort 当前已建立连接的SerialPort对象
* @return 读取到的数据
* @throws ReadDataFromSerialPortFailure 从串口读取数据时出错
* @throws SerialPortInputStreamCloseFailure 关闭串口对象输入流出错
*/
public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailure, SerialPortInputStreamCloseFailure { InputStream in = null;
byte[] bytes = null; try { in = serialPort.getInputStream();
int bufflenth = in.available(); //获取buffer里的数据长度 while (bufflenth != 0) {
bytes = new byte[bufflenth]; //初始化byte数组为buffer中数据的长度
in.read(bytes);
bufflenth = in.available();
}
} catch (IOException e) {
throw new ReadDataFromSerialPortFailure();
} finally {
try {
if (in != null) {
in.close();
in = null;
}
} catch(IOException e) {
throw new SerialPortInputStreamCloseFailure();
} } return bytes; } /**
* 添加监听器
* @param port 串口对象
* @param listener 串口监听器
* @throws TooManyListeners 监听类对象过多
*/
public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListeners { try { //给串口添加监听器
port.addEventListener(listener);
//设置当有数据到达时唤醒监听接收线程
port.notifyOnDataAvailable(true);
//设置当通信中断时唤醒中断线程
port.notifyOnBreakInterrupt(true); } catch (TooManyListenersException e) {
throw new TooManyListeners();
}
} }
注:该类方法中 throw 的 Exception 都是我自定义的 Exception,之所以这么做是为了方便在主程序中进行相应处理,下面贴其中一个Exception出来给大家做下说明:
(注意我所有自定义的 Exception 都放在 serialException 包里)
package serialException; public class SerialPortParameterFailure extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L; public SerialPortParameterFailure() {} @Override
public String toString() {
return "设置串口参数失败!打开串口操作未完成!";
} }
每个自定义的Exception类我都重写了它的 toString() 方法,便于主程序捕捉到该Exception后打印对应的错误信息
其中在serialException包里还有一个专门将接收到的Exception对象内的错误信息提取出来转换成字符串并返回的类,代码如下:
package serialException; import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter; /**
* 负责将传入的Exception中的错误信息提取出来并转换成字符串;
* @author zhong
*
*/
public class ExceptionWriter { /**
* 将Exception中的错误信息封装到字符串中并返回该字符串
* @param e 包含错误的Exception
* @return 错误信息字符串
*/
public static String getErrorInfoFromException(Exception e) { StringWriter sw = null;
PrintWriter pw = null; try {
sw = new StringWriter();
pw = new PrintWriter(sw);
e.printStackTrace(pw);
return "\r\n" + sw.toString() + "\r\n"; } catch (Exception e2) {
return "出错啦!未获取到错误信息,请检查后重试!";
} finally {
try {
if (pw != null) {
pw.close();
}
if (sw != null) {
sw.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
四:
主程序类的使用,Client.java里含有程序的入口地址(main方法),它的作用是显示一个欢迎界面并调用DataView.java这个类进行实际的串口数据显示。
Client.java代码如下:
package serialPort; import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import javax.swing.JOptionPane; import serialException.ExceptionWriter; /**
* 主程序
* @author zhong
*
*/
public class Client extends Frame{ /**
*
*/
private static final long serialVersionUID = 1L; /**
* 程序界面宽度
*/
public static final int WIDTH = 800; /**
* 程序界面高度
*/
public static final int HEIGHT = 620; /**
* 程序界面出现位置(横坐标)
*/
public static final int LOC_X = 200; /**
* 程序界面出现位置(纵坐标)
*/
public static final int LOC_Y = 70; Color color = Color.WHITE;
Image offScreen = null; //用于双缓冲 //设置window的icon(这里我自定义了一下Windows窗口的icon图标,因为实在觉得哪个小咖啡图标不好看 = =)
Toolkit toolKit = getToolkit();
Image icon = toolKit.getImage(Client.class.getResource("computer.png")); //持有其他类
DataView dataview = new DataView(this); //主界面类(显示监控数据主面板) /**
* 主方法
* @param args //
*/
public static void main(String[] args) {
new Client().launchFrame();
} /**
* 显示主界面
*/
public void launchFrame() {
this.setBounds(LOC_X, LOC_Y, WIDTH, HEIGHT); //设定程序在桌面出现的位置
this.setTitle("CDIO工程项目"); //设置程序标题
this.setIconImage(icon);
this.setBackground(Color.white); //设置背景色 this.addWindowListener(new WindowAdapter() {
//添加对窗口状态的监听
public void windowClosing(WindowEvent arg0) {
//当窗口关闭时
System.exit(0); //退出程序
} }); this.addKeyListener(new KeyMonitor()); //添加键盘监听器
this.setResizable(false); //窗口大小不可更改
this.setVisible(true); //显示窗口 new Thread(new RepaintThread()).start(); //开启重画线程
} /**
* 画出程序界面各组件元素
*/
public void paint(Graphics g) {
Color c = g.getColor(); g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.setColor(Color.black);
g.drawString("欢迎使用上位机实时监控系统", 45, 190); g.setFont(new Font("微软雅黑", Font.ITALIC, 26));
g.setColor(Color.BLACK);
g.drawString("Version:1.0 Powered By:ZhongLei", 280, 260); g.setFont(new Font("微软雅黑", Font.BOLD, 30));
g.setColor(color);
g.drawString("————点击Enter键进入主界面————", 100, 480);
//使文字 "————点击Enter键进入主界面————" 黑白闪烁
if (color == Color.WHITE) color = Color.black;
else if (color == color.BLACK) color = Color.white; } /**
* 双缓冲方式重画界面各元素组件
*/
public void update(Graphics g) {
if (offScreen == null) offScreen = this.createImage(WIDTH, HEIGHT);
Graphics gOffScreen = offScreen.getGraphics();
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.white);
gOffScreen.fillRect(0, 0, WIDTH, HEIGHT); //重画背景画布
this.paint(gOffScreen); //重画界面元素
gOffScreen.setColor(c);
g.drawImage(offScreen, 0, 0, null); //将新画好的画布“贴”在原画布上
} /*
* 内部类形式实现对键盘事件的监听
*/
private class KeyMonitor extends KeyAdapter { public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_ENTER) { //当监听到用户敲击键盘enter键后执行下面的操作
setVisible(false); //隐去欢迎界面
dataview.setVisible(true); //显示监测界面
dataview.dataFrame(); //初始化监测界面
}
} } /*
* 重画线程(每隔250毫秒重画一次)
*/
private class RepaintThread implements Runnable {
public void run() {
while(true) {
repaint();
try {
Thread.sleep(250);
} catch (InterruptedException e) {
//重画线程出错抛出异常时创建一个Dialog并显示异常详细信息
String err = ExceptionWriter.getErrorInfoFromException(e);
JOptionPane.showMessageDialog(null, err, "错误", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
} } }
运行截图:
注:实际运行过程中最下面的“点击Enter键进入主界面”有一个一闪一闪的效果(是通过每隔一段时间重画一次界面,让这句话以白黑两色反复交替出现实现的),双缓冲方式利于解决重画时界面闪烁的问题(如果不使用双缓冲方式的话相当于每次重画时是在旧界面上一点一点画上新东西,而双缓冲实质上是通过先在内存中直接画好一张新界面图,然后一次性直接用新界面覆盖掉旧界面)
DataView.java代码如下:(该类用于实时显示串口数据)
简单说明:
硬件设备每隔一段时间通过串口发送一次数据到计算机,该串口工具成功连接至硬件设备并添加监听后,会在每次接收到数据时解析数据并更新界面;
你在使用时很可能需求跟我不一样,该类仅供参考,实际使用中你很可能需要重新制作数据显示界面以及数据解析方式
package serialPort; import java.awt.Button;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Label;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import java.util.TooManyListenersException; import javax.swing.JOptionPane; import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import serialException.*; /**
* 监测数据显示类
* @author Zhong
*
*/
public class DataView extends Frame { /**
*
*/
private static final long serialVersionUID = 1L; Client client = null; private List<String> commList = null; //保存可用端口号
private SerialPort serialPort = null; //保存串口对象 private Font font = new Font("微软雅黑", Font.BOLD, 25); private Label tem = new Label("暂无数据", Label.CENTER); //温度
private Label hum = new Label("暂无数据", Label.CENTER); //湿度
private Label pa = new Label("暂无数据", Label.CENTER); //压强
private Label rain = new Label("暂无数据", Label.CENTER); //雨量
private Label win_sp = new Label("暂无数据", Label.CENTER); //风速
private Label win_dir = new Label("暂无数据", Label.CENTER); //风向 private Choice commChoice = new Choice(); //串口选择(下拉框)
private Choice bpsChoice = new Choice(); //波特率选择 private Button openSerialButton = new Button("打开串口"); Image offScreen = null; //重画时的画布 //设置window的icon
Toolkit toolKit = getToolkit();
Image icon = toolKit.getImage(DataView.class.getResource("computer.png")); /**
* 类的构造方法
* @param client
*/
public DataView(Client client) {
this.client = client;
commList = SerialTool.findPort(); //程序初始化时就扫描一次有效串口
} /**
* 主菜单窗口显示;
* 添加Label、按钮、下拉条及相关事件监听;
*/
public void dataFrame() {
this.setBounds(client.LOC_X, client.LOC_Y, client.WIDTH, client.HEIGHT);
this.setTitle("CDIO工程项目");
this.setIconImage(icon);
this.setBackground(Color.white);
this.setLayout(null); this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent arg0) {
if (serialPort != null) {
//程序退出时关闭串口释放资源
SerialTool.closePort(serialPort);
}
System.exit(0);
} }); tem.setBounds(140, 103, 225, 50);
tem.setBackground(Color.black);
tem.setFont(font);
tem.setForeground(Color.white);
add(tem); hum.setBounds(520, 103, 225, 50);
hum.setBackground(Color.black);
hum.setFont(font);
hum.setForeground(Color.white);
add(hum); pa.setBounds(140, 193, 225, 50);
pa.setBackground(Color.black);
pa.setFont(font);
pa.setForeground(Color.white);
add(pa); rain.setBounds(520, 193, 225, 50);
rain.setBackground(Color.black);
rain.setFont(font);
rain.setForeground(Color.white);
add(rain); win_sp.setBounds(140, 283, 225, 50);
win_sp.setBackground(Color.black);
win_sp.setFont(font);
win_sp.setForeground(Color.white);
add(win_sp); win_dir.setBounds(520, 283, 225, 50);
win_dir.setBackground(Color.black);
win_dir.setFont(font);
win_dir.setForeground(Color.white);
add(win_dir); //添加串口选择选项
commChoice.setBounds(160, 397, 200, 200);
//检查是否有可用串口,有则加入选项中
if (commList == null || commList.size()<1) {
JOptionPane.showMessageDialog(null, "没有搜索到有效串口!", "错误", JOptionPane.INFORMATION_MESSAGE);
}
else {
for (String s : commList) {
commChoice.add(s);
}
}
add(commChoice); //添加波特率选项
bpsChoice.setBounds(526, 396, 200, 200);
bpsChoice.add("1200");
bpsChoice.add("2400");
bpsChoice.add("4800");
bpsChoice.add("9600");
bpsChoice.add("14400");
bpsChoice.add("19200");
bpsChoice.add("115200");
add(bpsChoice); //添加打开串口按钮
openSerialButton.setBounds(250, 490, 300, 50);
openSerialButton.setBackground(Color.lightGray);
openSerialButton.setFont(new Font("微软雅黑", Font.BOLD, 20));
openSerialButton.setForeground(Color.darkGray);
add(openSerialButton);
//添加打开串口按钮的事件监听
openSerialButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //获取串口名称
String commName = commChoice.getSelectedItem();
//获取波特率
String bpsStr = bpsChoice.getSelectedItem(); //检查串口名称是否获取正确
if (commName == null || commName.equals("")) {
JOptionPane.showMessageDialog(null, "没有搜索到有效串口!", "错误", JOptionPane.INFORMATION_MESSAGE);
}
else {
//检查波特率是否获取正确
if (bpsStr == null || bpsStr.equals("")) {
JOptionPane.showMessageDialog(null, "波特率获取错误!", "错误", JOptionPane.INFORMATION_MESSAGE);
}
else {
//串口名、波特率均获取正确时
int bps = Integer.parseInt(bpsStr);
try { //获取指定端口名及波特率的串口对象
serialPort = SerialTool.openPort(commName, bps);
//在该串口对象上添加监听器
SerialTool.addListener(serialPort, new SerialListener());
//监听成功进行提示
JOptionPane.showMessageDialog(null, "监听成功,稍后将显示监测数据!", "提示", JOptionPane.INFORMATION_MESSAGE); } catch (SerialPortParameterFailure | NotASerialPort | NoSuchPort | PortInUse | TooManyListeners e1) {
//发生错误时使用一个Dialog提示具体的错误信息
JOptionPane.showMessageDialog(null, e1, "错误", JOptionPane.INFORMATION_MESSAGE);
}
}
} }
}); this.setResizable(false); new Thread(new RepaintThread()).start(); //启动重画线程 } /**
* 画出主界面组件元素
*/
public void paint(Graphics g) {
Color c = g.getColor(); g.setColor(Color.black);
g.setFont(new Font("微软雅黑", Font.BOLD, 25));
g.drawString(" 温度: ", 45, 130); g.setColor(Color.black);
g.setFont(new Font("微软雅黑", Font.BOLD, 25));
g.drawString(" 湿度: ", 425, 130); g.setColor(Color.black);
g.setFont(new Font("微软雅黑", Font.BOLD, 25));
g.drawString(" 压强: ", 45, 220); g.setColor(Color.black);
g.setFont(new Font("微软雅黑", Font.BOLD, 25));
g.drawString(" 雨量: ", 425, 220); g.setColor(Color.black);
g.setFont(new Font("微软雅黑", Font.BOLD, 25));
g.drawString(" 风速: ", 45, 310); g.setColor(Color.black);
g.setFont(new Font("微软雅黑", Font.BOLD, 25));
g.drawString(" 风向: ", 425, 310); g.setColor(Color.gray);
g.setFont(new Font("微软雅黑", Font.BOLD, 20));
g.drawString(" 串口选择: ", 45, 410); g.setColor(Color.gray);
g.setFont(new Font("微软雅黑", Font.BOLD, 20));
g.drawString(" 波特率: ", 425, 410); } /**
* 双缓冲方式重画界面各元素组件
*/
public void update(Graphics g) {
if (offScreen == null) offScreen = this.createImage(Client.WIDTH, Client.HEIGHT);
Graphics gOffScreen = offScreen.getGraphics();
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.white);
gOffScreen.fillRect(0, 0, Client.WIDTH, Client.HEIGHT); //重画背景画布
this.paint(gOffScreen); //重画界面元素
gOffScreen.setColor(c);
g.drawImage(offScreen, 0, 0, null); //将新画好的画布“贴”在原画布上
} /*
* 重画线程(每隔30毫秒重画一次)
*/
private class RepaintThread implements Runnable {
public void run() {
while(true) {
//调用重画方法
repaint(); //扫描可用串口
commList = SerialTool.findPort();
if (commList != null && commList.size()>0) { //添加新扫描到的可用串口
for (String s : commList) { //该串口名是否已存在,初始默认为不存在(在commList里存在但在commChoice里不存在,则新添加)
boolean commExist = false; for (int i=0; i<commChoice.getItemCount(); i++) {
if (s.equals(commChoice.getItem(i))) {
//当前扫描到的串口名已经在初始扫描时存在
commExist = true;
break;
}
} if (commExist) {
//当前扫描到的串口名已经在初始扫描时存在,直接进入下一次循环
continue;
}
else {
//若不存在则添加新串口名至可用串口下拉列表
commChoice.add(s);
}
} //移除已经不可用的串口
for (int i=0; i<commChoice.getItemCount(); i++) { //该串口是否已失效,初始默认为已经失效(在commChoice里存在但在commList里不存在,则已经失效)
boolean commNotExist = true; for (String s : commList) {
if (s.equals(commChoice.getItem(i))) {
commNotExist = false;
break;
}
} if (commNotExist) {
//System.out.println("remove" + commChoice.getItem(i));
commChoice.remove(i);
}
else {
continue;
}
} }
else {
//如果扫描到的commList为空,则移除所有已有串口
commChoice.removeAll();
} try {
Thread.sleep(30);
} catch (InterruptedException e) {
String err = ExceptionWriter.getErrorInfoFromException(e);
JOptionPane.showMessageDialog(null, err, "错误", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
} } /**
* 以内部类形式创建一个串口监听类
* @author zhong
*
*/
private class SerialListener implements SerialPortEventListener { /**
* 处理监控到的串口事件
*/
public void serialEvent(SerialPortEvent serialPortEvent) { switch (serialPortEvent.getEventType()) { case SerialPortEvent.BI: // 10 通讯中断
JOptionPane.showMessageDialog(null, "与串口设备通讯中断", "错误", JOptionPane.INFORMATION_MESSAGE);
break; case SerialPortEvent.OE: // 7 溢位(溢出)错误 case SerialPortEvent.FE: // 9 帧错误 case SerialPortEvent.PE: // 8 奇偶校验错误 case SerialPortEvent.CD: // 6 载波检测 case SerialPortEvent.CTS: // 3 清除待发送数据 case SerialPortEvent.DSR: // 4 待发送数据准备好了 case SerialPortEvent.RI: // 5 振铃指示 case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 输出缓冲区已清空
break; case SerialPortEvent.DATA_AVAILABLE: // 1 串口存在可用数据 //System.out.println("found data");
byte[] data = null; try {
if (serialPort == null) {
JOptionPane.showMessageDialog(null, "串口对象为空!监听失败!", "错误", JOptionPane.INFORMATION_MESSAGE);
}
else {
data = SerialTool.readFromPort(serialPort); //读取数据,存入字节数组
//System.out.println(new String(data)); // 自定义解析过程,你在实际使用过程中可以按照自己的需求在接收到数据后对数据进行解析
if (data == null || data.length < 1) { //检查数据是否读取正确
JOptionPane.showMessageDialog(null, "读取数据过程中未获取到有效数据!请检查设备或程序!", "错误", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
else {
String dataOriginal = new String(data); //将字节数组数据转换位为保存了原始数据的字符串
String dataValid = ""; //有效数据(用来保存原始数据字符串去除最开头*号以后的字符串)
String[] elements = null; //用来保存按空格拆分原始字符串后得到的字符串数组
//解析数据
if (dataOriginal.charAt(0) == '*') { //当数据的第一个字符是*号时表示数据接收完成,开始解析
dataValid = dataOriginal.substring(1);
elements = dataValid.split(" ");
if (elements == null || elements.length < 1) { //检查数据是否解析正确
JOptionPane.showMessageDialog(null, "数据解析过程出错,请检查设备或程序!", "错误", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
else {
try {
//更新界面Label值
/*for (int i=0; i<elements.length; i++) {
System.out.println(elements[i]);
}*/
//System.out.println("win_dir: " + elements[5]);
tem.setText(elements[0] + " ℃");
hum.setText(elements[1] + " %");
pa.setText(elements[2] + " hPa");
rain.setText(elements[3] + " mm");
win_sp.setText(elements[4] + " m/s");
win_dir.setText(elements[5] + " °");
} catch (ArrayIndexOutOfBoundsException e) {
JOptionPane.showMessageDialog(null, "数据解析过程出错,更新界面数据失败!请检查设备或程序!", "错误", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
}
} } } catch (ReadDataFromSerialPortFailure | SerialPortInputStreamCloseFailure e) {
JOptionPane.showMessageDialog(null, e, "错误", JOptionPane.INFORMATION_MESSAGE);
System.exit(0); //发生读取错误时显示错误信息后退出系统
} break; } } } }
运行截图:
整个项目源码打包下载:http://files.cnblogs.com/files/Dreamer-1/serialMonitor.rar
使用Java实现简单串口通信的更多相关文章
- java下的串口通信-RXTX
关于java实现的串口通信,使用的是开源项目RXTX,之前sun公司也有JCL项目,不过已经很久没有更新了,RXTX项目地址:点击打开,但是两个项目的API用法是一样的,只是导入的包不一样而已.简单的 ...
- C#串口介绍以及简单串口通信程序设计实现
C#串口介绍以及简单串口通信程序设计实现 周末,没事干,写个简单的串口通信工具,也算是本周末曾来过,废话不多,直接到主题 串口介绍 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口) ...
- Java实现RS485串口通信,发送和接收数据进行解析
最近项目有一个空气检测仪,需要得到空气检测仪的实时数据,保存到数据库当中.根据了解得到,硬件是通过rs485进行串口通讯的,需要发送16进制命令给仪器,然后通过轮询来得到数据. 需要先要下载RXTX的 ...
- Java实现RS485串口通信
前言 前段时间赶项目的过程中,遇到一个调用RS485串口通信的需求,赶完项目因为楼主处理私事,没来得及完成文章的更新,现在终于可以整理一下当时的demo,记录下来. 首先说一下大概需求:这个项目是机器 ...
- java可用与串口通信的一些库
java原生对串口的支持只有javax.comm,javax.comm比较老了,而且不支持64位系统,我在看jlibmodbus(一个java实现的modbus协议栈)的时候发现了几个可供使用的jav ...
- java 串口通信 代码
下面是我自己实现的串口接收的类,串口发送比较简单,就直接发送就可以了.下面的这个类可以直接使用. package com.boomdts.weather_monitor.util; import ja ...
- Java串口通信具体解释
序言 说到开源,恐怕非常少有人不挑大指称赞.学生通过开源码学到了知识,程序猿通过开源类库获得了别人的成功经验及可以按时完毕手头的project,商家通过开源软件赚到了钱……,总之是皆大欢喜.然而开源软 ...
- Java实现串口通信的小样例
用Java实现串口通信(windows系统下),须要用到sun提供的串口包 javacomm20-win32.zip.当中要用到三个文件,配置例如以下: 1.comm.jar放置到 JAVA_HOME ...
- Java串口通信详细解释
前言 说到开源.恐怕非常少有人不挑大指称赞. 学生通过开源码学到了知识,程序猿通过开源类库获得了别人的成功经验及可以按时完毕手头的project,商家通过开源软件赚到了钱……,总之是皆大欢喜. 然而开 ...
随机推荐
- DotNet项目中的一些常用验证操作
在项目中需要对用户输入的信息,以及一些方法生成的结果进行验证,一般在项目中较多的采用js插件或js来进行有关信息的校验,但是从项目安全性的角度进行考虑,可对系统进行js注入. 如果在后台对用户输入的信 ...
- javascript超过容器后显示省略号效果(兼容一行或者多行)
javascript超过容器后显示省略号效果 在实际的项目中,由于文字内容的长度不确定性和页面布局的固定性,难免会出现文字内容超过div(或其他标签,下同)区域的情况,此时比较好的做法就是 ...
- LinQ C#防注入式攻击实例代码
注入式攻击是Web开放项目中开发人员的第一时间要考虑的问题,下面就我的开发实例分享给大家,有用的的话就点个赞吧. 定義賬戶信息類 public class UserInfors { public st ...
- Java中,包的概念、常量、静态成员、继承
新建包:左上角-新建-包 命名规则(通常从大到小,方便整合不容易冲突) 例如:com.itnba.maya.test package必须在最顶行,之前不能再有其他代码 使用包: 快捷方式:使用包中的 ...
- python PIL比较图片像素
# -*- coding: utf-8 -*- from PIL import Image from pylab import * def compare_pic_L(pic1,pic2): #打开第 ...
- 前端实战Demo:一张图片搞定一页布局
对前端程序员来说,从设计师的手中拿过设计图和素材之后根据需要进行切图是必要的基本功,但是一般的程序员可能对切图并非那么熟悉,所以可能有很多时间都花在使用Photoshop上,那么这里就有一种方法可以减 ...
- Netty(二)入门
在上篇<Netty(一)引题>中,分别对AIO,BIO,PIO,NIO进行了简单的阐述,并写了简单的demo.但是这里说的简单,我也只能呵呵了,特别是NIO.AIO(我全手打的,好麻烦). ...
- Manage application.conf in several environments
When you work in a team, different developers will use different configuration keys in theirapplicat ...
- OData V4 学习目录
开放数据协议(Open Data Protocol,缩写OData)是一种描述如何创建和访问Restful服务的OASIS标准. Open Data Protocol (开放数据协议,OData)是用 ...
- #9.5课堂JS总结#循环语句、函数
一.循环语句 1.for循环 下面是 for 循环的语法: for (语句 1; 语句 2; 语句 3) { 被执行的代码块 } 语句 1 在循环(代码块)开始前执行 语句 2 定义运行循环(代码块) ...