1.下载与安装

Snap7 是一个开源的、跨平台的通信库,专门用于与西门子 S7 系列 PLC(可编程逻辑控制器)进行以太网通信。

官网:https://snap7.sourceforge.net/

选择下载:

下载此版本:

解压后的文件:

进入rich-demos:

选择对应版本,这里选择64位的windows

进入bin目录:

这里有4个文件

  • serverdemo.exe
    • 功能:这是一个PLC 模拟器,扮演着“服务器”的角色。启动它之后,电脑就会模拟成一台真实的西门子 PLC。其他程序(比如你写的 Java 代码或 clientdemo.exe)就可以像连接真实 PLC 一样连接到它,进行读写数据操作。这是在没有硬件时进行软件开发和调试的关键工具。
  • clientdemo.exe
    • 功能:这是一个通信测试客户端,扮演着“客户端”的角色。可以用它来连接 serverdemo.exe 模拟的 PLC,或者连接网络中真实的 PLC。它提供了一个图形界面,可以方便地测试读写数据块(DB)、输入(I)、输出(Q)、位存储区(M)等功能,验证通信是否正常。
  • snap7.dll
    • 功能:这是 Snap7 库的核心动态链接库。它是所有通信功能的实际执行者。无论是 serverdemo.execlientdemo.exe,还是你用 Java、C#、Python 等语言编写的程序,最终都是通过调用这个 .dll 文件里的函数来实现与 PLC 的数据交换。
  • PartnerDemo.exe
    • 功能:这是一个用于演示 Snap7 Partner 功能的程序。Partner 是一种更高级的通信模式,允许两个设备之间进行对等通信。

这里我需要使用java程序和服务端进行通信,所以只需要启动服务端。

双击启动:
 

查看数据块:

DB 1 的数据视图,左侧的 00000010 等代表字节偏移量,右侧的 00 代表当前存储的十六进制数据。最右边的.....是ASCII码。

数据块里的数据全部为0,不支持手动修改,只能在程序里写入修改。

2.基本使用

2.1.s7connector工具类

s7connector 是一个专门为 Java 开发者设计的开源库,它的核心作用是让你的 Java 程序能够直接与西门子 S7 系列 PLC 进行通信。

你可以把它理解成一个“翻译官”或“桥梁”,它屏蔽了底层复杂的工业通信协议(S7 协议),无需关心繁琐的字节流和握手过程,只需调用简单的 Java 方法,就能轻松实现对 PLC 数据的读写。

核心作用与优势

  • 简化开发:它封装了所有底层协议细节,如连接建立、数据打包/解包、错误处理等。你只需要关注业务逻辑,比如“从 DB1 的第 20 个字节读取 10 个字节的数据”,而不用去研究 S7 协议的具体报文格式。
  • 跨平台与免授权:与西门子官方的解决方案(如 SIMATIC NET 或 OPC UA Server)不同,s7connector 是一个纯 Java 库。这意味着你的程序可以在 Windows、Linux 等任何支持 Java 的系统上运行,并且完全免费,无需购买昂贵的软件授权。
  • 底层通信基础:它底层依赖于我们之前讨论的 Snap7 库(通过 Java Native Interface 调用 snap7.dll 或其他平台的库文件)来实现真正的网络通信。s7connector 在此基础上,为 Java 开发者提供了更友好、更面向对象的 API。

主要功能

通过 s7connector,你的 Java 程序可以实现以下功能:

  1. 建立连接:通过 IP 地址、机架号和插槽号连接到 S7-200/300/400/1200/1500 等全系列 PLC。
  2. 读取数据:从 PLC 的指定区域(如数据块 DB、输入 I、输出 Q、位存储区 M)读取原始字节数据。
  3. 写入数据:向 PLC 的指定区域写入字节数据,从而控制设备或修改参数。
  4. 数据转换:提供工具类,方便地将读取到的原始字节转换成 Java 中的基本数据类型(如 int, float, boolean)或字符串。

总而言之,s7connector 让你能够用熟悉的 Java 语言,以最少的代码量,快速开发出稳定可靠的工业数据采集和控制应用。

引入依赖:

        <dependency>
            <groupId>com.github.s7connector</groupId>
            <artifactId>s7connector</artifactId>
            <version>2.1</version>
        </dependency>

