服务器之家

服务器之家 > 正文

使用Java实现串口通信

时间:2020-07-15 12:08     来源/作者:容华谢后

本文实例为大家分享了Java实现串口通信的具体代码,供大家参考,具体内容如下

1.介绍

使用Java实现的串口通信程序,支持十六进制数据的发送与接收。
源码:SerialPortDemo

效果图如下:

使用Java实现串口通信

2.RXTXcomm

Java串口通信依赖的jar包RXTXcomm.jar
下载地址:http://download.csdn.net/detail/kong_gu_you_lan/9611334

内含32位与64位版本
使用方法:
拷贝 RXTXcomm.jar 到 JAVA_HOME\jre\lib\ext目录中;
拷贝 rxtxSerial.dll 到 JAVA_HOME\jre\bin目录中;
拷贝 rxtxParallel.dll 到 JAVA_HOME\jre\bin目录中;
JAVA_HOME为jdk安装路径

3.串口通信管理

SerialPortManager实现了对串口通信的管理,包括查找可用端口、打开关闭串口、发送接收数据。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package com.yang.serialport.manage;
 
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 java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TooManyListenersException;
 
import com.yang.serialport.exception.NoSuchPort;
import com.yang.serialport.exception.NotASerialPort;
import com.yang.serialport.exception.PortInUse;
import com.yang.serialport.exception.ReadDataFromSerialPortFailure;
import com.yang.serialport.exception.SendDataToSerialPortFailure;
import com.yang.serialport.exception.SerialPortInputStreamCloseFailure;
import com.yang.serialport.exception.SerialPortOutputStreamCloseFailure;
import com.yang.serialport.exception.SerialPortParameterFailure;
import com.yang.serialport.exception.TooManyListeners;
 
/**
 * 串口管理
 *
 * @author yangle
 */
public class SerialPortManager {
 
 /**
 * 查找所有可用端口
 *
 * @return 可用端口名称列表
 */
 @SuppressWarnings("unchecked")
 public static final ArrayList<String> findPort() {
 // 获得当前所有可用串口
 Enumeration<CommPortIdentifier> portList = CommPortIdentifier
  .getPortIdentifiers();
 ArrayList<String> portNameList = new ArrayList<String>();
 // 将可用串口名添加到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();
  }
  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();
  // 获取buffer里的数据长度
  int bufflenth = in.available();
  while (bufflenth != 0) {
  // 初始化byte数组为buffer中数据的长度
  bytes = new byte[bufflenth];
  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();
 }
 }
}

4.程序主窗口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/*
 * MainFrame.java
 *
 * Created on 2016.8.19
 */
 
package com.yang.serialport.ui;
 
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
 
import java.awt.Color;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
 
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
 
import com.yang.serialport.exception.NoSuchPort;
import com.yang.serialport.exception.NotASerialPort;
import com.yang.serialport.exception.PortInUse;
import com.yang.serialport.exception.SendDataToSerialPortFailure;
import com.yang.serialport.exception.SerialPortOutputStreamCloseFailure;
import com.yang.serialport.exception.SerialPortParameterFailure;
import com.yang.serialport.exception.TooManyListeners;
import com.yang.serialport.manage.SerialPortManager;
import com.yang.serialport.utils.ByteUtils;
import com.yang.serialport.utils.ShowUtils;
 
/**
 * 主界面
 *
 * @author yangle
 */
public class MainFrame extends JFrame {
 
 /**
 * 程序界面宽度
 */
 public static final int WIDTH = 500;
 
 /**
 * 程序界面高度
 */
 public static final int HEIGHT = 360;
 
 private JTextArea dataView = new JTextArea();
 private JScrollPane scrollDataView = new JScrollPane(dataView);
 
 // 串口设置面板
 private JPanel serialPortPanel = new JPanel();
 private JLabel serialPortLabel = new JLabel("串口");
 private JLabel baudrateLabel = new JLabel("波特率");
 private JComboBox commChoice = new JComboBox();
 private JComboBox baudrateChoice = new JComboBox();
 
 // 操作面板
 private JPanel operatePanel = new JPanel();
 private JTextField dataInput = new JTextField();
 private JButton serialPortOperate = new JButton("打开串口");
 private JButton sendData = new JButton("发送数据");
 
 private List<String> commList = null;
 private SerialPort serialport;
 
 public MainFrame() {
 initView();
 initComponents();
 actionListener();
 initData();
 }
 
 private void initView() {
 // 关闭程序
 setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
 // 禁止窗口最大化
 setResizable(false);
 
 // 设置程序窗口居中显示
 Point p = GraphicsEnvironment.getLocalGraphicsEnvironment()
  .getCenterPoint();
 setBounds(p.x - WIDTH / 2, p.y - HEIGHT / 2, WIDTH, HEIGHT);
 this.setLayout(null);
 
 setTitle("串口通讯");
 }
 
 private void initComponents() {
 // 数据显示
 dataView.setFocusable(false);
 scrollDataView.setBounds(10, 10, 475, 200);
 add(scrollDataView);
 
 // 串口设置
 serialPortPanel.setBorder(BorderFactory.createTitledBorder("串口设置"));
 serialPortPanel.setBounds(10, 220, 170, 100);
 serialPortPanel.setLayout(null);
 add(serialPortPanel);
 
 serialPortLabel.setForeground(Color.gray);
 serialPortLabel.setBounds(10, 25, 40, 20);
 serialPortPanel.add(serialPortLabel);
 
 commChoice.setFocusable(false);
 commChoice.setBounds(60, 25, 100, 20);
 serialPortPanel.add(commChoice);
 
 baudrateLabel.setForeground(Color.gray);
 baudrateLabel.setBounds(10, 60, 40, 20);
 serialPortPanel.add(baudrateLabel);
 
 baudrateChoice.setFocusable(false);
 baudrateChoice.setBounds(60, 60, 100, 20);
 serialPortPanel.add(baudrateChoice);
 
 // 操作
 operatePanel.setBorder(BorderFactory.createTitledBorder("操作"));
 operatePanel.setBounds(200, 220, 285, 100);
 operatePanel.setLayout(null);
 add(operatePanel);
 
 dataInput.setBounds(25, 25, 235, 20);
 operatePanel.add(dataInput);
 
 serialPortOperate.setFocusable(false);
 serialPortOperate.setBounds(45, 60, 90, 20);
 operatePanel.add(serialPortOperate);
 
 sendData.setFocusable(false);
 sendData.setBounds(155, 60, 90, 20);
 operatePanel.add(sendData);
 }
 
