【2023】JAVA and PLC realize communication to read and write data, taking Mitsubishi PLC as an example

1. Create a maven project and introduce dependencies

        <!-- https://mvnrepository.com/artifact/com.github.dathlin/HslCommunication -->
        <dependency>
            <groupId>com.github.dathlin</groupId>
            <artifactId>HslCommunication</artifactId>
            <version>3.3.1</version>
        </dependency>

There are two concepts that need to be understood to make PLC connections: long connections and short connections . In order to better explain the current communication situation, I split all communications into four parts, connection, sending, receiving, and disconnecting.

  • Short connection: connect, send, receive, disconnect, connect, send, receive, disconnect, connect, send, receive, disconnect, connect, send, receive, disconnect...infinite loop
  • Long connection: connect, send, receive, send, receive, send, receive, send, receive, send, receive, send, receive, send, receive, send, receive, send, receive...disconnect

Then let's take a look at the abnormal situation. The exception of short connection is easier to handle. Anyway, every request is connected first. The key is to look at the abnormal long connection of long connection
: connect, send, receive, send, receive... exception, connection, Send, receive, send, receive, exception, connect, connect, connect...send, send, receive, send, receive, send, receive, send, receive...disconnect
after the first exception occurs here, the second read and write immediately The connection was successful. After the second exception was triggered, reading and writing continued to fail, indicating that the connection could not be made.
For HSL components, there is no need to repeatedly connect to the server or PLC. Whether it is a short connection or a long connection, you only need to keep reading and writing, and the results of reading and writing are judged. Even if an exception occurs and the reading and writing fail, , but also keep insisting. When the network is good, reading and writing will resume successfully.

2. Connect and communicate through code

  • Realize short connection
// 实例化对象,指定PLC的ip地址和端口号
MelsecMcNet melsecMc = new MelsecMcNet( "192.168.1.110", 6000 );
// 举例读取D100的值
short D100 = melsecMc.ReadInt16( "D100" ).Content;
  • Realize long connection
// 实例化对象,指定PLC的ip地址和端口号
MelsecMcNet melsecMc = new MelsecMcNet( "192.168.1.110", 6000 );
// 如果网络不太理想,配置了两个端口,一个有问题,立即切换另一个的话,可以配置如下的代码
// melsecMc.GetPipeSocket( ).SetMultiPorts( new int[] { 6000, 6001 } );

// 连接对象
OperateResult connect = melsecMc.ConnectServer( );
if (!connect.IsSuccess)    //用于判断是否连接成功,返回true/false
{
    
    
    Console.WriteLine( "connect failed:" + connect.Message );
    return;
}

// 举例读取D100的值
short D100 = melsecMc.ReadInt16( "D100" ).Content;

// 实际上所有的读写都是返回是否成功的标记的,在实际的开发中,需要严格的判定,怎么判定呢?如下的代码
OperateResult<short> readD100 = melsecMc.ReadInt16( "D100" );
if (readD100.IsSuccess)
{
    
    
    // 读取成功,这时候获取Content才是正确的值
    short value = readD100.Content;
}
else
{
    
    
    // 读取失败,如果仍然坚持去获取Content的值,就为0
}

// 读写是否成功的情况,应用于几乎所有的读写代码,只要看清楚返回的数据类型即可
melsecMc.ConnectClose( );

3. Basic reading example

MelsecMcNet melsec_net = new MelsecMcNet( "192.168.0.100", 6000 );
melsec_net.SetPersistentConnection( );                                           // 设置长连接的操作

// 此处以D寄存器作为示例,此处没有判断是否读写成功,所以是有风险的,如果通讯失败,所有的值都不是正确的
short short_D1000 = melsec_net.ReadInt16( "D1000" ).Content;                     // 读取D1000的short值 
ushort ushort_D1000 = melsec_net.ReadUInt16( "D1000" ).Content;                  // 读取D1000的ushort值
int int_D1000 = melsec_net.ReadInt32( "D1000" ).Content;                         // 读取D1000-D1001组成的int数据
uint uint_D1000 = melsec_net.ReadUInt32( "D1000" ).Content;                      // 读取D1000-D1001组成的uint数据
float float_D1000 = melsec_net.ReadFloat( "D1000" ).Content;                     // 读取D1000-D1001组成的float数据
long long_D1000 = melsec_net.ReadInt64( "D1000" ).Content;                       // 读取D1000-D1003组成的long数据
ulong ulong_D1000 = melsec_net.ReadUInt64( "D1000" ).Content;                    // 读取D1000-D1003组成的long数据
double double_D1000 = melsec_net.ReadDouble( "D1000" ).Content;                  // 读取D1000-D1003组成的double数据
string str_D1000 = melsec_net.ReadString( "D1000", 10 ).Content;                 // 读取D1000-D1009组成的条码数据

