最近项目中需要调用串口激光扫码枪,这也是我首次在java项目中实现调用硬件的功能,所以特别感兴趣,经过研究后,在这把实现串口激光扫码枪的实现过程和大家说一下:
好了,下面我们要开始介绍详细的开发过程。
第一、首先我们要安装硬件驱动,这个产品官网上都有,而且产品都有详细的用户手册,自己可以百度下载,这里就不再细讲。官网地址:http://www.mindeo.cn/view_product.php?id=87&cid=71###
第二、安装串口中文输出工具。推荐使用COM_Text V2.0。
COM_Text软件可以仿真串行键输入的效果,将由串口(COM)或USB虚拟串口(USB Virtual COM)获得的数据信息(ASCII码)转换成字符(Unicode、简体中文、日文等)格式,在.txt文本文件或.doc微软Word文件上输出。 所连接的设备(如条码阅读器)使用的必须是RS232串口电缆线或USB电缆线(USB类型必须设置为“USB虚拟串口”)。无论PC机处于何种输入法,都可正确输出中英文等字符。
第三、工具我们都准备好了,我们现在需要的是连接扫码枪,这里我要说明一下,因为我用的是笔记本电脑,大部分笔记本电脑已经不支持串口,所以我用了一根串口转USB线,大家可以根据自己的实际情况进行选择,当然也可以直接使用台式机,那就不需要考虑这件事了。
第四步、扫码枪连到电脑之后,打开COM_Text软件,如果驱动安装正确,此工具会读出几个重要参数。端口名称、波特率、数据位、停止位、无奇偶校验等属性,这些属性后边我们用的到,这是属性也是我们连接扫码枪的必用参数。
第五步、RXTX是个提供串口和并口通信的开源java类库,由该项目发布的文档均遵循LGPL协议。针对x86体系结构的Linux操作系统平台,RXTX的部署包括下面几个文档:* RXTXcomm.jar RXTX自己的实*librxtxSerial.so 由调用的底层串口库文档* librxtxParallel.so 由RXTXcomm.jar调用的底层并口库文档驱动的类配置文档,内容是Driver=gnu.io.RXTXCommDriver。我用的是mfz-rxtx-2.2-20081207-win-x64这个版本。当你选择的时候,必须下载使用适配你电脑的版本,我的电脑是win10 64位专业版,所以必须得使用x64的项目,里面包含两个重要的dll文件,即rxtxParallel.dll、rxtxSerial.dll,我们需要把这两个文件放到C:\Windows\System32下。
第六步、我们靠开始开发了,入口函数代码如下,
package cn.com.checknull.rxtx.main;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import cn.com.checknull.rxtx.bean.SerialPortParms;
import cn.com.checknull.rxtx.listener.SerialReader;
public class SerialPortMain implements Observer {
private List<String> mListComName;
private SerialReader sr = new SerialReader();
public static void main(String[] args) {
new SerialPortMain();
}
public SerialPortMain() {
searchSerialPort();
connectSerialPort();
sendOrder();
}
private void searchSerialPort() {
mListComName = new ArrayList<String>();
CommPortIdentifier portId;
Enumeration enumeration = CommPortIdentifier.getPortIdentifiers();
while (enumeration.hasMoreElements()) {
portId = (CommPortIdentifier) enumeration.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
mListComName.add(portId.getName());
}
}
}
private void connectSerialPort() {
String comName;
if (mListComName.size() > 0) {
comName = mListComName.get(0);
String PortName = comName;
String rate_value = SerialPortParms.RATE[0];
String databit_value = SerialPortParms.DATABIT[0];
String stopbit_value = SerialPortParms.STOPBIT[0];
HashMap<String, Comparable> params = new HashMap<String, Comparable>();
int parityInt = SerialPort.PARITY_NONE;
params.put(SerialReader.PARAMS_PORT, PortName);
params.put(SerialReader.PARAMS_RATE, rate_value);
params.put(SerialReader.PARAMS_DATABITS, databit_value);
params.put(SerialReader.PARAMS_STOPBITS, stopbit_value);
params.put(SerialReader.PARAMS_PARITY, parityInt);
params.put(SerialReader.PARAMS_TIMEOUT, 100);
params.put(SerialReader.PARAMS_DELAY, 100);
try {
sr.open(params);
sr.addObserver(SerialPortMain.this);
System.out.println(PortName + ":已经打开");
} catch (Exception e1) {
System.out.println("端口被占用");
}
}
}
private void sendOrder() {
byte []all = new byte[]{0x00,0x01,0x02};
if ( all!= null) {
sr.start();
sr.run(all);
}
}
@Override
public void update(Observable o, Object arg) {
byte []date = (byte[])arg;
System.out.println(Arrays.toString(date));
}
}
package cn.com.checknull.rxtx.listener;
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.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Observable;
import java.util.TooManyListenersException;
public class SerialReader extends Observable implements Runnable,
SerialPortEventListener {
static CommPortIdentifier portId;
int delayRead = 100;
int numBytes;
private static byte[] readBuffer = new byte[1024];
static Enumeration portList;
InputStream inputStream;
OutputStream outputStream;
static SerialPort serialPort;
HashMap serialParams;
Thread readThread;
boolean isOpen = false;
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";
private HashMap<Byte, byte[]> map;
public boolean isOpen() {
return isOpen;
}
/**
* 初始化端口操作的参数.
*
* @throws SerialPortException
*
* @see
*/
public SerialReader() {
isOpen = false;
}
public void open(HashMap params) throws NoSuchPortException,
PortInUseException, IOException, UnsupportedCommOperationException,
TooManyListenersException {
serialParams = params;
if (isOpen) {
close();
}
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);
serialPort = (SerialPort) portId.open("SerialReader", timeout);
inputStream = serialPort.getInputStream();
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
serialPort.setSerialPortParams(rate, dataBits, stopBits, parity);
isOpen = true;
serialParams.clear();
}
public void run() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start() {
try {
outputStream = serialPort.getOutputStream();
} catch (IOException e) {
}
try {
readThread = new Thread(this);
readThread.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public void run(byte[] message) {
try {
Thread.sleep(4);
} catch (InterruptedException e) {
}
try {
if (message != null) {
System.out.println("run message:" + message);
outputStream.write(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void close() {
if (isOpen) {
try {
serialPort.notifyOnDataAvailable(false);
serialPort.removeEventListener();
inputStream.close();
serialPort.close();
isOpen = false;
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
@Override
public void serialEvent(SerialPortEvent event) {
String strs[] = null;
try {
Thread.sleep(delayRead);
} catch (InterruptedException e) {
e.printStackTrace();
}
switch (event.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 {
while (inputStream.available() > 0) {
readBuffer = new byte[inputStream.available()];
numBytes = inputStream.read(readBuffer);
}
strs = changeMessage(readBuffer, numBytes);
System.out.print("条形码为:");
for (int i = 0 ;i < strs.length; i++) {
System.out.print(strs[i]);
}
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
public String[] changeMessage(byte[] message, int length) {
boolean flag = false;
byte type = message[3];
setChanged();
notifyObservers(message);
List<String> list = new ArrayList<String>();
for (int i = 0; i < message.length; i++) {
String result = toAsciiImage(message[i]);
list.add(result);
}
String strs[] = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
strs[i] = list.get(i);
}
return strs;
}
public String toAsciiImage(byte b){
String result = "";
switch (b) {
case 48:
result = "0";
break;
case 49:
result = "1";
break;
case 50:
result = "2";
break;
case 51:
result = "3";
break;
case 52:
result = "4";
break;
case 53:
result = "5";
break;
case 54:
result = "6";
break;
case 55:
result = "7";
break;
case 56:
result = "8";
break;
case 57:
result = "9";
break;
default:
break;
}
return result;
}
static void listPorts() {
Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
while (portEnum.hasMoreElements()) {
CommPortIdentifier portIdentifier = (CommPortIdentifier) portEnum
.nextElement();
}
}
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 HashSet<CommPortIdentifier> getAvailableSerialPorts()// 本来static
{
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;
}
}
package cn.com.checknull.rxtx.bean;
public class SerialPortParms {
public static final String[] RATE = { "9600", "9600", "4800", "2400" };
public static final String[] DATABIT = { "8", "7", "6", "5" };
public static final String[] STOPBIT = { "1", "1.5", "2" };
}
第七步、运行主程序之后,串口扫码枪就可以开始工作了。这里我要特别说一下,我扫描的一般都是条形码,大部分条形码都是采用的ASCII图形格式,因为扫描枪扫描出来的一般是十进制数字,所以在程序中转换了一下,转成ASCII值。
结尾:我只给大家普及一个小知识,大部分药品盒上的条形码采用的ASCII图形格式,所以,童鞋们,为了知道其数字代表的十进制是多少,赶紧去背ASCII数值对照表吧。