SpringBoot 2.2.6 集成ModbusTCP协议 请求从站获取数据

概要

  1. 转载地址
  2. 通过后端集成ModbusTCP协议,主动请求从站获取数据。
  3. 因甲方方案调整,此代码最终未采用,故也未进行更多的处理与优化。

什么是Modbus TCP

image.png

如何集成Modbus TCP MASTER

  1. 仿真机下载地址 仿真机有主站和从站 需要模拟从站 下载 Modbus Slave 激活码 5455415451475662

  2. 添加依赖

implementation 'com.digitalpetri.modbus:modbus-master-tcp:1.1.0'
  1. 贴代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ExecutionException;

@RestController
@RequestMapping("/modbus")
public class ModbusApi {

    private static final Logger LOGGER = LoggerFactory.getLogger(ModbusApi.class);

    @Autowired
    private ModbusService modbusService;

    @ResponseBody
    @GetMapping
    public void get(int address, int unitId, ModbusEunm modbusEunm, int typeId) throws ExecutionException, InterruptedException {
        modbusService.get(address, unitId, modbusEunm, typeId);
    }
}

import com.syxp.dlsesp.base.BaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.ExecutionException;

@Service
public class ModbusService extends BaseService<ModbusEntity> {

    private static final Logger LOGGER = LoggerFactory.getLogger(ModbusService.class);

    @Autowired
    private ModbusMasterTCP modbusMasterTCP;

    public void get(int address, int unitId, ModbusEunm modbusEunm, int typeId) throws ExecutionException, InterruptedException {
        Number number;
        switch (modbusEunm) {
            case COILS:
                Boolean coils = modbusMasterTCP.readCoils(address, unitId, typeId);
                number = coils ? 1 : 0;
                break;
            case DISCRETE_INPUTS:
                Boolean discreteInputs = modbusMasterTCP.readDiscreteInputs(address, unitId, typeId);
                number = discreteInputs ? 1 : 0;
                break;
            case HOLDING_REGISTERS:
                number = modbusMasterTCP.readHoldingRegisters(address, unitId, typeId);
                break;
            case INPUT_REGISTERS:
                number = modbusMasterTCP.readInputRegisters(address, unitId, typeId);
                break;
            default:
                number = -1;
        }
        ModbusEntity modbusEntity = new ModbusEntity();
        modbusEntity.setAddress(address);
        modbusEntity.setfId(modbusEunm.getCode());
        modbusEntity.setsId(unitId);
        modbusEntity.setData(number.doubleValue());
        this.save(modbusEntity);
        LOGGER.info(number.toString());
    }
}

import com.digitalpetri.modbus.codec.Modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.master.ModbusTcpMasterConfig;
import com.digitalpetri.modbus.requests.ReadCoilsRequest;
import com.digitalpetri.modbus.requests.ReadDiscreteInputsRequest;
import com.digitalpetri.modbus.requests.ReadHoldingRegistersRequest;
import com.digitalpetri.modbus.requests.ReadInputRegistersRequest;
import com.digitalpetri.modbus.responses.ReadCoilsResponse;
import com.digitalpetri.modbus.responses.ReadDiscreteInputsResponse;
import com.digitalpetri.modbus.responses.ReadHoldingRegistersResponse;
import com.digitalpetri.modbus.responses.ReadInputRegistersResponse;
import com.serotonin.modbus4j.code.DataType;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Component
public class ModbusMasterTCP {

    public static String address;
    public static int port;

    public String getAddress() {
        return address;
    }

    @Value("${modbusAddress}")
    public void setAddress(String address) {
        ModbusMasterTCP.address = address;
    }

    public int getPort() {
        return port;
    }

    @Value("${modbusPort}")
    public void setPort(int port) {
        ModbusMasterTCP.port = port;
    }

    static ModbusTcpMaster master;

    /**
     * 获取TCP协议的Master
     *
     * @return
     */
    @Bean
    public void initModbusTcpMaster() {
        if (master == null) {
            // 创建配置
            ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(ModbusMasterTCP.address).setPort(ModbusMasterTCP.port).build();
            master = new ModbusTcpMaster(config);
        }
    }

    /***
     * 释放资源
     */
    public void release() {
        if (master != null) {
            master.disconnect();
        }
        Modbus.releaseSharedResources();
    }

    /**
     * 读取Coils开关量
     *
     * @param address 寄存器开始地址
     * @param unitId  ID
     * @return 读取值
     * @throws InterruptedException 异常
     * @throws ExecutionException   异常
     */
    public Boolean readCoils(int address, int unitId, int typeId)
            throws InterruptedException, ExecutionException {
        Boolean result = null;
        CompletableFuture<ReadCoilsResponse> future = master.sendRequest(new ReadCoilsRequest(address, DataType.getRegisterCount(typeId)),
                unitId);
        ReadCoilsResponse readCoilsResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
        if (readCoilsResponse != null) {
            ByteBuf buf = readCoilsResponse.getCoilStatus();
            result = buf.readBoolean();
            ReferenceCountUtil.release(readCoilsResponse);
        }
        return result;
    }

