Java 与 西门子PLC通信

 

package com.siemens.simatic;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

/***
 * SIMATIC S7-200 SMART CPU SR60
 * 西门子PLC通信案例
 * 
 * @author 何智潮
 * 微信: QQ11527773
 * 邮箱: [email protected]
 *
 */
public class SimaticClient {

    protected final byte[] header = { 0x03, 0x00, 0x00, 0x16, 0x11, (byte) 0xE0, 0x00, 0x00, 0x00, 0x01, 0x00, (byte) 0xC1, 0x02, 0x01, 0x00, (byte) 0xC2, 0x02, 0x01, 0x01, (byte) 0xC0, 0x01, 0x09 };
    protected final byte[] header2 = { 0x03, 0x00, 0x00, 0x19, 0x02, (byte) 0xF0, (byte) 0x80, 0x32, 0x01, 0x00, 0x00, (byte) 0xCC, (byte) 0xC1, 0x00, 0x08, 0x00, 0x00, (byte) 0xF0, 0x00, 0x00, 0x01, 0x00, 0x01, 0x03, (byte) 0xC0 };

    protected final byte[] READ = { 0x03, 0x00, 0x00, 0x1F, 0x02, (byte) 0xF0, (byte) 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x00, 0x04, 0x01, 0x12, 0x0A, 0x10, 0x02, 0x00, 0x03, 0x00, 0x01, (byte) 0x84, 0x00, 0x00,
            0x08 };
    protected final byte[] WRITE = { 0x03, 0x00, 0x00, 0x24, 0x02, (byte) 0xF0, (byte) 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x05, 0x05, 0x01, 0x12, 0x0A, 0x10, 0x02, 0x00, 0x01, 0x00, 0x01, (byte) 0x84, 0x00, 0x00,
            0x50, 0x00, 0x04, 0x00, 0x08 };// length=35

    protected String host = "192.168.31.253";
    protected int port = 102;

    protected Socket socket;
    protected InputStream inputStream;
    protected OutputStream outputStream;

    public SimaticClient(String host, int port) {
        super();
        this.host = host;
        this.port = port;
    }

