您的位置:首页 > 编程语言 > Java开发

java语言基于万准衡器(吊钩秤)的串口通信案例

2018-03-12 08:20 330 查看
最近到钢铁公司出差,项目其中有个需求是需要对钢铁称重,利用吊钩秤基于串口通信,其中万准衡器向串口发送的数据格式是五个字节,分别是一个字节的起始位(0xFF),一个字节的状态位,三个字节的数据位。在取数过程中也是琢磨很久,需要经历一个计算过程。以下是自己在这个项目中整理的案例:

package com.kingdee.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TooManyListenersException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;

public class Test extends Thread implements SerialPortEventListener {
InputStream inputStream; // 从串口来的输入流
static OutputStream outputStream;// 向串口输出的流
static SerialPort serialPort; // 串口的引用
static Enumeration<?> portList; // 有效连接上的端口的枚举
static CommPortIdentifier port; // 串口通信管理类
private List<String> list = new ArrayList<String>();

@Override
public void serialEvent(SerialPortEvent arg0) {
switch (arg0.getEventType()) {
case SerialPortEvent.BI:
case SerialPortEvent.OE:
case SerialPortEvent.FE:
case SerialPortEvent.PE:
case SerialPortEvent.CD:
case SerialPortEvent.CTS:
case SerialPortEvent.DSR:
case SerialPortEvent.RI:
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
break;
case SerialPortEvent.DATA_AVAILABLE:// 当有可用数据时读取数据
try {
inputStream = serialPort.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
byte[] bytes = new byte[inputStream.available()];
int numBytes = 0;
while (inputStream.available() > 0) {
String str = "";
numBytes = inputStream.read(bytes);
// 记录吊钩秤的状态,稳定还是不稳定
String status = "";
// 记录小数位
int decimalPlace = 0;
// 记录重量参数
String strValue;
byte byteValue;
double doubleValue;
// 第二位为状态字 十进制18代表静态并且有一位小数 十进制2代表动态并且有一位小数
// 若传输一次的数据长度不为5,抛出异常
if (bytes.length != 5) {
throw new Exception("数据格式不正确!");
} else {
// 若起始位不为16进制的0xFF即java中byte类型的-1,抛出异常
if (bytes[0] != (byte) 0xFF) {
throw new Exception("起始位异常!!!");
} else {
System.out.println("获取数据正常");
// 判断状态位的二进制数
// D7--0--量程以内 1--超载
// D6--0
// D5--0--正数 1--负数
// D4--0--动态 1--静态
// D3--0
// D2 D1 D0--001无小数 010--一位小数 011--两位 100--三位
// 101--四位
if ((bytes[1] & 128) == 128) {
throw new Exception("超载!!!");
} else if ((bytes[1] & 32) == 32) {
status = "稳定";
}
// 根据状态位取小数位
if ((bytes[1] & 0x1) == 0x1) {
decimalPlace = 0;
} else if ((bytes[1] & 0x2) == 0x2) {
decimalPlace = 10;
} else if ((bytes[1] & 0x3) == 0x3) {
decimalPlace = 100;
} else if ((bytes[1] & 0x4) == 0x4) {
decimalPlace = 1000;
} else if ((bytes[1] & 0x5) == 0x5) {
decimalPlace = 10000;
}
// 计算重量 由高位到中位到低位
// 高位
strValue = "";
byteValue = rightMoveByte(bytes[4], 4);
strValue = strValue + byteValue;
byteValue = (byte) (bytes[4] & 15);
strValue = strValue + byteValue;
// 中位
byteValue = rightMoveByte(bytes[3], 4);
strValue = strValue + byteValue;
byteValue = (byte) (bytes[3] & 15);
strValue = strValue + byteValue;
// 低位
byteValue = rightMoveByte(bytes[2], 4);
strValue = strValue + byteValue;
byteValue = (byte) (bytes[2] & 15);
strValue = strValue + byteValue;
doubleValue = Double.parseDouble(strValue);
if (decimalPlace > 0) {
doubleValue = doubleValue / decimalPlace;
}
}
}
System.out.println("重量值为:" + doubleValue + "kg");
// 取到的数据存在str字符串
// list.add(new Date() + "真实收到的数据为: " + str);

// 重新构造缓冲对象,否则有可能会影响接下来接收的数据
bytes = new byte[inputStream.available()];
// System.out.println(" 字节数为: " + numBytes);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

// 向右移位方法,用来计算重量
private static byte rightMoveByte(byte b, int n) {
byte target = b;
for (int i = 1; i <= n; i++) {
target = (byte) (target / 2);
}
return target;
}

public int startComPort() throws Exception {
// 通过串口通信管理类获得当前连接上的串口列表
portList = CommPortIdentifier.getPortIdentifiers();

while (portList.hasMoreElements()) {

// 获取相应串口对象
port = (CommPortIdentifier) portList.nextElement();

System.out.println("设备类型:--->" + port.getPortType());
System.out.println("设备名称:---->" + port.getName());
// 判断端口类型是否为串口
if (port.getPortType() == CommPortIdentifier.PORT_SERIAL) {
// 判断哪几个串口存在,就打开该串口
switch (port.getName()) {
case "COM1":
serialPort = (SerialPort) port.open("COM1", 1000);
break;
case "COM2":
serialPort = (SerialPort) port.open("COM2", 1000);
break;
case "COM3":
serialPort = (SerialPort) port.open("COM3", 1000);
break;

}
// 设置当前串口的输入输出流
try {
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
return 0;
}
// 给当前串口添加一个监听器
try {
serialPort.addEventListener(this);
} catch (TooManyListenersException e) {
e.printStackTrace();
return 0;
}
// 设置监听器生效,即:当有数据时通知
// 设置当端口有可用数据时触发事件,此设置必不可少。
serialPort.notifyOnDataAvailable(true);

// 设置串口的一些读写参数
try {
// 比特率、数据位、停止位、奇偶校验位
serialPort.setSerialPortParams(4800, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);

} catch (UnsupportedCommOperationException e) {
e.printStackTrace();
return 0;
}

return 1;

} else {
throw new Exception("端口类型不是串口!");
}
}
return 0;
}

public static void main(String[] args) throws Exception {
final Test t = new Test();
t.startComPort();
// java定时器
                //这里需要经过很短的时间关闭串口,只需要取一组数据,利用java定时器操作
                Timer timer = new Timer();
TimerTask task = new TimerTask() {

@Override
public void run() {
t.serialPort.close();
}

};
timer.schedule(task, 200);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: