Java实现串口通信
- 串口通信
- MODBUS
- Java实现串口通信
- RXTX串口通信开源框架(JAVA)
- 获取设备可以串口
- 打开指定串口
- 设置监听
- 往串口中发送数据
- 从串口中读取数据
- 关闭串口
- 调试工具(自行百度)
- 注意
串口通信
所谓串口,指的是串行通信接口(com),区别于并行通信,一次性可传输8位数据,不会发生数据位序混乱,但是比并行通信传输时间长得多,可以双向通信,主要用于设备与设备之间的通信,常用的主要有两类
1.RS232(一对一数据传输,适合本地设备之间的通信)
2.RS485(一对多数据传输,适合远程设备之间的通信)
MODBUS
应用层面的通信协议,Modbus可使用串口和网线(含光纤)方式进行传输
Java实现串口通信
流程:设置串口通信参数—》打开串口—》发送数据—》获得返回的数据—》解析数据—》关闭串口
RXTX串口通信开源框架(JAVA)
<dependency>
<groupId>org.bidib.jbidib.org.qbang.rxtx</groupId>
<artifactId>rxtxcomm</artifactId>
<version>2.2</version>
</dependency>
获取设备可以串口
Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
打开指定串口
返回一个可用的SerialPort对象,通过这个对象发送数据,接收数据,关闭串口
1.端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个
2.波特率(baudrate),如 9600
3.数据位(datebits),如 SerialPort.DATABITS_8 = 8
4.停止位(stopbits),如 SerialPort.STOPBITS_1 = 1
5.校验位 (parity),如 SerialPort.PARITY_NONE = 0
/**
* 打开电脑上指定的串口
*
* @param portName 端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个
* @param b 波特率(baudrate),如 9600
* @param d 数据位(datebits),如 SerialPort.DATABITS_8 = 8
* @param s 停止位(stopbits),如 SerialPort.STOPBITS_1 = 1
* @param p 校验位 (parity),如 SerialPort.PARITY_NONE = 0
* @return 打开的串口对象,打开失败时,返回 null
*/
public static final SerialPort openComPort(String portName, int b, int d, int s, int p) {
CommPort commPort = null;
try {
//当没有传入可用的 com 口时,默认使用电脑中可用的 com 口中的第一个
if (portName == null || "".equals(portName)) {
List<String> comPortList = findSystemAllComPort();
if (comPortList != null && comPortList.size() > 0) {
portName = comPortList.get(0);
}
}
logger.info("开始打开串口:portName=" + portName + ",baudrate=" + b + ",datebits=" + d + ",stopbits=" + s + ",parity=" + p);
//通过端口名称识别指定 COM 端口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
/**
* open(String TheOwner, int i):打开端口
* TheOwner 自定义一个端口名称,随便自定义即可
* i:打开的端口的超时时间,单位毫秒,超时则抛出异常:PortInUseException if in use.
* 如果此时串口已经被占用,则抛出异常:gnu.io.PortInUseException: Unknown Application
*/
commPort = portIdentifier.open(portName, 5000);
/**
* 判断端口是不是串口
* public abstract class SerialPort extends CommPort
*/
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
/**
* 设置串口参数:setSerialPortParams( int b, int d, int s, int p )
* b:波特率(baudrate)
* d:数据位(datebits),SerialPort 支持 5,6,7,8
* s:停止位(stopbits),SerialPort 支持 1,2,3
* p:校验位 (parity),SerialPort 支持 0,1,2,3,4
* 如果参数设置错误,则抛出异常:gnu.io.UnsupportedCommOperationException: Invalid Parameter
* 此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用
*/
serialPort.setSerialPortParams(b, d, s, p);
logger.info("打开串口 " + portName + " 成功...");
return serialPort;
} else {
logger.error("当前端口 " + commPort.getName() + " 不是串口...");
}
} catch (NoSuchPortException e) {
e.printStackTrace();
} catch (PortInUseException e) {
logger.warn("串口 " + portName + " 已经被占用,请先解除占用...");
e.printStackTrace();
} catch (UnsupportedCommOperationException e) {
logger.warn("串口参数设置错误,关闭串口,数据位[5-8]、停止位[1-3]、验证位[0-4]...");
e.printStackTrace();
if (commPort != null) {//此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用
commPort.close();
}
}
logger.error("打开串口 " + portName + " 失败...");
return null;
}
设置监听
每当事件响应进行对应操作
//设置串口监听
SerialPortTool.setListenerToSerialPort(serialPort, new SerialPortEventListener() {
@Override
public void serialEvent(SerialPortEvent serialPortEvent) {
switch (serialPortEvent.getEventType()) {
case SerialPortEvent.DATA_AVAILABLE: // 1.串口存在有效数据
try {
//读取串口数据
SerialPortTool.readData(serialPort);
} catch (Exception e) {
}
break;
case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2.输出缓冲区已清空
logger.error("输出缓冲区已清空");
break;
case SerialPortEvent.CTS: // 3.清除待发送数据
logger.error("清除待发送数据");
break;
case SerialPortEvent.DSR: // 4.待发送数据准备好了
logger.error("待发送数据准备好了");
break;
case SerialPortEvent.BI: // 10.通讯中断
logger.error("与串口设备通讯中断");
break;
default:
break;
}
}
});
往串口中发送数据
serialPort全局对象发送,参数为byte[]数组(16进制)
/**
* 往串口发送数据
*
* @param serialPort 串口对象
*/
public static void sendDataToComPort(SerialPort serialPort, byte[] orders) {
OutputStream outputStream = null;
try {
if (serialPort != null) {
outputStream = serialPort.getOutputStream();
outputStream.write(orders);
outputStream.flush();
logger.info("往串口 " + serialPort.getName() + " 发送数据:" + Arrays.toString(orders) + " 完成...");
} else {
logger.error("gnu.io.SerialPort 为null,取消数据发送...");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
从串口中读取数据
serialPort全局对象获取
// 从串口读取数据
public static byte[] readData(SerialPort serialPort) {
InputStream is = null;
byte[] bytes = null;
try {
//获得串口的输入流
is = serialPort.getInputStream();
// 通过输入流对象的available方法获取数组字节长度
byte[] readBuffer = new byte[is.available()];
// 从线路上读取数据流
int len = 0;
while ((len = is.read(readBuffer)) != -1) {
// 直接获取到的数据
String a=new String(readBuffer, 0, len);
}
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
关闭串口
/**
* 关闭串口
*
* @param serialPort 待关闭的串口对象
*/
public static void closeComPort(SerialPort serialPort) {
if (serialPort != null) {
serialPort.close();
logger.info("关闭串口 " + serialPort.getName());
}
}
调试工具(自行百度)
笔记本电脑可以使用usb转串口线,安装转串口驱动就可以使用了
注意
串口占用,连接线断开,中文字符乱码处理(字符超过框架设定的字节,比如中文字符)自行转码,接口文档找厂家要。数据转化为16进制再发送。长时间通信就不用关闭串口