本文主要讲述串口调试的Java工具类,并实现循环发送指令,接收数据!!
本文主要实现的功能是调用工具类中打开串口方法,连接传感器所在串口,向串口(传感器)发送指令,并接收串口(传感器)数据。
主函数-----main():
public static void main(String[] args){
SerialTool st =SerialTool.getSerialTool();//实例化一个串口工具类对象
String portName = "COM9";//传感器连接的串口
int baudrate = 9600;//设置波特率
List portNameList = st.findPort();//查询所有可用串口
for(int i=0;i list = serialMessage.dealxml();
while(true){//循环发送指令接收数据
for (Attribute attr : list) {
String order = attr.getValue();//获取指令
order = order.replaceAll(" ", "");
byte[] order1 = hexStringToByteArray(order);//十六进制转字节数组
//发送数据
st.sendToPort(serialPort, order1);
try {
Thread.sleep(2000);//休眠2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
//读取数据
byte[] shuju = st.readFromPort(serialPort);//读取传感器数据
String s=bytesToHex(shuju);//字节数组转16进制
System.out.println("传感器返回数据为:"+s);
ProcessMethod.ZPFunction(s,order);
try {
Thread.sleep(5000);//休眠5秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
byte数组转16进制-----bytesToHex(byte[] bytes):
/**
* byte字节数组转16进制
*/
public static String bytesToHex(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if(hex.length() < 2){
sb.append(0);
}
sb.append(hex);
}
return sb.toString();
}
16进制转byte数组方法-----hexStringToByteArray(String s):
/**
* 16进制转byte数组
*/
public static byte[] hexStringToByteArray(String s){
int len = s.length();
byte[] data = new byte[len / 2];
try {
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
} catch (Exception e) {
}
return data;
}
串口服务工具类-----SerialTool:
package com.njau.serialtool;
import java.io.BufferedInputStream;
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;
/**
* 串口服务类,提供打开、关闭串口,读取、发送串口数据等服务(采用单例设计模式)
* @author njau
*
*/
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 findPort() {
//获得当前所有可用串口
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
ArrayList 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 PortInUseException
* @throws NoSuchPortException
* @throws NotASerialPort 端口指向设备不是串口类型
* @throws NoSuchPort 没有该端口对应的串口设备
* @throws PortInUse 端口已被占用
*/
public static final SerialPort openPort(String portName, int baudrate) throws PortInUseException, NoSuchPortException {
//通过端口名识别端口
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) {
System.out.println("设置串口参数失败!打开串口操作未完成!");
}
System.out.println("Open " + portName + " sucessfully !");
return serialPort;
}
else {
System.out.println("输入端口号不是串口!");
return null;
}
}
/**
* 关闭串口
* @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) {
OutputStream out = null;
try {
out = serialPort.getOutputStream();
out.write(order);
out.flush();
System.out.println("指令发送成功!");
} catch (IOException e) {
System.out.println("串口数据关闭失败!");
} finally {
try {
if (out != null) {
out.close();
out = null;
}
} catch (IOException e) {
System.out.println("串口数据发送流关闭失败!");
}
}
}
/**
* 从串口读取数据
* @param serialPort 当前已建立连接的SerialPort对象
* @return 读取到的数据
* @throws ReadDataFromSerialPortFailure 从串口读取数据时出错
* @throws SerialPortInputStreamCloseFailure 关闭串口对象输入流出错
*/
public static byte[] readFromPort(SerialPort serialPort) {
InputStream in = null;
byte[] bytes = null;
try {
in = new BufferedInputStream(serialPort.getInputStream());//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) {
System.out.println("读取数据失败!");
} finally {
try {
if (in != null) {
in.close();
in = null;
}
} catch(IOException e) {
System.out.println("串口数据读取流关闭失败!");
}
}
return bytes;
}
}
解析指令类-----serialMessage;
package com.njau.serialtool;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class serialMessage {
public static List dealxml(){
List list = new ArrayList();
SAXReader reader = new SAXReader();
try {
// 通过reader对象的read方法加载serialCommand.xml文件,获取docuemnt对象。
Document document = reader.read(new File("src/serialCommand.xml"));
// 通过document对象获取根节点cultivateCodes
Element cultivateCodes = document.getRootElement();
// 通过element对象的elementIterator方法获取迭代器
Iterator it = cultivateCodes.elementIterator();
// 遍历迭代器,获取根节点中的信息
while (it.hasNext()) {
Element code = (Element) it.next();
List codeAttrs = code.attributes();
for (Attribute attr : codeAttrs) {
list.add(attr);
}
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
}
指令配置文件-----serialCommand.xml:
单层基质栽培基质水分传感器01
单层基质栽培基质水分传感器02
通过上述代码可以实现:解析serialCommand.xml中的指令,通过串口将指令发送至传感器,并接收传感器数据