概述
串口数据读取类,用于windows的串口数据读取;
1.例如观察者为羊,被观察者为狼 ,模仿的场景为狼叫羊跑,可参考博客:
https://blog.csdn.net/dada360778512/article/details/6977758
2.模拟串口传输数据,需要两个工具,Virtual Serial Port Driver、串口调试助手;可参考:
https://jingyan.baidu.com/article/046a7b3eae7028f9c27fa9f7.html
3.基于RXTX(提供串口和并口通信)开源类库对串口进行操作的。具体配置,详见:
https://blog.csdn.net/liu4071325/article/details/53392218
必备插件/工具包:
1.项目里引用: RXTXcomm.jar
2.windows服务器需要以下三个文件:
JDK目录jrelibext ---> RXTXcomm.jar
JDK目录bin ---> rxtxParallel.dll 和 rxtxSerial.dll
2.Linux服务器需要放置以下三个文件
JDK目录jrelibext ---> RXTXcomm.jar
JDK目录bin --->librxtxParallel.so 和 librxtxSerial.so
感谢分享!
代码:
1.创建被观察者 SerialReader.java
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Observable;
import java.util.TooManyListenersException;
/**
* <p>串口数据读取类,用于windows的串口数据读取</p>
*
* 声明被观察者SerialReader,继承Observable<br/>
* 观察者,继承Observer<br/>
*
* Observer模式 主要是观察者与被观察者之间的关系。<br/>
*
*/
public class SerialReader extends Observable implements Runnable, SerialPortEventListener {
static CommPortIdentifier portId;
int delayRead = 200;
int numBytes; // buffer中的实际数据字节数
private static byte[] readBuffer = new byte[4096]; // 4k的buffer空间,缓存串口读入的数据
static Enumeration portList;
InputStream inputStream;
SerialPort serialPort;
//声明观察者时,被指定的参数信息
HashMap serialParams;
// 端口读入数据事件触发后,等待n毫秒后再读取,以便让数据一次性读完
public static final String PARAMS_DELAY = "delay read"; // 延时等待端口数据准备的时间
public static final String PARAMS_TIMEOUT = "timeout"; // 超时时间
public static final String PARAMS_PORT = "port name"; // 端口名称
public static final String PARAMS_DATABITS = "data bits"; // 数据位
public static final String PARAMS_STOPBITS = "stop bits"; // 停止位
public static final String PARAMS_PARITY = "parity"; // 奇偶校验
public static final String PARAMS_RATE = "rate"; // 波特率
public SerialReader() {
}
/**
* 初始化端口操作的参数.
*
* @see
*/
public SerialReader(HashMap params) {
serialParams = params;
init();
}
private void init() {
try {
// 参数初始化
int timeout = Integer.parseInt(serialParams.get(PARAMS_TIMEOUT).toString());
int rate = Integer.parseInt(serialParams.get(PARAMS_RATE).toString());
int dataBits = Integer.parseInt(serialParams.get(PARAMS_DATABITS).toString());
int stopBits = Integer.parseInt(serialParams.get(PARAMS_STOPBITS).toString());
int parity = Integer.parseInt(serialParams.get(PARAMS_PARITY).toString());
delayRead = Integer.parseInt(serialParams.get(PARAMS_DELAY).toString());
String port = serialParams.get(PARAMS_PORT).toString();
// 打开端口
portId = CommPortIdentifier.getPortIdentifier(port);
EWeightConstant.IS_OPEN_PORT = true;
serialPort = (SerialPort) portId.open("SerialReader", timeout);
inputStream = serialPort.getInputStream();
serialPort.addEventListener(this);// 注册串口监听
serialPort.notifyOnDataAvailable(true);// 数据可用
serialPort.setSerialPortParams(rate, dataBits, stopBits, parity);// 设置参数
} catch (PortInUseException e) {
// System.out.println("串口已经被占用!");
e.printStackTrace();
} catch (TooManyListenersException e) {
// System.out.println("串口监听者过多!");
e.printStackTrace();
} catch (UnsupportedCommOperationException e) {
// System.out.println("串口操作命令不支持!");
e.printStackTrace();
} catch (NoSuchPortException e) {
// System.out.println("串口不存在!");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Thread readThread = new Thread(this);
readThread.start();
}
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void serialEvent(SerialPortEvent event) {
try {
// 等待1秒钟让串口把数据全部接收后在处理
Thread.sleep(delayRead);
// System.out.print("serialEvent[" + event.getEventType() + "] ");
} catch (InterruptedException e) {
e.printStackTrace();
}
switch (event.getEventType()) {
case SerialPortEvent.BI: // 10
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
try {
// 多次读取,将所有数据读入
while (inputStream.available() > 0) {
numBytes = inputStream.read(readBuffer);
}
// numBytes = inputStream.read(readBuffer);
changeMessage(readBuffer, numBytes);
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
// 通过observer pattern将收到的数据发送给observer
// 将buffer中的空字节删除后再发送更新消息,通知观察者
private String temp1 = "";
public void changeMessage(byte[] message, int length) {
setChanged();
byte[] temp = new byte[length];
System.arraycopy(message, 0, temp, 0, length);
// 判断数据是否稳定,稳定则只监听不执行更新数据
if (!"".equals(temp1)) {
if (!temp1.equals(new String(temp).trim())) {
temp1 = new String(temp).trim();
notifyObservers(temp);
// System.out.println("msg[" + numBytes + "]: [" + new
// String(temp).trim() +"]");
}
} else {
temp1 = new String(temp).trim();
notifyObservers(temp);
}
}
/**
* 调试用,获取所有的串口
*/
static void listPorts() {
Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
while (portEnum.hasMoreElements()) {
CommPortIdentifier portIdentifier = (CommPortIdentifier) portEnum.nextElement();
System.out.println("串口名称:"+portIdentifier.getName() + " - " +"串口类型:"+getPortTypeName(portIdentifier.getPortType()));
}
}
/**
* 读取所有串口名字
*/
public static String getPortName() {
CommPortIdentifier portId;
Enumeration en = CommPortIdentifier.getPortIdentifiers();
while (en.hasMoreElements()) {
portId = (CommPortIdentifier) en.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
return portId.getName();
}
}
return "";
}
/**
* 读取所有串口名字
*/
public static void closePort() {
CommPortIdentifier portId;
Enumeration en = CommPortIdentifier.getPortIdentifiers();
while (en.hasMoreElements()) {
portId = (CommPortIdentifier) en.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
}
}
}
static String getPortTypeName(int portType) {
switch (portType) {
case CommPortIdentifier.PORT_I2C:
return "I2C";
case CommPortIdentifier.PORT_PARALLEL:
return "Parallel";
case CommPortIdentifier.PORT_RAW:
return "Raw";
case CommPortIdentifier.PORT_RS485:
return "RS485";
case CommPortIdentifier.PORT_SERIAL:
return "Serial";
default:
return "unknown type";
}
}
public static HashSet<CommPortIdentifier> getAvailableSerialPorts() {
HashSet<CommPortIdentifier> h = new HashSet<CommPortIdentifier>();
Enumeration thePorts = CommPortIdentifier.getPortIdentifiers();
while (thePorts.hasMoreElements()) {
CommPortIdentifier com = (CommPortIdentifier) thePorts.nextElement();
switch (com.getPortType()) {
case CommPortIdentifier.PORT_SERIAL:
try {
CommPort thePort = com.open("CommUtil", 50);
thePort.close();
h.add(com);
} catch (PortInUseException e) {
// System.out.println("Port, " + com.getName()+ ", is in
// use.");
} catch (Exception e) {
// System.out.println("Failed to open port " +
// com.getName()+ e);
}
}
}
return h;
}
}
2.创建观察者CommDataObserver.java
import java.util.Observable;
import java.util.Observer;
/**
* 观察类,继承Observer<br/>
* 创建一个观察类,该观察类有自己的name名称
*
*/
public class CommDataObserver implements Observer {
private String name;
public CommDataObserver() {
}
public CommDataObserver(String name) {
this.name = name;
}
/**
* 监控串口,获取串口数据
*/
public void update(Observable o, Object arg) {
//获取串口返回数据
String weight = new String((byte[]) arg).trim();
//将获取到的数据,赋值到全局变量里,以便可以调用该数据
EWeightConstant.GOOD_WEIGHT = weight;
//testing start 根据串口类型不同,返回的数据格式也不尽相同,此处调试打印而已 {{
System.out.println("weight="+weight);
StringBuilder sb = new StringBuilder(weight);// 0.000或者00.000
sb.insert(weight.length() - 3, ".");
System.out.println(sb.toString() + "kg");
//testing end }}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3.初始化端口数据,并创建被观察者和观察者,并加入观察GetWeightUtil.java
import java.util.HashMap;
import gnu.io.SerialPort;
/**
* 获取串口工具类
* 此处声明观察者和被观察者
*/
public class GetWeightUtil {
/**
* 串口设置, 初始化端口数据
* @param com 端口
*/
public static void comConfig(String com) {
//存储端口数据
HashMap<String, Comparable> params = new HashMap<String, Comparable>();
// 端口名称
params.put(SerialReader.PARAMS_PORT, com);
// 波特率
params.put(SerialReader.PARAMS_RATE, 9600);
// 设备超时时间 1秒
params.put(SerialReader.PARAMS_TIMEOUT, 1000);
// 端口数据准备时间 1秒
params.put(SerialReader.PARAMS_DELAY, 200);
// 数据位
params.put(SerialReader.PARAMS_DATABITS, SerialPort.DATABITS_8);
// 停止位
params.put(SerialReader.PARAMS_STOPBITS, SerialPort.STOPBITS_1);
// 无奇偶校验
params.put(SerialReader.PARAMS_PARITY, SerialPort.PARITY_NONE);
//创建被观察者
SerialReader serialReader = new SerialReader(params);
//创建观察者
CommDataObserver obServer = new CommDataObserver("电子秤");
//添加一个观察者,加入观察
serialReader.addObserver(obServer);
//TODO 调试用,输出到控制台 显示所有串口号
SerialReader.listPorts();
}
public static void main(String[] args) throws Exception{
comConfig("COM1");
while(true){
Thread.sleep(1000);
System.out.println(EWeightConstant.GOOD_WEIGHT);
}
}
}
4.EWeightConstant.java
/**
* 记录串口的基础信息 全局变量
*
*/
public class EWeightConstant {
/**
* 串口数据
*/
public static String GOOD_WEIGHT = "0";
/**
* 串口是否打开
*/
public static Boolean IS_OPEN_PORT = false;
}
5.Controller方法调用获取串口数据,并作用于业务开发
/**
* 前端 调用该方法,用于获取串口返回数据
* 如果想一直调用该串口返回数据,JS前端可做轮询
* @param request
* @return
*/
@RequestMapping(value = "/getWeight", method = RequestMethod.GET)
@ResponseBody
public String getWeight(HttpServletRequest request) {
// 获取数据的串口
final String E_WEIGHT_COM = "COM1";
try{
if(!EWeightConstant.IS_OPEN_PORT){
GetWeightUtil.comConfig(E_WEIGHT_COM);
}
}catch(Exception e){
e.printStackTrace();
}
//全局变量,记录串口数据
String weight = EWeightConstant.GOOD_WEIGHT;
//输出串口数据,查看串口数据格式
System.out.println("获取串口原始数据格式 = " + weight);
if(StringUtils.equals(weight, "0")){
return weight;
}
//截取字符串,获取要取得数据部分
weight = weight.substring(weight.indexOf("+")+1, weight.indexOf(" "));
System.out.println("最终数据,返回截取后的数据="+weight);
return weight;
}
最后
以上就是开放诺言为你收集整理的JavaWeb 用于windows的串口数据读取的全部内容,希望文章能够帮你解决JavaWeb 用于windows的串口数据读取所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复