ToB企服应用市场:ToB评测及商务社交产业平台

标题: 三大硬核方式揭秘:Java如何与底层硬件和工业设备轻松通信! [打印本页]

作者: 千千梦丶琪    时间: 2024-9-26 10:16
标题: 三大硬核方式揭秘:Java如何与底层硬件和工业设备轻松通信!
大家好,我是V哥,程序员聊灵活是三句不到离不开技能啊,这不前两天跟一个哥们用饭,他是我很多多少年前的学员了,不停保持着接洽,现在都李总了,在做工业互联网相关的项目,真是只要 Java 学得好,能干一辈子,卷死的是那些半吊子。
感谢李总给我分享了工业互联网项目的事情,收获很多,本日的内容来聊一聊 Java如何与底层硬件和工业设备轻松通信的事情。
Java读取寄存器数据通常涉及与硬件设备的通信。这种利用通常是通过以下几种方式来实现的:
使用 Modbus 协议读取设备寄存器数据(使用 jLibModbus)

Modbus 是一种用于工业自动化设备的通信协议。常见的Modbus通信方式包罗:Modbus RTU(基于串行通信)和Modbus TCP(基于网络通信)。在此示例中,我们将使用 Java 和 jLibModbus 库通过 Modbus TCP 协议读取设备的寄存器数据。
实现步调

1. 添加 jLibModbus 依赖

使用 Maven 管理项目时,可以在 pom.xml 中添加 jLibModbus 依赖:
  1. <dependency>
  2.     <groupId>com.intelligt.modbus</groupId>
  3.     <artifactId>jlibmodbus</artifactId>
  4.     <version>1.2.8.1</version>
  5. </dependency>
复制代码
或者直接下载 jar 包并将其添加到项目的 classpath 中。
2. 示例代码:通过 Modbus TCP 读取寄存器
  1. import com.intelligt.modbus.jlibmodbus.Modbus;
  2. import com.intelligt.modbus.jlibmodbus.ModbusMaster;
  3. import com.intelligt.modbus.jlibmodbus.ModbusMasterFactory;
  4. import com.intelligt.modbus.jlibmodbus.exception.ModbusIOException;
  5. import com.intelligt.modbus.jlibmodbus.exception.ModbusNumberException;
  6. import com.intelligt.modbus.jlibmodbus.exception.ModbusProtocolException;
  7. import com.intelligt.modbus.jlibmodbus.modbus.ModbusFunctionCode;
  8. import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
  9. import java.net.InetAddress;
  10. public class ModbusTcpClient {
  11.     public static void main(String[] args) {
  12.         try {
  13.             // 配置 Modbus TCP 参数
  14.             TcpParameters tcpParameters = new TcpParameters();
  15.             InetAddress address = InetAddress.getByName("192.168.1.100"); // 设备的IP地址
  16.             tcpParameters.setHost(address);
  17.             tcpParameters.setPort(Modbus.TCP_PORT); // Modbus 默认TCP端口 502
  18.             // 创建 ModbusMaster 实例
  19.             ModbusMaster master = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);
  20.             master.connect();
  21.             // 设备的 Slave ID(通常是从站地址)
  22.             int slaveId = 1;
  23.             // 读取保持寄存器(Holding Registers),从地址 0 开始,读取 10 个寄存器
  24.             int startAddress = 0;
  25.             int quantity = 10;
  26.             try {
  27.                 // 读取保持寄存器数据
  28.                 int[] registerValues = master.readHoldingRegisters(slaveId, startAddress, quantity);
  29.                 System.out.println("寄存器数据:");
  30.                 for (int i = 0; i < registerValues.length; i++) {
  31.                     System.out.println("寄存器[" + (startAddress + i) + "] = " + registerValues[i]);
  32.                 }
  33.             } catch (ModbusProtocolException | ModbusNumberException | ModbusIOException e) {
  34.                 System.err.println("Modbus 读取失败: " + e.getMessage());
  35.             }
  36.             // 断开连接
  37.             master.disconnect();
  38.         } catch (Exception e) {
  39.             e.printStackTrace();
  40.         }
  41.     }
  42. }
复制代码
来解释一下代码哈

3. 如何使用

  1.    寄存器数据:
  2.    寄存器[0] = 1234
  3.    寄存器[1] = 5678
  4.    寄存器[2] = 910
  5.    ...
复制代码
使用时要注意的事项

小结一下

