Easy Mod bus TCP / U DP / R TU Java 클 라이언 트 샘플 코드

무료무료 기술 자료

이 글은 바로 읽을 수 있으며 기초 학습과 검색 유입에 적합합니다.

Easy Mod bus TCP / U DP / R TU Java 클 라이언 트 샘플 코드

EasyModbus是Java生态中最流行的Modbus通讯库之一,以其简洁的API、丰富的功能和良好的문서著称。它支持Modbus TCP、RTU和UDP三种프로토콜,既可作为클라이언트也可作为服务端,广泛적용于산업 자동화、데이터采集、物联网게이트웨이等领域。本文详细介绍EasyModbus的安装설정、연결管理、코일读写、레지스터读写、浮点数处理以及完整的项目예제。

一、EasyModbus库개요

1.1 核心特性

  • 多프로토콜支持:Modbus TCP、RTU、UDP三种传输모드
  • 主从兼备:既可作为클라이언트(마스터),也可作为服务端(슬레이브)
  • 功能完整:支持01-16所有표준기능 코드
  • 데이터유형丰富:支持16位/32位整数、32位/64位浮点数、문자串
  • 바이트序可配:支持大端、小端、字交换等多种바이트序
  • 事件驱动:支持데이터变化监听、연결状态回调
  • 跨平台:Windows、Linux、Mac OS、嵌入式Linux均可运行
  • 오픈소스무료:MIT프로토콜,可무료用于商业项目

1.2 Maven依赖설정

<!-- pom.xml -->
<dependency>
    <groupId>com.github.s7connector</groupId>
    <artifactId>easy-modbus</artifactId>
    <version>5.0.0</version>
</dependency>

<!-- 시리얼 포트支持(RTU모드需要) -->
<dependency>
    <groupId>com.fazecast</groupId>
    <artifactId>jSerialComm</artifactId>
    <version>2.9.2</version>
</dependency>

1.3 Gradle依赖설정

// build.gradle
dependencies {
    implementation 'com.github.s7connector:easy-modbus:5.0.0'
    implementation 'com.fazecast:jSerialComm:2.9.2'
}

二、TCP클라이언트基础操作

2.1 建立연결

import de.re.easymodbus.modbusclient.ModbusClient;
import de.re.easymodbus.exceptions.ModbusException;
import java.io.IOException;

public class ModbusTcpDemo {
    
    public static void main(String[] args) {
        // 创建Modbus클라이언트
        ModbusClient client = new ModbusClient("192.168.1.100", 502);
        
        try {
            // 设置슬레이브 주소(Unit ID)
            client.setUnitIdentifier((byte) 1);
            
            // 设置연결超时(毫秒)
            client.setConnectionTimeout(3000);
            
            // 建立연결
            client.Connect();
            System.out.println("연결成功!");
            
            // 业务逻辑...
            
            // 닫기연결
            client.Disconnect();
            System.out.println("연결已닫기");
            
        } catch (IOException e) {
            System.err.println("연결失败:" + e.getMessage());
        } catch (ModbusException e) {
            System.err.println("Modbus异常:" + e.getMessage());
        }
    }
}

2.2 读코일(기능 코드01)

// 읽기从주소0开始的8个코일 상태
boolean[] coils = client.ReadCoils(0, 8);

System.out.println("코일 상태:");
for (int i = 0; i < coils.length; i++) {
    System.out.println("  코일" + i + ":" + (coils[i] ? "吸合" : "断开"));
}

// 方法签名:
// boolean[] ReadCoils(int 시작ing주소, int 수량)
// 시작ing주소: 시작주소(0-based)
// 수량: 읽을 수량(1-2000)

2.3 读이산 입력(기능 코드02)

// 읽기从주소0开始的4个이산 입력
boolean[] inputs = client.ReadDiscreteInputs(0, 4);

for (int i = 0; i < inputs.length; i++) {
    System.out.println("입력" + i + ":" + (inputs[i] ? "高电平" : "低电平"));
}