2.2.建立连接

    /**
     * 初始化PLC连接
     */
    public static S7Connector initConnect(){
        //PLC地址
        String ipAddress = "127.0.0.1";
        //默认端口
        int port = 102;
        S7Connector s7Connector =  S7ConnectorFactory
                .buildTCPConnector()
                .withHost(ipAddress)
                .withPort(port)
                .withTimeout(10000) //连接超时时间
                .withRack(0)
                .withSlot(1)
                .build();
        return s7Connector;

    }

withRack(0) .withSlot(1):

  • 这是西门子 PLC 寻址的关键参数,代表 CPU 在机架上的物理位置。
  • Rack 0, Slot 1: 这是 S7-1200 / S7-1500 系列 PLC 的典型配置。
  • 如果是 S7-300/400,Slot 通常可能是 2 或 3,具体取决于硬件组态。

首先启动服务端:

下面有启动的日志。

测试代码:

        S7Connector s7Connector = S7ConnectorUtil.initConnect();
        System.err.println(s7Connector);

服务端日志区域:

日志逐行解析

  1. 2026-04-22 10:44:41 Server started
    • 含义:服务端(Snap7 Server)已启动。
    • 状态:服务端正在监听端口(默认 102),等待客户端连接。
  1. 2026-04-22 10:45:27 [127.0.0.1] Client added
    • 含义:检测到一个来自 127.0.0.1(本机)的客户端连接请求,并已接受。
    • 对应代码:这正是你的 Java 代码执行到 .build() 时,底层 Snap7 库向服务端发起 TCP 连接的时刻。
  1. 2026-04-22 10:45:27 [127.0.0.1] The client requires a PDU size of 960 bytes
    • 含义:客户端(你的 Java 程序)告诉服务端:“我最大能接收 960 字节 的数据包(PDU)。”
    • 解释:PDU 是通信中单次传输的最大数据单元。S7 协议在连接建立时会协商这个大小。960 是 S7-1200/1500 常见的默认值。这说明握手协议正在正常进行。
  1. 2026-04-22 10:45:28 [127.0.0.1] Client disconnected by peer
    • 含义:客户端(你的 Java 程序)主动断开了连接。
    • 关键点by peer 意味着是对方(你的 Java 代码) 挂断了电话,而不是服务端踢掉的。

2.3.写入数据

格式:

// 方法签名大致如下:
s7Connector.write(Area, DBNumber, StartByte, data);
  1. DaveArea.DB —— 存储区域
    • 含义:指定要写入 PLC 的哪个内存区域。
    • 常用选项
      • DaveArea.DB数据块(最常用)。
      • DaveArea.MK位存储区
      • DaveArea.PE输入区
      • DaveArea.PA输出区
      • DaveArea.TM定时器
      • DaveArea.CT计数器
  1. 1 —— DB 块编号
    • 含义:如果第一个参数选了 DaveArea.DB,这里填的就是 DB 块的号码。这里填 1 代表 DB1
  1. 20 —— 起始字节
    • 含义:从该数据块的第几个字节开始写入。
  1. data —— 数据内容
    • 含义:这是一个 byte[] (字节数组)。Snap7 原生接口只能接收字节数组。你不能直接传 intfloat,必须先手动把它们转换成字节数组,否则代码会报错或写入乱码。

因为 data 必须是字节数组,直接写比较麻烦。

写入String类型

