资讯详情

modbus连接PLC

modbus连接PLC

  1. 创建springboot项目

  2. 导入pom文件

    <dependency>     <groupId>com.infiniteautomation</groupId>     <artifactId>modbus4j</artifactId>     <version>${ 
              modbus.version}</version> </dependency> 

3.在com.ncty.modbus.config下创建ModbusConfig类

package com.ncty.modbus.config;   /**  * @author zyw  * @version 1.0  * @date 2021-09-23 11:25  */  import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.exception.ModbusInitException; import com.serotonin.modbus4j.ip.IpParameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import java.util.HashMap;  @Configuration /*  * 使用@Bean,就不用使用@Import导入相应的类,@Bean生成的bean默认的名字是方法名,因为hashMap广泛使用,  * 所以使用@Bean引入依赖的方式,以便在注入时指定名称,以免注入错误的对象  * @Import({java.util.HashMap.class,com.serotonin.modbus4j.ModbusFactory.class})  */ @Import(ModbusFactory.class) public class ModbusConfig {     @Bean     public HashMap<String, ModbusMaster> modbusMasterHashMap() {          return new HashMap<>();     }        @Autowired     private ModbusFactory modbusFactory;      @Autowired     @Qualifier("modbusMasterHashMap")     private HashMap<String,ModbusMaster> masterMap;      /**      * @Description:  通过ip获取对应的modbus连接器      * @Param:  [ip]      * @return:  com.serotonin.modbus4j.ModbusMaster      * @throws:      */     public ModbusMaster getMaster(String ip) {          ModbusMaster modbusMaster = masterMap.get(ip);         if(modbusMaster == null) {             setMaster(ip, 502);             modbusMaster = masterMap.get(ip);         }         return modbusMaster;       }      /**      * @Description:  设置ip对应的modbus连接器      * @Param:  [ip, port]      * @return:  void      * @throws:      */     private void setMaster(String ip, Integer port) {          ModbusMaster master;         IpParameters params = new IpParameters();         params.setHost(ip);         params.setPort(port);         /**          * 设置为true,会导致TimeoutException: request=com.serotonin.modbus4j.ip.encap.EncapMessageRequest@774dfba5",          * params.setEncapsulated(true);          * TCP 协议          */         master = modbusFactory.createTcpMaster(params, false);         try {             //设置超时间             master.setTimeout(3*1000);             //设置重连次数             master.setRetries(3);             //初始化             master.init();         } catch (ModbusInitException e) {             e.printStackTrace();         }         masterMap.put(ip, master);     } } 

4.在com.ncty.modbus.utils下创建ModbusUtil类

package com.ncty.modbus.utils;  import com.ncty.modbus.config.ModbusConfig; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.exception.ModbusInitException; import com.serotonin.modbus4j.exception.ModbusTransportException; import com.serotonin.modbus4j.msg.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;  /**  * @author zyw  * @version 1.0  * @date 2021-08-20 9:58  */ @Component public class ModbusUtil {      //从机默认值     private Integer slaveId = 1;      @Autowired     private ModbusConfig modbusConig;


    public boolean[] readCoilStatus(String ip, int offset, int numberOfRegister) throws ModbusTransportException {

        ModbusMaster master = modbusConfig.getMaster(ip);
        ReadCoilsRequest request = new ReadCoilsRequest(slaveId, offset, numberOfRegister);
        ReadCoilsResponse response = (ReadCoilsResponse) master.send(request);
        boolean[] booleans = response.getBooleanData();

        return valueRegroup(numberOfRegister, booleans);
    }

    /**
     * @Description:  读取外围设备输入的开关量,相当于功能码:02H-读离散输入状态
     * @Param:  [ip, offset, numberOfRegister]
     * @return:  boolean[]
     * @throws:

     */
    public boolean[] readInputStatus(String ip, int offset, int numberOfRegister) throws ModbusTransportException {

        ModbusMaster master = modbusConfig.getMaster(ip);
        ReadDiscreteInputsRequest request = new ReadDiscreteInputsRequest(slaveId,offset, numberOfRegister);
        ReadDiscreteInputsResponse response = (ReadDiscreteInputsResponse) master.send(request);
        boolean[] booleans = response.getBooleanData();

        return valueRegroup(numberOfRegister, booleans);
    }

    /**
     * @Description:  读取保持寄存器数据,相当于功能码:03H-读保持寄存器
     * @Param:  [ip, offset, numberOfRegister]
     * @return:  short[]
     * @throws:

     */
    public short[] readHoldingRegister(String ip, int offset, int numberOfRegister) throws ModbusTransportException {

        ModbusMaster master = modbusConfig.getMaster(ip);
        ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, offset, numberOfRegister);
        ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request);
        return response.getShortData();
    }

    /**
     * @Description:  读取外围设备输入的数据,相当于功能码:04H-读输入寄存器
     * @Param:  [ip, offset, numberOfRegister]
     * @return:  short[]
     * @throws:
     */
    public short[] readInputRegisters(String ip, int offset, int numberOfRegister) throws ModbusTransportException {

        ModbusMaster master = modbusConfig.getMaster(ip);
        ReadInputRegistersRequest request = new ReadInputRegistersRequest(slaveId, offset, numberOfRegister);
        ReadInputRegistersResponse response = (ReadInputRegistersResponse) master.send(request);
        return response.getShortData();
    }

    /**
     * @Description:  写单个(线圈)开关量数据,相当于功能码:05H-写单个线圈
     * @Param:  [ip, writeOffset, writeValue]
     * @return:  boolean
     * @throws:
     * @Author:  Ricardo.Liu
     * @Date:  2020/5/8
     */
    public boolean writeCoil(String ip, int writeOffset, boolean writeValue) throws ModbusTransportException {

        ModbusMaster tcpMaster = modbusConfig.getMaster(ip);
        WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
        WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
        return !response.isException();
    }

    /**
     * @Description:  写多个开关量数据(线圈),相当于功能码:0FH-写多个线圈
     * @Param:  [ip, startOffset, data]
     * @return:  boolean
     * @throws:
     * @Author:  Ricardo.Liu
     * @Date:  2020/5/8
     */
    public boolean writeCoils(String ip, int startOffset, boolean[] data) throws ModbusTransportException {

        ModbusMaster tcpMaster = modbusConfig.getMaster(ip);
        WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, data);
        WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
        return !response.isException();

    }

    /**
     * @Description:  写单个保持寄存器,相当于功能码:06H-写单个保持寄存器
     * @Param:  [ip, writeOffset, writeValue]
     * @return:  boolean
     * @throws:
     */
    public boolean writeHoldingRegister(String ip, int writeOffset, short writeValue) throws ModbusTransportException, ModbusInitException {

        ModbusMaster tcpMaster = modbusConfig.getMaster(ip);
        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
        WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);
        return !response.isException();

    }

    /**
     * @Description:  写多个保持寄存器,相当于功能码:10H-写多个保持寄存器
     * @Param:  [ip, startOffset, data]
     * @return:  boolean
     * @throws:

     */
    public boolean writeHoldingRegisters(String ip, int startOffset, short[] data) throws ModbusTransportException, ModbusInitException {

        ModbusMaster tcpMaster = modbusConfig.getMaster(ip);
        WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, data);
        WriteRegistersResponse response = (WriteRegistersResponse) tcpMaster.send(request);
        return !response.isException();
    }

    /**
     * @Description:  转换工具,将Boolean转换成0,1
     * @Param:  [numberOfBits, values]
     * @return:  boolean[]
     * @throws:

     */
    private  boolean[] valueRegroup(int numberOfBits, boolean[] values) {
        boolean[] bs = new boolean[numberOfBits];
        int temp = 1;
        for (boolean b : values) {
            bs[temp - 1] = b;
            temp++;
            if (temp > numberOfBits) {
                break;
            }
        }
        return bs;
    }
}