2.4 读유지 레지스터(기능 코드03)

// 읽기从주소0开始的10个유지 레지스터
int[] registers = client.ReadHolding회원가입s(0, 10);

System.out.println("유지 레지스터:");
for (int i = 0; i < registers.length; i++) {
    System.out.println("  레지스터" + i + ":" + registers[i]);
}

// 返回值为int数组,每个元素为16位无符号整数(0-65535)
// 如需有符号整数:short value = (short) registers[i];

2.5 读입력 레지스터(기능 코드04)

// 읽기센서데이터(온도、湿度等)
int[] inputRegs = client.ReadInput회원가입s(0, 2);

double temperature = inputRegs[0] / 10.0;  // 온도放大10倍
double humidity = inputRegs[1] / 10.0;     // 湿度放大10倍
System.out.printf("온도:%.1f℃,湿度:%.1f%%RH%n", temperature, humidity);

2.6 写单个코일(기능 코드05)

// 控制주소0的코일吸合
client.WriteSingleCoil(0, true);
System.out.println("코일吸合成功");

// 控制주소0的코일断开
client.WriteSingleCoil(0, false);

// 方法签名:
// void WriteSingleCoil(int 주소, boolean value)

2.7 写单个레지스터(기능 코드06)

// 向주소0쓰기数值1234
client.WriteSingle회원가입(0, 1234);
System.out.println("레지스터쓰기成功");

// 쓰기有符号数(-100)
client.WriteSingle회원가입(0, -100 & 0xFFFF);

2.8 写多个코일(기능 코드15)

// 同时控制前4个코일
boolean[] values = {true, false, true, false};
client.WriteMultipleCoils(0, values);
System.out.println("批量写코일成功");

2.9 写多个레지스터(기능 코드16)

// 向주소0开始쓰기3个레지스터
int[] values = {100, 200, 300};
client.WriteMultiple회원가입s(0, values);
System.out.println("批量写레지스터成功");

三、浮点数与多바이트데이터处理

EasyModbus提供了便捷的方法处理32位浮点数、32位整数和64位데이터,支持多种바이트序。

3.1 읽기32位浮点数

import de.re.easymodbus.데이터types.데이터Type;

// 읽기2个레지스터并转换为32位浮点数
// 方法1:使用ReadHolding회원가입s手动转换
int[] regs = client.ReadHolding회원가입s(10, 2);
float floatValue = client.Convert회원가입sToFloat(regs);
System.out.println("浮点数值:" + floatValue);

// 方法2:直接읽기浮点数(v5.0+支持)
float temp = client.ReadFloat(10, 데이터Type.FLOAT);
System.out.println("온도:" + temp);

// 设置바이트序(默认大端ABCD)
client.set데이터Type(데이터Type.FLOAT);  // 32位浮点数
// 可选:데이터Type.FLOAT_SWAP (CDAB), 데이터Type.FLOAT_LOWWORD_FIRST (BADC)

3.2 쓰기32位浮点数

// 将浮点数25.5转换为2个레지스터并쓰기
float value = 25.5f;
int[] regs = client.ConvertFloatTo회원가입s(value);
client.WriteMultiple회원가입s(10, regs);
System.out.println("쓰기浮点数:" + value + ",레지스터 값:" + regs[0] + ", " + regs[1]);

3.3 읽기32位整数

// 읽기32位无符号整数
int[] regs = client.ReadHolding회원가입s(0, 2);
long uint32 = client.Convert회원가입sToLong(regs);
System.out.println("32位无符号整数:" + uint32);

// 읽기32位有符号整数
int int32 = (int) uint32;
System.out.println("32位有符号整数:" + int32);

3.4 읽기문자串

// 읽기문자串(每个레지스터存2个문자,읽기10个레지스터=20문자)
int[] regs = client.ReadHolding회원가입s(0, 10);
String str = client.Convert회원가입sToString(regs, 20);
System.out.println("문자串:" + str);

3.5 바이트序설명