// 读取数组
short[] short_D1000_array = melsec_net.ReadInt16( "D1000", 10 ).Content;         // 读取D1000的short值 
ushort[] ushort_D1000_array = melsec_net.ReadUInt16( "D1000", 10 ).Content;      // 读取D1000的ushort值
int[] int_D1000_array = melsec_net.ReadInt32( "D1000", 10 ).Content;             // 读取D1000-D1001组成的int数据
uint[] uint_D1000_array = melsec_net.ReadUInt32( "D1000", 10 ).Content;          // 读取D1000-D1001组成的uint数据
float[] float_D1000_array = melsec_net.ReadFloat( "D1000", 10 ).Content;         // 读取D1000-D1001组成的float数据
long[] long_D1000_array = melsec_net.ReadInt64( "D1000", 10 ).Content;           // 读取D1000-D1003组成的long数据
ulong[] ulong_D1000_array = melsec_net.ReadUInt64( "D1000", 10 ).Content;        // 读取D1000-D1003组成的long数据
double[] double_D1000_array = melsec_net.ReadDouble( "D1000", 10 ).Content;      // 读取D1000-D1003组成的double数据

4. Read the demo in detail

Common methods

  • setNetworkNumber(): set the network number
  • ConnectServer(): Switch the connection from short connection to long connection, need to disconnect and reconnect
  • SetPersistentConnection(): Set long connection operation, no need to disconnect and reconnect
  • IsSuccess: Determine whether the connection is successful
  • readThe methods at the beginning are all reading methods.
  • writeThe methods at the beginning are all writing methods
public class MelsenMcClent {
    
    

    private MelsecMcNet clent;
    private String ip;
    private int port;

    /**
     * 初始化连接对象
     * @author zhengfuping
     * @date 2023/1/9 8:07
     * @version 1.0
     */
    public boolean iniConnet(String ip,int port){
    
    
        clent = new MelsecMcNet(ip, port);
        this.ip = ip;
        this.port = port;
        clent.setNetworkStationNumber((byte) 0x00);
        clent.setSleepTime(10);
        OperateResult connet = clent.ConnectServer();
        return connet.IsSuccess;
    }
    /**
     * @description: TODO 重试连接
     * @author zhengfuping
     * @date 2023/1/9 8:07
     * @version 1.0
     */
    public boolean restartConnet(){
    
    
        OperateResult connet = clent.ConnectServer();
        if(connet != null && connet.IsSuccess){
    
    
            return true;
        }else{
    
    
            clent = new MelsecMcNet(this.ip, this.port);
            clent.setNetworkStationNumber((byte) 0x00);
            clent.setSleepTime(10);
            connet = clent.ConnectServer();
            return connet.IsSuccess;
        }
    }

    /**
     * 读取字符串
     * */
    public String read(String address,int length){
    
    
        OperateResultExOne<String> result = clent.ReadString(address,(short)length);
        return result.Content.trim();
    }
    /**
     * 读取32位数字
     * */
    public Integer readInt32(String address){
    
    
        OperateResultExOne<Integer> result = clent.ReadInt32(address);
        return result.Content;
    }
    /**
     * 读取16位数字
     * */
    public Short readInt16(String address){
    
    
        OperateResultExOne<Short> result = clent.ReadInt16(address);
        return result.Content;
    }
    /**
     * 读取浮点数
     * */
    public Float readFloat(String address){
    
    
        OperateResultExOne<Float> result = clent.ReadFloat(address);
        return result.Content;
    }

    /**
     * 写入字符串
     * */
    public boolean write(String address,String dataVal){
    
    
        OperateResult result = clent.Write(address, dataVal);
        return result.IsSuccess;
    }
    /**
     * 写入数字
     * */
    public boolean write(String address,short dataVal){
    
    
        OperateResult result = clent.Write(address, dataVal);
        return result.IsSuccess;
    }

//下面的或者工具类对象可以自己根据业务情况设置,一般三菱PLC是一个端口只能有一个客户端去连接
  /**
     * 创建单例
     * */
    private static class Interior{
    
    
        private static MelsenMcClent CLENT = new MelsenMcClent();

        public static MelsenMcClent getConnect(String state){
    
    
            MelsenMcClent writeClent;
            if (state.equals("Write")){
    
    
                writeClent = getWriteClent();
            }else if (state.equals("Read")){
    
    
                writeClent = getReadClent();
            }else {
    
    
                writeClent = null;
            }
            return writeClent;
        }

        /**
         * 写入对象
         * */
        private static MelsenMcClent getWriteClent(){
    
    
            MelsenMcClent writeClent=Interior.CLENT;
            writeClent.iniConnet("192.168.120.158", 4000);
            return writeClent;
        }
        /**读取对象*/
        private static MelsenMcClent getReadClent(){
    
    
            MelsenMcClent readClent=Interior.CLENT;
            readClent.iniConnet("192.168.120.158", 4001);
            return readClent;
        }
    }

    /**
     * 返回连接工具对象(因为我这边需要读取写入分开,所以设置为两个,可以不设置)
     * @param state 读取/写入状态
     * @return MelsenMcClent
     */
    public static MelsenMcClent getConnect(String state){
    
    
        return Interior.getConnect(state);
    }

### The specific code for calling reading and writing is as follows.
Because I am not connected to the PLC locally, I will not paste the output results of the log. You can use the following software for testing.
Insert image description here

Test with software

1. Write value:

Insert image description here

2. Read value

the value just written
Insert image description here

  • The name of the software is HslCommunication. You can download it directly from its official website. The specific page is as follows. Select the PLC model, then enter the IP and port to connect and test.
    Insert image description here

Guess you like

Origin blog.csdn.net/weixin_52315708/article/details/131536639