You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Java实现Modbus设备寄存器读取并输出至JSP页面的技术问询

嘿,你的问题我刚好有不少实践经验,来给你一步步捋清楚:

核心问题解答

1. 能否通过Modbus协议直接读取设备寄存器值?

完全可以!Modbus本身就是为工业设备间的寄存器数据交互设计的,读取*保持寄存器(功能码03)*是最常用的场景之一。你提到的请求帧格式请求帧 = 设备地址 + 03(功能码) + 起始寄存器高字节 + 起始寄存器低字节 + 寄存器数量高字节 + 寄存器数量低字节 + CRC校验完全正确,只要按照这个规则组装报文,通过TCP/RTU发送给目标设备,就能直接拿到寄存器的原始值,不需要额外的中间转换。

2. Java实现Modbus读取并输出到JSP的方案

针对你的毕业设计和Java学习需求,推荐两种易上手的方案,避开复杂的Mango绑定部分:

方案一:用jamod(轻量直观,适合入门)

jamod是老牌的轻量Modbus Java库,API设计非常直白,没有多余的依赖,很适合学习阶段使用。

步骤1:引入依赖(Maven)

<dependency>
    <groupId>net.wimpi</groupId>
    <artifactId>jamod</artifactId>
    <version>1.2</version>
</dependency>

步骤2:读取保持寄存器的核心代码

import net.wimpi.modbus.Modbus;
import net.wimpi.modbus.io.ModbusTCPTransaction;
import net.wimpi.modbus.msg.ReadMultipleRegistersRequest;
import net.wimpi.modbus.msg.ReadMultipleRegistersResponse;
import net.wimpi.modbus.net.TCPMasterConnection;

import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;

public class ModbusRegisterReader {
    // 封装读取逻辑,返回寄存器地址和值的映射
    public static Map<Integer, Integer> readRegisters(String deviceIp, int deviceId, int startAddr, int count) {
        Map<Integer, Integer> registerData = new HashMap<>();
        TCPMasterConnection connection = null;
        try {
            // 建立TCP连接(Modbus TCP默认端口502)
            connection = new TCPMasterConnection(InetAddress.getByName(deviceIp));
            connection.setPort(Modbus.DEFAULT_PORT);
            connection.connect();

            // 创建读取请求:起始寄存器地址、读取数量
            ReadMultipleRegistersRequest request = new ReadMultipleRegistersRequest(startAddr, count);
            request.setUnitID(deviceId); // 设置设备地址

            // 执行事务
            ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection);
            transaction.setRequest(request);
            transaction.execute();

            // 解析响应数据
            ReadMultipleRegistersResponse response = (ReadMultipleRegistersResponse) transaction.getResponse();
            for (int i = 0; i < response.getWordCount(); i++) {
                registerData.put(startAddr + i, response.getRegisterValue(i));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null && connection.isConnected()) {
                connection.close();
            }
        }
        return registerData;
    }

    // 测试用主方法
    public static void main(String[] args) {
        Map<Integer, Integer> data = readRegisters("192.168.1.100", 1, 0, 10);
        data.forEach((addr, value) -> System.out.println("寄存器" + addr + ":" + value));
    }
}

步骤3:输出到JSP页面

把读取逻辑封装成工具类后,在Servlet或者Spring MVC的Controller中调用,将数据存入请求域,再转发到JSP:

// 示例Servlet代码
@WebServlet("/modbusData")
public class ModbusDataServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 调用工具类读取数据
        Map<Integer, Integer> registerData = ModbusRegisterReader.readRegisters("192.168.1.100", 1, 0, 10);
        // 存入请求域
        request.setAttribute("registerData", registerData);
        // 转发到JSP
        request.getRequestDispatcher("/modbusResult.jsp").forward(request, response);
    }
}

JSP页面用EL表达式展示数据:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Modbus寄存器数据展示</title>
</head>
<body>
    <h2>Altivar/Modicon设备寄存器读取结果</h2>
    <table border="1" cellpadding="8">
        <tr>
            <th>寄存器地址</th>
            <th>数值</th>
        </tr>
        <c:forEach items="${registerData}" var="entry">
            <tr>
                <td>${entry.key}</td>
                <td>${entry.value}</td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>

方案二:简化使用modbus4j(避开Mango,聚焦核心功能)

你觉得modbus4j难用,大概率是因为接触了它和Mango绑定的复杂部分,但单独用它的Modbus核心功能其实非常简洁,它会帮你自动处理报文组装、CRC校验这些细节。

步骤1:引入依赖(Maven)

<dependency>
    <groupId>com.infiniteautomation</groupId>
    <artifactId>modbus4j</artifactId>
    <version>3.0.3</version>
</dependency>

步骤2:读取寄存器的核心代码

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.locator.BaseLocator;

import java.util.HashMap;
import java.util.Map;

public class Modbus4jReader {
    public static Map<Integer, Short> readHoldingRegisters(String deviceIp, int deviceId, int startAddr, int count) {
        Map<Integer, Short> registerData = new HashMap<>();
        ModbusFactory modbusFactory = new ModbusFactory();
        // 创建TCP主站(第三个参数为false表示不保持连接)
        ModbusMaster master = modbusFactory.createTcpMaster(deviceIp, 502, false);
        try {
            master.init();
            // 循环读取每个寄存器(也可以用批量读取方法,更高效)
            for (int i = 0; i < count; i++) {
                // 定位器:设备地址、寄存器类型(保持寄存器)、地址、数据类型
                BaseLocator<Short> locator = BaseLocator.holdingRegister(deviceId, startAddr + i, Short.class);
                Short value = master.getValue(locator);
                registerData.put(startAddr + i, value);
            }
        } catch (ModbusInitException | ModbusTransportException e) {
            e.printStackTrace();
        } finally {
            master.destroy(); // 释放资源
        }
        return registerData;
    }

    public static void main(String[] args) {
        Map<Integer, Short> data = readHoldingRegisters("192.168.1.100", 1, 0, 10);
        data.forEach((addr, value) -> System.out.println("寄存器" + addr + ":" + value));
    }
}

这个方案的代码比jamod更简洁,适合快速实现功能,而且modbus4j的文档和社区资源也比较丰富,遇到问题容易找到解决方案。

3. 关于手动组装Modbus请求帧的补充

如果你想深入理解Modbus协议细节,手动组装请求帧也是可行的:用Java的ByteArrayOutputStream来拼接字节数组,比如设备地址1、起始寄存器0、读取10个寄存器的请求帧(十六进制)是01 03 00 00 00 0A D5 CA,其中最后两位是CRC16校验码,你可以自己实现CRC计算逻辑,然后通过Socket发送字节流,再解析响应帧。不过学习阶段还是推荐先用库实现功能,等熟悉了协议再手动实现,效率更高。

内容的提问来源于stack exchange,提问作者Миша Ивченко

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:51:54