데이터Type枚举바이트序설명
FLOATABCD(大端)大多数PLC、Modbus设备
FLOAT_SWAPCDAB(字交换)部分西门子设备
FLOAT_LOWWORD_FIRSTBADC(바이트交换)较少见
FLOAT_SWAP_LOWWORD_FIRSTDCBA(小端)部分嵌入式设备

四、Modbus RTU시리얼 포트通讯

import de.re.easymodbus.modbusclient.ModbusClient;
import de.re.easymodbus.데이터types.Parity;
import de.re.easymodbus.데이터types.StopBits;

public class ModbusRtuDemo {
    
    public static void main(String[] args) {
        // 创建RTU클라이언트
        ModbusClient client = new ModbusClient();
        
        try {
            // 设置시리얼 포트 매개변수
            client.setSerialPort("/dev/ttyUSB0");  // 시리얼 포트设备(Windows为"COM3")
            client.setBaudRate(9600);               // 통신 속도
            client.setParity(Parity.None);          // 패리티:None/Even/Odd
            client.setStopBits(StopBits.One);       // 정지 비트:One/Two
            client.set데이터Bits(8);                  // 데이터 비트
            
            // 设置슬레이브 주소
            client.setUnitIdentifier((byte) 1);
            
            // 建立연결
            client.Connect();
            System.out.println("RTU연결成功");
            
            // 读写操作与TCP完全相同
            int[] regs = client.ReadHolding회원가입s(0, 10);
            System.out.println("레지스터:" + java.util.Arrays.toString(regs));
            
            client.Disconnect();
            
        } catch (Exception e) {
            System.err.println("错误:" + e.getMessage());
        }
    }
}

五、完整도구类封装

import de.re.easymodbus.modbusclient.ModbusClient;
import de.re.easymodbus.exceptions.ModbusException;
import java.io.IOException;

public class ModbusUtil {
    private ModbusClient client;
    private final String host;
    private final int port;
    private final byte slaveId;
    
    public ModbusUtil(String host, int port, int slaveId) {
        this.host = host;
        this.port = port;
        this.slaveId = (byte) slaveId;
    }
    
    /**
     * 建立연결(带重试)
     */
    public boolean connect() {
        for (int attempt = 1; attempt <= 3; attempt++) {
            try {
                client = new ModbusClient(host, port);
                client.setUnitIdentifier(slaveId);
                client.setConnectionTimeout(3000);
                client.Connect();
                System.out.println("연결成功:" + host + ":" + port);
                return true;
            } catch (IOException e) {
                System.err.println("연결失败(第" + attempt + "次):" + e.getMessage());
                try { Thread.sleep(1000); } catch (InterruptedException ie) { }
            }
        }
        return false;
    }
    
    /**
     * 断开연결
     */
    public void disconnect() {
        if (client != null) {
            try {
                client.Disconnect();
                System.out.println("연결已닫기");
            } catch (IOException e) {
                System.err.println("닫기연결失败:" + e.getMessage());
            }
        }
    }
    
    /**
     * 유지 레지스터 읽기 (FC03)(带重试)
     */
    public int[] read회원가입s(int addr, int count) {
        for (int attempt = 1; attempt <= 3; attempt++) {
            try {
                return client.ReadHolding회원가입s(addr, count);
            } catch (Exception e) {
                System.err.println("읽기失败(第" + attempt + "次):" + e.getMessage());
                reconnect();
            }
        }
        throw new RuntimeException("읽기레지스터失败,주소:" + addr);
    }
    
    /**
     * 읽기32位浮点数
     */
    public float readFloat(int addr) {
        int[] regs = read회원가입s(addr, 2);
        return client.Convert회원가입sToFloat(regs);
    }
    
    /**
     * 쓰기32位浮点数
     */
    public void writeFloat(int addr, float value) {
        int[] regs = client.ConvertFloatTo회원가입s(value);
        write회원가입s(addr, regs);
    }
    