 @SuppressWarnings("unchecked")
 private void initData() {
 commList = SerialPortManager.findPort();
 // 检查是否有可用串口,有则加入选项中
 if (commList == null || commList.size() < 1) {
  ShowUtils.warningMessage("没有搜索到有效串口!");
 } else {
  for (String s : commList) {
  commChoice.addItem(s);
  }
 }
 
 baudrateChoice.addItem("9600");
 baudrateChoice.addItem("19200");
 baudrateChoice.addItem("38400");
 baudrateChoice.addItem("57600");
 baudrateChoice.addItem("115200");
 }
 
 private void actionListener() {
 serialPortOperate.addActionListener(new ActionListener() {
 
  @Override
  public void actionPerformed(ActionEvent e) {
  if ("打开串口".equals(serialPortOperate.getText())
   && serialport == null) {
   openSerialPort(e);
  } else {
   closeSerialPort(e);
  }
  }
 });
 
 sendData.addActionListener(new ActionListener() {
 
  @Override
  public void actionPerformed(ActionEvent e) {
  sendData(e);
  }
 });
 }
 
 /**
 * 打开串口
 *
 * @param evt
 *  点击事件
 */
 private void openSerialPort(java.awt.event.ActionEvent evt) {
 // 获取串口名称
 String commName = (String) commChoice.getSelectedItem();
 // 获取波特率
 int baudrate = 9600;
 String bps = (String) baudrateChoice.getSelectedItem();
 baudrate = Integer.parseInt(bps);
 
 // 检查串口名称是否获取正确
 if (commName == null || commName.equals("")) {
  ShowUtils.warningMessage("没有搜索到有效串口!");
 } else {
  try {
  serialport = SerialPortManager.openPort(commName, baudrate);
  if (serialport != null) {
   dataView.setText("串口已打开" + "\r\n");
   serialPortOperate.setText("关闭串口");
  }
  } catch (SerialPortParameterFailure e) {
  e.printStackTrace();
  } catch (NotASerialPort e) {
  e.printStackTrace();
  } catch (NoSuchPort e) {
  e.printStackTrace();
  } catch (PortInUse e) {
  e.printStackTrace();
  ShowUtils.warningMessage("串口已被占用!");
  }
 }
 
 try {
  SerialPortManager.addListener(serialport, new SerialListener());
 } catch (TooManyListeners e) {
  e.printStackTrace();
 }
 }
 
 /**
 * 关闭串口
 *
 * @param evt
 *  点击事件
 */
 private void closeSerialPort(java.awt.event.ActionEvent evt) {
 SerialPortManager.closePort(serialport);
 dataView.setText("串口已关闭" + "\r\n");
 serialPortOperate.setText("打开串口");
 }
 
 /**
 * 发送数据
 *
 * @param evt
 *  点击事件
 */
 private void sendData(java.awt.event.ActionEvent evt) {
 // 输入框直接输入十六进制字符,长度必须是偶数
 String data = dataInput.getText().toString();
 try {
  SerialPortManager.sendToPort(serialport,
   ByteUtils.hexStr2Byte(data));
 } catch (SendDataToSerialPortFailure e) {
  e.printStackTrace();
 } catch (SerialPortOutputStreamCloseFailure e) {
  e.printStackTrace();
 }
 }
 
 private class SerialListener implements SerialPortEventListener {
 /**
  * 处理监控到的串口事件
  */
 public void serialEvent(SerialPortEvent serialPortEvent) {
 
  switch (serialPortEvent.getEventType()) {
 
  case SerialPortEvent.BI: // 10 通讯中断
  ShowUtils.errorMessage("与串口设备通讯中断");
  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 串口存在可用数据
  byte[] data = null;
  try {
   if (serialport == null) {
   ShowUtils.errorMessage("串口对象为空!监听失败!");
   } else {
   // 读取串口数据
   data = SerialPortManager.readFromPort(serialport);
   dataView.append(ByteUtils.byteArrayToHexString(data,
    true) + "\r\n");
   }
  } catch (Exception e) {
   ShowUtils.errorMessage(e.toString());
   // 发生读取错误时显示错误信息后退出系统
   System.exit(0);
  }
  break;
  }
 }
 }
 
 public static void main(String args[]) {
 java.awt.EventQueue.invokeLater(new Runnable() {
  public void run() {
  new MainFrame().setVisible(true);
  }
 });
 }
}

5.写在最后

源码下载地址:SerialPortDemo

欢迎同学们吐槽评论,如果你觉得本篇博客对你有用,那么就留个言或者顶一下吧(^-^)

感谢:基于Java编写串口通信工具

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://blog.csdn.net/kong_gu_you_lan/article/details/52302075

标签:

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享 2020-04-07
男生常说24816是什么意思?女生说13579是什么意思?
男生常说24816是什么意思?女生说13579是什么意思? 2019-09-17
沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意
沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意 2019-07-07
玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分
玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分 2019-06-21
返回顶部