5.在com.ncty.modbus.utils下创建ShortAndIntUtils类

package com.ncty.modbus.utils;

import org.springframework.stereotype.Component;

/**
 * @author zyw
 * @version 1.0
 * @date 2021-09-23 16:13
 * 转换读写PLC的DWORD转换字节码
 */
@Component
public class ShortAndIntUtils {

    public short[] intToShortArray(Integer num){
        String str = Integer.toBinaryString(num);
        int high = 0;
        int low = 0;//后16位
        if(str.length() > 16){
            high = Integer.parseInt(str.substring(0,str.length()-16) , 2);//前16位
            low = Integer.parseInt(str.substring(str.length() -16) , 2);//后16位
        }else {
            low = Integer.parseInt(str , 2);//后16位
        }
        if(high > Short.MAX_VALUE){
            high = (short) (Short.MAX_VALUE - high);
        }
        if(low > Short.MAX_VALUE){
            low = (short) (Short.MAX_VALUE - low);
        }
        short[] shorts = {(short) high, (short) low};
        return shorts;
    }

    public int shoToIntValue(short[] num){
        String str = "";
        for (int item : num) {
            if(item < 0){
                item = Short.MAX_VALUE-item;
            }
            str += Integer.toBinaryString(item);
        }
        return scale2Decimal(str , 2);
    }

    /**
     * 其他进制转十进制
     * @param number
     * @return
     */
    public static int scale2Decimal(String number, int scale) {
        String regexp = "^\\d+$";
        if (null == number || !number.matches(regexp)) {
            throw new IllegalArgumentException("input is not a number");
        }

        if (2 > scale || scale > 32) {
            throw new IllegalArgumentException("scale is not in range");
        }
        // 不同其他进制转十进制,修改这里即可
        int total = 0;
        String[] ch = number.split("");
        int chLength = ch.length;
        for (int i = 0; i < chLength; i++) {
            total += Integer.valueOf(ch[i]) * Math.pow(scale, chLength - 1 - i);
        }
        return total;
    }
}

6.在com.ncty.modbus.controller下创建ModbusController类

package com.ncty.modbus.controller;

import com.ncty.modbus.utils.ModbusUtil;
import com.ncty.modbus.utils.ShortAndIntUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zyw
 * @version 1.0
 * @date 2021-08-20 9:28
 * 测试读写接口
 * 下列是读取DWORD类型数据
 */
@RestController
@RequestMapping("/modbus")
public class ModbusController {

    @Autowired
    private ModbusUtil modbusUtil;

    @Autowired
    private ShortAndIntUtils shortAndIntUtils;

    @RequestMapping("read")
    public Integer read() throws Exception {
        short[] shorts = modbusUtil.readHoldingRegister("127.0.0.1", 3000, 2);
        return  shortAndIntUtils.shoToIntValue(shorts);
    }

    @RequestMapping("write")
    public String write() throws Exception {
        short[] shorts = shortAndIntUtils.intToShortArray(65535);

        modbusUtil.writeHoldingRegisters("localhost",3000, shorts);

         return "写入成功";
    }

}

标签: 连接器fh52

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台