我们通过 jLibModbus 库使用 Java 读取支持 Modbus TCP 协议的设备的寄存器数据。Modbus是工业控制范畴中广泛应用的通信协议,利用Java实现设备通信可以用于各种自动化系统中。假如你的设备使用Modbus RTU协议,可以通过设置串口通信来实现雷同的利用。
JNI(Java Native Interface)

Java Native Interface (JNI) 允许Java代码与C/C++等当地语言编写的代码交互,可以用于实现高性能、直接的硬件访问,如寄存器读取。
JNI基本流程

来看案例:使用JNI读取寄存器数据

1. Java代码

首先,界说一个Java类,该类声明一个当地方法用于读取寄存器数据。
  1. public class RegisterReader {
  2.     // 声明本地方法,该方法将在C/C++代码中实现
  3.     public native int readRegister(int address);
  4.     static {
  5.         // 加载本地库,假设库名为 "register_reader"
  6.         System.loadLibrary("register_reader");
  7.     }
  8.     public static void main(String[] args) {
  9.         RegisterReader reader = new RegisterReader();
  10.         int registerAddress = 0x1000; // 假设寄存器地址
  11.         int value = reader.readRegister(registerAddress);
  12.         System.out.println("Register Value: " + value);
  13.     }
  14. }
复制代码
编译Java文件:
  1. javac RegisterReader.java
复制代码
生成C/C++头文件:
  1. javah -jni RegisterReader
复制代码
此命令将生成一个RegisterReader.h文件,包含C/C++中需要实现的方法声明。
2. 生成的头文件(RegisterReader.h)
  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class RegisterReader */
  4. #ifndef _Included_RegisterReader
  5. #define _Included_RegisterReader
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*
  10. * Class:     RegisterReader
  11. * Method:    readRegister
  12. * Signature: (I)I
  13. */
  14. JNIEXPORT jint JNICALL Java_RegisterReader_readRegister
  15.   (JNIEnv *, jobject, jint);
  16. #ifdef __cplusplus
  17. }
  18. #endif
  19. #endif
复制代码
3. C代码实现

接下来,在C语言中实现readRegister方法。在这里,我们假设寄存器通过内存映射的方式访问。
  1. #include "RegisterReader.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. // 模拟寄存器的内存映射地址
  5. #define REGISTER_BASE_ADDRESS 0x1000
  6. JNIEXPORT jint JNICALL Java_RegisterReader_readRegister(JNIEnv *env, jobject obj, jint address) {
  7.     // 模拟读取寄存器,实际实现应访问真实硬件哈
  8.     int registerValue = (address - REGISTER_BASE_ADDRESS) * 2;  // 伪代码,用来模拟一下
  9.     printf("Reading register at address: 0x%x\n", address);
  10.     return registerValue;
  11. }
复制代码
4. 编译生成动态库

在Linux或macOS上,编译C代码并生成动态库:
  1. gcc -shared -o libregister_reader.so -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux RegisterReader.c
复制代码
在Windows上:
  1. gcc -shared -o register_reader.dll -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" RegisterReader.c
复制代码
5. 运行Java程序

确保编译生成的动态库位于Java的库路径中,然后运行Java程序:
  1. java -Djava.library.path=. RegisterReader
复制代码
结果

Java程序将调用当地C代码来读取寄存器的值,输出雷同如下的结果:
  1. Reading register at address: 0x1000
  2. Register Value: 0
复制代码
解释一下

优点

要注意的事

JSerialComm或RXTX等库

使用 JSerialComm 通过串口通信读取设备寄存器数据。
在一些嵌入式或工业设备中,使用串口(如RS232或RS485)进行数据通信是非经常见的。Java提供了多个库来实现串口通信,此中JSerialComm和RXTX是两个常用的库。JSerialComm相对较新且维护良好,兼容性更好,因此我们以它为例介绍如何使用它进行串口通信。
实现步调

1. 添加 JSerialComm 依赖

使用Maven管理项目时,可以在pom.xml中添加JSerialComm的依赖:
  1. <dependency>
  2.     <groupId>com.fazecast</groupId>
  3.     <artifactId>jSerialComm</artifactId>
  4.     <version>2.9.2</version>
  5. </dependency>