    /**
     * 다중 레지스터 쓰기 (FC16)
     */
    public void write회원가입s(int addr, int[] values) {
        for (int attempt = 1; attempt <= 3; attempt++) {
            try {
                client.WriteMultiple회원가입s(addr, values);
                return;
            } catch (Exception e) {
                System.err.println("쓰기失败(第" + attempt + "次):" + e.getMessage());
                reconnect();
            }
        }
        throw new RuntimeException("쓰기레지스터失败,주소:" + addr);
    }
    
    /**
     * 写单个코일
     */
    public void writeCoil(int addr, boolean value) {
        try {
            client.WriteSingleCoil(addr, value);
        } catch (Exception e) {
            throw new RuntimeException("写코일失败:" + e.getMessage());
        }
    }
    
    /**
     * 读코일
     */
    public boolean[] readCoils(int addr, int count) {
        try {
            return client.ReadCoils(addr, count);
        } catch (Exception e) {
            throw new RuntimeException("读코일失败:" + e.getMessage());
        }
    }
    
    /**
     * 重新연결
     */
    private void reconnect() {
        disconnect();
        connect();
    }
}

// 使用예제
class Demo {
    public static void main(String[] args) {
        ModbusUtil mb = new ModbusUtil("192.168.1.100", 502, 1);
        
        if (mb.connect()) {
            // 읽기온도(浮点数)
            float temp = mb.readFloat(10);
            System.out.printf("온도:%.2f℃%n", temp);
            
            // 읽기10个레지스터
            int[] regs = mb.read회원가입s(0, 10);
            System.out.println("레지스터:" + java.util.Arrays.toString(regs));
            
            // 控制릴레이
            mb.writeCoil(0, true);
            System.out.println("릴레이1已吸合");
            
            // 읽기릴레이状态
            boolean[] coils = mb.readCoils(0, 8);
            System.out.println("릴레이状态:" + java.util.Arrays.toString(coils));
            
            mb.disconnect();
        }
    }
}

六、Modbus服务端(슬레이브)实现

import de.re.easymodbus.modbusserver.ModbusServer;

public class ModbusServerDemo {
    
    public static void main(String[] args) {
        // 创建Modbus TCP服务端
        ModbusServer server = new ModbusServer();
        
        try {
            // 设置监听포트
            server.setPort(502);
            
            // 设置슬레이브 주소
            server.setUnitIdentifier((byte) 1);
            
            // 设置初始值
            server.holding회원가입s[0] = 100;  // 온도
            server.holding회원가입s[1] = 50;   // 湿度
            server.coils[0] = true;            // 릴레이1
            
            // 启动服务端
            server.Listen();
            System.out.println("Modbus TCP服务端已启动,监听포트:502");
            
            // 模拟데이터更新
            while (true) {
                Thread.sleep(1000);
                server.holding회원가입s[2] = (int) (Math.random() * 100);
                server.input회원가입s[0] = (int) (Math.random() * 4096);
            }
            
        } catch (Exception e) {
            System.err.println("服务端错误:" + e.getMessage());
        }
    }
}

七、实际적용:릴레이模块控制

public class Relay컨트롤러 {
    private final ModbusUtil mb;
    
    public Relay컨트롤러(String host) {
        mb = new ModbusUtil(host, 502, 1);
        mb.connect();
    }
    
    /** 읽기所有릴레이状态 */
    public boolean[] getAllStatus() {
        return mb.readCoils(0, 8);
    }
    
    /** 열기指定通道(1-8) */
    public void turnOn(int channel) {
        mb.writeCoil(channel - 1, true);
    }
    
    /** 닫기指定通道 */
    public void turnOff(int channel) {
        mb.writeCoil(channel - 1, false);
    }
    
    /** 전환指定通道状态 */
    public void toggle(int channel) {
        boolean[] coils = mb.readCoils(channel - 1, 1);
        mb.writeCoil(channel - 1, !coils[0]);
    }
    
    /** 跑马灯效果 */
    public void marquee(int delayMs) {
        for (int i = 1; i <= 8; i++) {
            turnOn(i);
            try { Thread.sleep(delayMs); } catch (InterruptedException e) { }
            turnOff(i);
        }
    }
    