    protected void connect() {
        try {
            if (socket != null && socket.isConnected())
                return;
            socket = new Socket(host, port);
            outputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
            inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
            send(header);
            send(header2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /***
     * 发送报文
     * 
     * @param messages
     *            报文
     * @return 返回响应的结果
     */
    public byte[] send(byte[] messages) {
        connect();
        byte[] result = null;
        try {
            outputStream.write(messages);
            outputStream.flush();
            byte[] first = new byte[4];
            int size = 0;
            int count = -1;
            byte[] b = new byte[1];
            while (true) {
                count++;
                if (size > 4 && count >= size)
                    break;
                if (inputStream.read(b) == -1)
                    break;
                if (count < 4)
                    first[count] = b[0];
                if (count == 3) {
                    size = ((0 | first[2]) << 8) | first[3];
                    result = new byte[size];
                    result[0] = first[0];
                    result[1] = first[1];
                    result[2] = first[2];
                    result[3] = first[3];
                }
                if (count > 3) {
                    if (result != null && result.length > count)
                        result[count] = b[0];
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    private byte[] readNative(int first, int count) {
        if (count > 102)
            System.out.println("SimaticClient.read(): count不能大于102  !!!!!");
        int value = 0;

        // 起始位置:
        byte[] posistion = new byte[3];
        value = first * 8;
        posistion[0] = (byte) ((value << 8) >> 24);
        value = first * 8;
        posistion[1] = (byte) ((value << 16) >> 24);
        value = first * 8;
        posistion[2] = (byte) ((value << 24) >> 24);
        READ[28] = posistion[0];
        READ[29] = posistion[1];
        READ[30] = posistion[2];

        // 读取数量:
        byte[] length = new byte[2];
        value = count;
        length[0] = (byte) ((value << 16) >> 24);
        value = count;
        length[1] = (byte) ((value << 24) >> 24);
        READ[23] = length[0];
        READ[24] = length[1];

        byte[] result = send(READ);
        return result;

    }

    /***
     * 读取VB区的数据
     * 
     * @param first
     *            起始字节
     * @param count
     *            返回的字节数量
     * @return 返回目标数据
     */
    public byte[] read(int first, int count) {
        int origin = 25;
        byte[] nativeResult = readNative(first, count);
        int size = nativeResult.length - origin;
        byte[] result = new byte[size];
        for (int i = 0; i < size; i++) {
            result[i] = nativeResult[i + origin];
        }
        return result;
    }

    /***
     * 向VB区写入数据
     * 
     * @param first
     *            起始字节
     * @param values
     *            要写入的数据
     * @return 返回PLC响应的信息
     */
    public byte[] write(int first, byte[] values) {
        if (values == null)
            return null;

        int origin = WRITE.length;// 报文基本长度
        int length = origin + values.length;
        byte[] messages = new byte[length];
        for (int i = 0; i < length; i++) {
            if (i < origin)
                messages[i] = WRITE[i];
            else
                messages[i] = values[i - origin];
        }

        int value = 0;// 临时操作值

        // 【2】【3】报文长度:
        value = length;
        messages[2] = (byte) ((value << 16) >> 24);
        value = length;
        messages[3] = (byte) ((value << 24) >> 24);

        // 【15】【16】写入长度:
        value = values.length + 4;
        messages[15] = (byte) ((value << 16) >> 24);
        value = values.length + 4;
        messages[16] = (byte) ((value << 24) >> 24);

        // 【23】【24】写入的数据个数:
        value = values.length;
        messages[23] = (byte) ((value << 16) >> 24);
        value = values.length;
        messages[24] = (byte) ((value << 24) >> 24);

        // 【28】【29】【30】偏移量(起始位置):
        value = first * 8;
        messages[28] = (byte) ((value << 8) >> 24);
        value = first * 8;
        messages[29] = (byte) ((value << 16) >> 24);
        value = first * 8;
        messages[30] = (byte) ((value << 24) >> 24);

        // 位个数:
        value = 8 * values.length;
        messages[33] = (byte) ((value << 16) >> 24);
        value = 8 * values.length;
        messages[34] = (byte) ((value << 24) >> 24);

        byte[] result = send(messages);
        return result;

    }

    /***
     * 打印数据
     * 
     * @param title
     *            标题
     * @param messages
     *            要打印的数据
     */
    public static void print(String title, byte[] messages) {
        if (messages == null) {
            System.out.println("\n SimaticClient.class: 无结果可打印 ");
            return;
        }
        System.out.println("\n" + title);
        // System.out.println("\n 编号:");
        for (int i = 0; i < messages.length; i++) {
            System.out.print("    " + i);
        }
        System.out.println();
        // System.out.println("\n 10 进制:");
        for (byte m : messages) {
            System.out.print("    " + (m & 0xFF));
        }
        System.out.println();
        // System.out.println("\n 16 进制:");
        for (byte m : messages) {
            System.out.print("    " + Integer.toHexString(m & 0xFF).toUpperCase());
        }
        System.out.println("\n");
    }

}
 

 

 

 

 

package com.siemens.simatic;

public class Demo {

    public static void main(String[] args) {
        try {
            
            SimaticClient client = new SimaticClient("192.168.31.253", 102);
            
            int count = 16;
            byte[] values = createValues(1, count);
            
            // client.send(messages); // 发送自定义报文
            
            client.write(0, values); // 从VB0 开始写入 values            
            byte[] result =client.read(0, count);   // 从VB0 开始读取 count个数据
            
            //打印:第一行为下标,第二行以10进制显示结果,第三行以16进制显示结果
            SimaticClient.print("返回读取VB区的数据【25】起:", result);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //生成简单的测试数据:
    public static byte[] createValues(int min, int count) {
        byte[] values = new byte[count];
        for (int i = 0; i < count; i++) {
            values[i] = (byte) (i + min);// 注意:大于127时,数据溢出错误
        }
        return values;
    }
    
    
}
 

你可能感兴趣的:(Java 与 西门子PLC通信)