    /**
     * 读取readDiscreteInputs开关量
     *
     * @param address 寄存器开始地址
     * @param unitId  ID
     * @return 读取值
     * @throws InterruptedException 异常
     * @throws ExecutionException   异常
     */
    public Boolean readDiscreteInputs(int address, int unitId, int typeId)
            throws InterruptedException, ExecutionException {
        Boolean result = null;
        CompletableFuture<ReadDiscreteInputsResponse> future = master
                .sendRequest(new ReadDiscreteInputsRequest(address, DataType.getRegisterCount(typeId)), unitId);
        ReadDiscreteInputsResponse discreteInputsResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
        if (discreteInputsResponse != null) {
            ByteBuf buf = discreteInputsResponse.getInputStatus();
            result = buf.readBoolean();
            ReferenceCountUtil.release(discreteInputsResponse);
        }
        return result;
    }

    /**
     * 读取HoldingRegister数据
     *
     * @param address 寄存器地址
     * @param unitId  id
     * @return 读取结果
     * @throws InterruptedException 异常
     * @throws ExecutionException   异常
     */
    public Number readHoldingRegisters(int address, int unitId, int typeId)
            throws InterruptedException, ExecutionException {
        Number result = null;
        CompletableFuture<ReadHoldingRegistersResponse> future = master
                .sendRequest(new ReadHoldingRegistersRequest(address, DataType.getRegisterCount(typeId)), unitId);
        ReadHoldingRegistersResponse readHoldingRegistersResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
        if (readHoldingRegistersResponse != null) {
            ByteBuf buf = readHoldingRegistersResponse.getRegisters();
            result = this.getJavaType(buf, typeId);
            ReferenceCountUtil.release(readHoldingRegistersResponse);
        }
        return result;
    }

    /**
     * 读取InputRegisters模拟量数据
     *
     * @param address 寄存器开始地址
     * @param unitId  ID
     * @return 读取值
     * @throws InterruptedException 异常
     * @throws ExecutionException   异常
     */
    public Number readInputRegisters(int address, int unitId, int typeId)
            throws InterruptedException, ExecutionException {
        Number result = null;
        CompletableFuture<ReadInputRegistersResponse> future = master
                .sendRequest(new ReadInputRegistersRequest(address, DataType.getRegisterCount(typeId)), unitId);
        ReadInputRegistersResponse readInputRegistersResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
        if (readInputRegistersResponse != null) {
            ByteBuf buf = readInputRegistersResponse.getRegisters();
            result = this.getJavaType(buf, typeId);
            ReferenceCountUtil.release(readInputRegistersResponse);
        }
        return result;
    }


    /**
     * 转换slave数据格式
     *
     * @param buf    字节容器
     * @param typeId 数据库类型id 类型id参考 com.serotonin.modbus4j.code.DataType
     * @return 转换后的数据格式
     */
    private Number getJavaType(ByteBuf buf, int typeId) {
        switch (typeId) {
            case 2:
            case 5:
            case 7:
            case 10:
            case 12:
            case 17:
            case 20:
            case 22:
            case 25:
                return buf.readInt();
            case 3:
            case 16:
            case 23:
                return buf.readShort();
            case 4:
            case 6:
            case 11:
            case 13:
            case 24:
                return buf.readLong();
            case 14:
            case 15:
                return buf.readDouble();
            case 8:
            case 9:
            case 18:
            case 21:
                return buf.readFloat();
            default:
                return null;
        }

    }


}

public enum ModbusEunm {

    /**
     * 读线圈
     */
    COILS("01"),
    /**
     * 读离散输入
     */
    DISCRETE_INPUTS("02"),
    /**
     * 读保存寄存器
     */
    HOLDING_REGISTERS("03"),
    /**
     * 读输入寄存器
     */
    INPUT_REGISTERS("04");

    private String code;

    ModbusEunm(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

import com.syxp.dlsesp.base.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "T_MODBUS")
@ApiModel(description = "Modbus元数据")
public class ModbusEntity extends BaseEntity {

    @Column(columnDefinition = "DOUBLE(9,2)")
    private Double data;


    @Column
    @ApiModelProperty(value = "从机编号")
    private Integer sId;

    @Column
    @ApiModelProperty(value = "功能编码")
    private String fId;

    @Column
    @ApiModelProperty(value = "地址编号")
    private Integer address;

    public Double getData() {
        return data;
    }

    public void setData(Double data) {
        this.data = data;
    }

    public Integer getsId() {
        return sId;
    }

    public void setsId(Integer sId) {
        this.sId = sId;
    }

    public String getfId() {
        return fId;
    }

    public void setfId(String fId) {
        this.fId = fId;
    }

    public Integer getAddress() {
        return address;
    }

    public void setAddress(Integer address) {
        this.address = address;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。