比如我要写入“我是中国人”

    public static void writePlcData() {
        S7Connector s7Connector = initConnect();

        try {
            // 1. 准备要写入的数据
            String text = "我是中国人";
            // 将字符串转换为字节数组
            // 注意:通常PLC使用GBK编码来处理中文,这样1个汉字占2个字节
            // 如果使用UTF-8,1个汉字通常占3个字节,可能会导致乱码或长度不够
            byte[] data = text.getBytes("GBK");

            // 2. 执行写入
            // 参数解释:
            // DaveArea.DB -> 区域:数据块
            // 1           -> DB编号:DB1
            // 20          -> 起始位置:从第20个字节开始写 (对应截图的 0010)
            // data        -> 数据内容:转换后的字节数组
            s7Connector.write(DaveArea.DB, 1, 20, data);

            System.out.println("写入成功!写入长度:" + data.length + " 字节");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                s7Connector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

数据块:

之所以写在0010的位置:

  1. 地址换算
    • 你的代码写的是十进制 20
    • 十进制 20 转换为十六进制是 14(即 0x14)。
  1. 界面布局
    • 0010 :代表地址范围 0x10 (16) 到 0x1F (31)。
    • 0020 :代表地址范围 0x20 (32) 到 0x2F (47)。
  1. 结论
    • 你要写入的起始地址是 0x14
    • 0x14 位于 0x100x1F 之间,所以它必须显示在 0010 这一行。

看日志:

日志中 Write request, Area : DB1, Start : 20, Size : 10 --> OK 的含义如下:

  • Write request:这是一个写入操作的请求。
  • Area : DB1:目标区域是数据块 1。
  • Start : 20:起始地址是第 20 个字节(十进制)。
  • Size : 10:写入的数据长度是 10 个字节。
  • --> OK:操作成功。

写入int类型

假如要存储100的数字到DB1里,也就是64,但是这里不能直接把100转换为字节数组直接写入,因为计算机在存储多字节数据(如 int)时,需要决定是先存高位还是先存低位。

在 Java 中,一个 int 类型占用 4 个字节(32位),而在 S7 PLC 中,一个 INT 类型(如你代码中的 100)通常占用 2 个字节(16位)。

假设 int myValue = 100,它的二进制是 00000000 00000000 00000000 01100100

如果你使用 Java 的标准方法(如 ByteBuffer)直接转换,默认是 大端模式(Big-Endian),结果是 4 个字节:
[00] [00] [00] [64](十六进制,每个【】是一个字节)

问题在于:

  1. 长度不对:PLC 的 INT 只需要 2 个字节,你传 4 个字节会覆盖掉后面相邻的变量。
  2. 数值不对:如果你截取后两个字节 [00] [64],这在 PLC 里是 100。但如果你截取前两个字节 [00] [00],那就是 0

所以在转换为字节数组的时候需要进行位运算。

    public static void writePlcData() {
        S7Connector s7Connector = initConnect();
        try {
            // 1. 准备数据
            int myValue = 100;
            // 2. 手动将 int 转为 byte[] (高位在前)
            // 在创建字节数组的同时初始化参数
            // 第一个参数是将32位的二进制数据右移低8位挤出去,结果为0
            // 第二个当你把一个占用空间大的类型(如 4 字节的 int)强制转换成一个占用空间小的类型(如 1 字节的 byte)时
            // 只保留原始数据的低 8 位(也就是最右边的 8 位)。
            byte[] data = new byte[]{
                    (byte) (myValue >> 8),
                    (byte) myValue
            };
            
            s7Connector.write(DaveArea.DB, 1, 1, data);

            System.out.println("写入成功!写入长度:" + data.length + " 字节");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                s7Connector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

结果:

2.4..读取数据

格式:

// 方法签名大致如下:
s7Connector.write(Area, DBNumber, readNumber,StartByte)

读取字符串

比如读取我是中国人:

    /**
     * 读取PLC中的数据,字符串类型
     **/
    public static void readPlcData() throws UnsupportedEncodingException {

        S7Connector s7Connector = initConnect();
        // 这四个参数共同定义了一次“读取操作”的完整指令,它们告诉连接器:去哪里、拿什么、拿多少、从哪开始。
        byte[] barcodeByte = s7Connector.read(DaveArea.DB, 1, 10, 20);
        //由于当前PLC地址中保存的数据类型是字符串类型,所以直接将byte[] 转成string即可;
        String barcode = new String(barcodeByte, "GBK");
        System.out.println(barcode);
        try {
            s7Connector.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

因为在写入的时候是从20的位置上写的,所以读取的时候需要从这里读,读取的数量就是你存入数据的字节数。

结果:

读取int类型

    public static void readPlcData() throws UnsupportedEncodingException {

        S7Connector s7Connector = initConnect();
        // 这四个参数共同定义了一次“读取操作”的完整指令,它们告诉连接器:去哪里、拿什么、拿多少、从哪开始。
        byte[] barcodeByte = s7Connector.read(DaveArea.DB, 1, 2, 1);
        int barcode = ((barcodeByte[0] & 0xFF) << 8) | (barcodeByte[1] & 0xFF);
        try {
            s7Connector.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

结果是100

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