    public void close() {
        mb.disconnect();
    }
    
    public static void main(String[] args) {
        Relay컨트롤러 relay = new Relay컨트롤러("192.168.1.100");
        
        // 읽기当前状态
        boolean[] status = relay.getAllStatus();
        System.out.print("当前状态:");
        for (boolean s : status) {
            System.out.print(s ? "ON " : "OFF ");
        }
        System.out.println();
        
        // 跑马灯测试
        System.out.println("跑马灯测试...");
        relay.marquee(300);
        
        // 依次控制
        relay.turnOn(1);
        try { Thread.sleep(500); } catch (InterruptedException e) { }
        relay.turnOn(2);
        try { Thread.sleep(500); } catch (InterruptedException e) { }
        relay.turnOff(1);
        try { Thread.sleep(500); } catch (InterruptedException e) { }
        relay.turnOff(2);
        
        relay.close();
    }
}

八、常见문제与最佳实践

8.1 常见문제

  • 연결超时:检查IP주소、포트号、防火墙,确认设备在线且포트502开放
  • 返回异常响应:检查슬레이브 주소(Unit ID)是否正确,기능 코드和주소是否在设备支持范围内
  • 浮点数분석错误:尝试不同的데이터Type(FLOAT/FLOAT_SWAP等),确认设备的데이터형식
  • RTU시리얼 포트打不开:检查시리얼 포트设备名,确认权限(Linux需加入dialout组),닫기其他占用시리얼 포트的程序
  • 데이터읽기为0:确认레지스터주소正确,注意0-based和1-based주소的区别
  • 频繁断连:추가超时时间,检查네트워크稳定性,추가自动重连机制

8.2 最佳实践

  • 使用try-with-resources:确保연결正确닫기
  • 批量읽기:尽量一次읽기多个레지스터,减少通讯次数
  • 合理设置超时:局域网建议1-3秒,RTU建议3-5秒
  • 추가重试机制:네트워크不稳定时自动重试2-3次
  • 控制轮询频率:避免过快轮询,建议间隔不小于100ms
  • 异常处理:捕获ModbusException和IOException,区分연결错误和프로토콜错误
  • 로그记录:记录每次读写的주소、데이터和耗时,便于排查
  • 多设备管理:每个设备使用独立的ModbusClient实例,避免共享연결

九、其他Java Modbus库对比

库名프로토콜支持特点适用시나리오
EasyModbusTCP/RTU/UDPAPI简洁,문서完善,功能丰富大多数项目首选
j2modTCP/RTU/ASCIIj2mod的活跃分支,功能全面需要ASCII프로토콜
JamodTCP/RTU经典库,稳定但更新慢遗留项目维护
Modbus4JTCP/RTU강력한 성능,API较复杂复杂项目
modbus-masterTCP/RTU轻量级,仅마스터简单读写시나리오

EasyModbus以其简洁的API和丰富的功能,成为Java Modbus개발的首选库。本文提供的도구类可直接用于项目개발,建议先使用Modbus Poll等도구确认设备通讯正常,再将Java代码통합到实际项目中。

실제 프로젝트에 이 자료를 활용하시겠습니까?

도구 센터에서 프레임 분석, CRC 검증, 장비 디버깅을 진행하거나 요청을 제출하여 선정 및 연동 제안을 받아보세요.

엔지니어 회원

이 글을 실행 가능한 디버깅 자료로 활용하세요

가입하면 고급 프레임 분석, 자료 패키지 다운로드, 코드 예제, 엔지니어링 사례, 우선 기술 지원을 이용할 수 있어 실제 프로젝트 납품에 적합합니다.

고급 도구 무제한 이용
자료 패키지와 코드 패키지
완전한 엔지니어링 사례 라이브러리
우선 기술 지원 채널

답글 작성

이메일 주소는 공개되지 않습니다. 必填项已用 * 标注