很老套的代码,但是却费时很久,找到过很多参考代码,但是要不然和本身项目不太符合,要不然就运行不出来,报串口找不到的错误,也还因为jar包整了很久,去各种百度解决办法才真正实现使用java实现串口通信。
1. jar包的导入
1.1 如果你的电脑安装的是32位的JDK,那么有两种解决方案
A.
- 将文件comm.jar拷贝到%JAVA_HOME%\jre\lib\ext;
- 文件javax.comm. properties拷贝到%JAVA_HOME%\jre\lib;
- 文件win32comm.dll拷贝到%JAVA_HOME%\bin。
- 注意%JAVA_HOME%是jdk的路径,而非jre。
B. 使用Rxtx jar包(32位)
下载地址:点击打开链接
1.2 如果你的电脑安装的是64位的JDK,那么只能使用Rxtx jar包(64位)
下载地址:点击打开链接
由于我写的项目是一个动态WEB项目,所以目前只实现了接收串口数据,在WEB页面操作后,再向硬件发送数据还未实现,后续还会更新。
接收数据的实现思路如下:现在java程序中启动读串口数据的类,读出之后按解析保存至数据库中,WEB的显示后台则从数据库中取数据。
首先是写好的串口工具类:
- /**
- * 串口服务类,提供打开、关闭串口,读取、发送串口数据等服务(采用单例设计模式)
- * @author zhong
- *
- */
- 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 可用端口名称列表
- */
- @SuppressWarnings("unchecked")
- public static final ArrayList<String> findPort() {
- //获得当前所有可用串口
- Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
- ArrayList<String> 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 NotASerialPort 端口指向设备不是串口类型
- * @throws NoSuchPort 没有该端口对应的串口设备
- * @throws PortInUse 端口已被占用
- */
- public static final SerialPort openPort(String portName, int baudrate) throws SerialPortParameterFailure, NotASerialPort, NoSuchPort, PortInUse {
- try {
- //通过端口名识别端口
- 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) {
- throw new SerialPortParameterFailure();
- }
- System.out.println("Open " + portName + " sucessfully !");
- return serialPort;
- }
- else {
- //不是串口
- throw new NotASerialPort();
- }
- } catch (NoSuchPortException e1) {
- throw new NoSuchPort();
- } catch (PortInUseException e2) {
- throw new PortInUse();
- }
- }
- /**
- * 关闭串口
- * @param serialport 待关闭的串口对象
- */
- public static void closePort(SerialPort serialPort) {
- if (serialPort != null) {
- serialPort.close();
- System.out.println("Close " + serialPort + " sucessfully !");
- serialPort = null;
- }
- }
- /**
- * 往串口发送数据
- * @param serialPort 串口对象
- * @param order 待发送数据
- * @throws SendDataToSerialPortFailure 向串口发送数据失败
- * @throws SerialPortOutputStreamCloseFailure 关闭串口对象的输出流出错
- */
- public static void sendToPort(SerialPort serialPort, byte[] order) throws SendDataToSerialPortFailure, SerialPortOutputStreamCloseFailure {
- OutputStream out = null;
- try {
- out = serialPort.getOutputStream();
- out.write(order);
- out.flush();
- } catch (IOException e) {
- throw new SendDataToSerialPortFailure();
- } finally {
- try {
- if (out != null) {
- out.close();
- out = null;
- }
- } catch (IOException e) {
- throw new SerialPortOutputStreamCloseFailure();
- }
- }
- }
- /**
- * 从串口读取数据
- * @param serialPort 当前已建立连接的SerialPort对象
- * @return 读取到的数据
- * @throws ReadDataFromSerialPortFailure 从串口读取数据时出错
- * @throws SerialPortInputStreamCloseFailure 关闭串口对象输入流出错
- */
- public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailure, SerialPortInputStreamCloseFailure {
- InputStream in = null;
- byte[] bytes = null;
- try {
- 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) {
- throw new ReadDataFromSerialPortFailure();
- } finally {
- try {
- if (in != null) {
- in.close();
- in = null;
- }
- } catch(IOException e) {
- throw new SerialPortInputStreamCloseFailure();
- }
- }
- return bytes;
- }
- /**
- * 添加监听器
- * @param port 串口对象
- * @param listener 串口监听器
- * @throws TooManyListeners 监听类对象过多
- */
- public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListeners {
- try {
- //给串口添加监听器
- port.addEventListener(listener);
- //设置当有数据到达时唤醒监听接收线程
- port.notifyOnDataAvailable(true);
- //设置当通信中断时唤醒中断线程
- port.notifyOnBreakInterrupt(true);
- } catch (TooManyListenersException e) {
- throw new TooManyListeners();
- }
- }
- }
写好之后,就是读串口类,要保存至数据库的话就是在读出数据后保存,此处无保存至数据库的代码:
- public class EventListener implements SerialPortEventListener {
- //1.定义变量
- SerialPort serialPort = null;
- InputStream inputStream = null;//输入流
- Thread readThread = null;
- //2.构造函数:
- //实现初始化动作:获取串口COM21、打开串口、获取串口输入流对象、为串口添加事件监听对象
- public EventListener() throws NoSuchPortException, PortInUseException{
- try {
- //获取串口、打开窗串口、获取串口的输入流。
- serialPort = SerialTool.openPort("COM3", 115200);
- inputStream = serialPort.getInputStream();
- //向串口添加事件监听对象。
- serialPort.addEventListener(this);
- //设置当端口有可用数据时触发事件,此设置必不可少。
- serialPort.notifyOnDataAvailable(true);
- } catch (IOException e) {
- e.printStackTrace();
- } catch (TooManyListenersException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (SerialPortParameterFailure e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (NotASerialPort e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (NoSuchPort e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (PortInUse e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }finally {
- // SerialTool.closePort(serialPort);
- }
- }
- //重写继承的监听器方法
- @Override
- public void serialEvent(SerialPortEvent event) {
- //定义用于缓存读入数据的数组
- byte[] cache = new byte[1024];
- //记录已经到达串口COM21且未被读取的数据的字节(Byte)数。
- int availableBytes = 0;
- //如果是数据可用的时间发送,则进行数据的读写
- if(event.getEventType() == SerialPortEvent.DATA_AVAILABLE){
- try {
- availableBytes = inputStream.available();
- while(availableBytes > 0){
- inputStream.read(cache);
- for(int i = 0; i < cache.length && i < availableBytes; i++){
- //解码并输出数据
- System.out.print((char)cache[i]);
- }
- availableBytes = inputStream.available();
- }
- System.out.println();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) throws NoSuchPortException, PortInUseException {
- new EventListener();
- }
- }
再就是向串口发送数据:
- public class Write {
- public static void main(String[] args) {
- SerialPort serialPort = null; //打开的端
- try {
- //打开串口
- serialPort = SerialTool.openPort("COM21", 9600);
- //数组“Hello World!”
- byte[] bs = new byte[]{'H','e','l','l','o',' ','W','o','r','l','d','!'};
- //写入数组
- SerialTool.sendToPort(serialPort, bs);
- } catch (SerialPortParameterFailure | NotASerialPort | NoSuchPort | PortInUse | SendDataToSerialPortFailure | SerialPortOutputStreamCloseFailure e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }finally {
- //关闭串口
- SerialTool.closePort(serialPort);
- }
- }
- }