复制代码
或者,下载 jar 包并将其添加到项目的 classpath 中。
2. 示例代码:使用 JSerialComm 读取寄存器数据
  1. import com.fazecast.jSerialComm.SerialPort;
  2. public class SerialCommExample {
  3.     public static void main(String[] args) {
  4.         // 获取系统上的所有串口设备
  5.         SerialPort[] ports = SerialPort.getCommPorts();
  6.         System.out.println("可用串口设备列表:");
  7.         for (int i = 0; i < ports.length; i++) {
  8.             System.out.println(i + ": " + ports[i].getSystemPortName());
  9.         }
  10.         // 选择第一个串口设备并打开
  11.         SerialPort serialPort = ports[0];
  12.         serialPort.setBaudRate(9600); // 设置波特率
  13.         serialPort.setNumDataBits(8); // 数据位
  14.         serialPort.setNumStopBits(SerialPort.ONE_STOP_BIT); // 停止位
  15.         serialPort.setParity(SerialPort.NO_PARITY); // 校验位
  16.         if (serialPort.openPort()) {
  17.             System.out.println("串口打开成功: " + serialPort.getSystemPortName());
  18.         } else {
  19.             System.out.println("无法打开串口");
  20.             return;
  21.         }
  22.         // 等待串口设备准备好
  23.         try {
  24.             Thread.sleep(2000); // 等待2秒
  25.         } catch (InterruptedException e) {
  26.             e.printStackTrace();
  27.         }
  28.         // 发送命令给设备读取寄存器
  29.         String command = "READ_REGISTER";  // 根据设备协议构建读取命令
  30.         byte[] commandBytes = command.getBytes();
  31.         serialPort.writeBytes(commandBytes, commandBytes.length);
  32.         // 接收设备响应
  33.         byte[] readBuffer = new byte[1024];
  34.         int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
  35.         System.out.println("读取到的数据长度: " + numRead);
  36.         System.out.println("数据内容:");
  37.         for (int i = 0; i < numRead; i++) {
  38.             System.out.print((char) readBuffer[i]);
  39.         }
  40.         // 关闭串口
  41.         serialPort.closePort();
  42.         System.out.println("\n串口关闭");
  43.     }
  44. }
复制代码
解释一下代码

运行时结果示例
  1. 可用串口设备列表:
  2. 0: COM3
  3. 串口打开成功: COM3
  4. 读取到的数据长度: 6
  5. 数据内容:
  6. 123456
  7. 串口关闭
复制代码
要注意的事项有哪些

RXTX 示例

RXTX是另一种用于串口通信的库,但由于维护不如JSerialComm积极,V哥建议使用JSerialComm。假如你还是要使用RXTX咋办?那 V 哥只能...上案例了,一个简单的串口通信示例:
  1. import gnu.io.CommPortIdentifier;
  2. import gnu.io.SerialPort;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. public class RXTXExample {
  6.     public static void main(String[] args) throws Exception {
  7.         // 获取串口
  8.         CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier("COM3");
  9.         SerialPort serialPort = (SerialPort) portIdentifier.open("SerialComm", 2000);
  10.         // 设置串口参数
  11.         serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
  12.         // 获取输入输出流
  13.         InputStream inputStream = serialPort.getInputStream();
  14.         OutputStream outputStream = serialPort.getOutputStream();
  15.         // 发送命令
  16.         String command = "READ_REGISTER";
  17.         outputStream.write(command.getBytes());
  18.         // 接收响应
  19.         byte[] buffer = new byte[1024];
  20.         int length = inputStream.read(buffer);
  21.         System.out.println("读取到的数据长度: " + length);
  22.         // 打印接收到的数据
  23.         for (int i = 0; i < length; i++) {
  24.             System.out.print((char) buffer[i]);
  25.         }
  26.         // 关闭串口
  27.         serialPort.close();
  28.     }
  29. }
复制代码
小结一下

通过 JSerialComm 库,咱们可以方便地在 Java 中实现串口通信。这个库简化了串口的设置和利用,且跨平台兼容性好,非常得当需要与硬件设备通过串口通信的项目。假如你在工业设备、嵌入式系统或物联网应用中需要使用串口通信,它是一个很好的选择。
总结一下三种方式的使用场景

以下是使用 JNIModbus协议串口通信库(JSerialComm或RXTX) 三种方式的场景总结:
1. JNI(Java Native Interface)

2. Modbus协议

3. 串口通信库(JSerialComm或RXTX)

总结对比:

选择哪种方式取决于设备的通信协议和项目的复杂性需求,假如是标准工业设备,Modbus协议 是首选。假如是自界说设备或嵌入式设备,使用 JSerialCommRXTX。假如需要高效底层硬件访问:JNI 可能是唯一选择。好了,本日的内容就到这里,欢迎关注威哥爱编程,点赞关注加收藏,让我们一起在 Java 路上越走越远。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4