C#项目连接S7-PLCSIM Advanced读写操作

一.设置

1.S7-PLCSIM Advanced V5.0 配置

1.1S7-PLCSIM Advanced 配置

2.设置 PG/PC 接口

在西门子 PLC 编程或仿真时,设置 PG/PC 接口是确保电脑与 PLC(或仿真器)正常通信

  1. 打开 Windows 控制面板 (可通过 Win+R 输入control快速打开)。
  2. 切换到 "小图标" 视图,找到并点击 "Set PG/PC Interface"(西门子专用设置,安装 TIA Portal 或 PLCSIM 后会出现)。
  1. Siemens PLCSIM Virtual Ethernet Adapter.TCPIP.1

    • 基于TCP/IP 协议 的虚拟接口,支持标准 S7 协议(端口 102),是连接 PLCSIM 仿真 PLC(如 S7-1200/1500)的首选接口,兼容性好,支持 PUT/GET 通信。
  2. Siemens PLCSIM Virtual Ethernet Adapter.TCPIP.Auto.1

    • 自动适配的 TCP/IP 虚拟接口,会尝试自动匹配通信参数,适合新手或不确定具体配置的场景,但稳定性略逊于TCPIP.1
  3. Siemens PLCSIM Virtual Ethernet Adapter. ISO.1,但 S7-1200/1500 通常无需此接口

3.配置网络

选择接口后,点击 "属性" 按钮,确认以下设置:

  1. IP 地址 :确保虚拟网卡的 IP 与仿真 PLC 在同一网段(如 PLC 为192.168.1.25,虚拟网卡可设为192.168.1.10)。
  2. 子网掩码 :统一设为 255.255.255.0
  3. 其他参数:保持默认(无需修改网关、DNS 等)

2.PLC的配置

2.1修改IP

2.2 允许 PUT/GET 通信访问

  1. 在设备组态界面中,选中左侧机架上的PLC(如 S7-1500 CPU)
  2. 在右侧 "属性" 面板中,找到 **"常规" "防护与安全""连接机制"**。
  3. 勾选 **"允许来自远程伙伴的 PUT/GET 通信访问"**(该选项用于开启外部设备的读写权限)。

2.3 启用 "块编译过程中支持仿真" 选项

  1. 在 TIA Portal 项目树中,右键点击项目名称(如 "CPSim"),选择 **"属性"**。
  2. 在弹出的属性窗口中,选择 **"PLC 保护和优化"** 选项卡。
  3. 勾选 **"块编译过程中支持仿真"**(需确保该选项在项目属性的 "PLC 保护和优化" 中可见,不同版本界面可能略有差异)。
  4. 点击 **"确定"** 保存设置。

3.VisionStudio 中添加 S7NetPlus 管理

3.1 使用 NuGet 包管理器控制台

  1. 打开 Visual Studio,点击顶部菜单「工具 」→「NuGet 包管理器 」→「程序包管理器控制台」。

  2. 在控制台中输入以下命令并回车:

    复制代码
    Install-Package S7NetPlus

二.代码

  • I 区(输入)I[字节].[位](如 I0.0),通常为只读
  • Q 区(输出)Q[字节].[位](如 Q0.0),可读写
  • V 区(变量存储) :字节V[字节]、字VW[字节](16 位)、双字VD[字节](32 位)
  • W 区(临时工作存储) :位W[字节].[位]、字WW[字节]、双字WD[字节]
  • DW 区(双字)DW[字节](32 位,部分 PLC 中为通用数据区)
  • R 区(过程映像) :位R[字节].[位]、双字RD[字节](32 位)
  1. 注意事项

    • I 区:输入区通常由外部信号控制,写入可能失败(取决于 PLC 型号)
    • W 区:临时变量区,仅在 PLC 程序执行时有效,不保存数据
    • 兼容性:部分区域(如 V 区)主要用于 S7-200/200SMART,S7-1200/1500 更常用 DB 区和 M 区
    • 权限:确保 PLC 已开启 "允许 PUT/GET 通信"(见之前的配置步骤)
  2. 数据类型对应

    • 位(bool):I0.0Q0.0
    • 字节(byte):V0R0
    • 字(16 位整数):VW2WW2
    • 双字(32 位整数):VD4RD4
cs 复制代码
using System;
using S7.Net;

class PlcMemoryAccess
{
    static void Main(string[] args)
    {
        // 配置PLC连接参数(根据实际情况修改)
        string plcIp = "192.168.1.25";
        int rack = 0;
        int slot = 1; // S7-1500默认槽号为1,S7-1200通常为0

        Plc plc = new Plc(CpuType.S71500, plcIp, rack, slot);

        try
        {
            Console.WriteLine("连接PLC中...");
            plc.Open();

            if (plc.IsConnected)
            {
                Console.WriteLine("PLC连接成功!\n");

                // 1. 读写输入区(I点):数字量输入,通常为只读
                bool i0_0 = (bool)plc.Read("I0.0"); // 读取I0.0
                Console.WriteLine($"I0.0 原始值: {i0_0}");
                // 注意:I区为输入区,通常不建议写入,部分PLC可能禁止写入
                // plc.Write("I0.0", true); // 多数情况下会失败


                // 2. 读写输出区(Q点):数字量输出
                bool q0_0 = (bool)plc.Read("Q0.0"); // 读取Q0.0
                Console.WriteLine($"Q0.0 原始值: {q0_0}");
                plc.Write("Q0.0", !q0_0); // 翻转Q0.0的值
                Console.WriteLine($"Q0.0 新值: {plc.Read("Q0.0")}\n");


                // 3. 读写变量存储区(V区,S7-200/200SMART常用)
                // 读取V区字节(8位)
                byte v0 = (byte)plc.Read("V0.0", 1); // 读取V0开始的1个字节
                // 读取V区字(16位整数)
                short v2 = (short)plc.Read("VW2"); // 读取VW2(V2.0-V3.7)
                Console.WriteLine($"V0 原始值: {v0}, VW2 原始值: {v2}");
                
                plc.Write("V0.0", (byte)0xAA); // 写入V0字节
                plc.Write("VW2", (short)1234); // 写入VW2字
                Console.WriteLine($"V0 新值: {plc.Read("V0.0", 1)}, VW2 新值: {plc.Read("VW2")}\n");


                // 4. 读写工作存储区(W区,S7-1200/1500的临时变量区)
                // 注意:W区为临时变量,仅在块执行时有效,断电丢失
                bool w0_0 = (bool)plc.Read("W0.0");
                short w2 = (short)plc.Read("WW2");
                Console.WriteLine($"W0.0 原始值: {w0_0}, WW2 原始值: {w2}");
                
                plc.Write("W0.0", true);
                plc.Write("WW2", (short)5678);
                Console.WriteLine($"W0.0 新值: {plc.Read("W0.0")}, WW2 新值: {plc.Read("WW2")}\n");


                // 5. 读写数据字(DW区,通常指双字32位,不同PLC定义可能不同)
                int dw4 = (int)plc.Read("DW4"); // 读取DW4(32位整数)
                Console.WriteLine($"DW4 原始值: {dw4}");
                plc.Write("DW4", 123456); // 写入32位整数
                Console.WriteLine($"DW4 新值: {plc.Read("DW4")}\n");


                // 6. 读写过程映像区(R区,S7-1200/1500的过程数据区)
                bool r0_0 = (bool)plc.Read("R0.0");
                int r4 = (int)plc.Read("RD4"); // 读取R区双字(32位)
                Console.WriteLine($"R0.0 原始值: {r0_0}, RD4 原始值: {r4}");
                
                plc.Write("R0.0", true);
                plc.Write("RD4", 98765);
                Console.WriteLine($"R0.0 新值: {plc.Read("R0.0")}, RD4 新值: {plc.Read("RD4")}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"操作失败: {ex.Message}");
        }
        finally
        {
            if (plc.IsConnected)
            {
                plc.Close();
                Console.WriteLine("\nPLC连接已关闭");
            }
        }

        Console.WriteLine("按任意键退出...");
        Console.ReadKey();
    }
}
python 复制代码
import snap7
from snap7.util import *
import time

class PlcCommunication:
    def __init__(self, ip, rack=0, slot=1):
        self.plc = snap7.client.Client()
        self.ip = ip
        self.rack = rack
        self.slot = slot
        self.connected = False

    def connect(self):
        """连接到PLC"""
        try:
            self.plc.connect(self.ip, self.rack, self.slot)
            self.connected = True
            print(f"成功连接到PLC: {self.ip}")
            return True
        except Exception as e:
            print(f"连接PLC失败: {str(e)}")
            self.connected = False
            return False

    def disconnect(self):
        """断开与PLC的连接"""
        if self.connected:
            self.plc.disconnect()
            self.connected = False
            print("已断开与PLC的连接")

    def read_write_i_area(self):
        """读写输入区(I点)- 通常为只读"""
        if not self.connected:
            print("未连接到PLC")
            return

        try:
            # 读取I区:读取从字节0开始的1个字节(包含I0.0-I0.7)
            data = self.plc.read_area(snap7.client.Areas.PE, 0, 0, 1)
            i0_0 = get_bool(data, 0, 0)  # 获取I0.0的值
            print(f"I0.0 原始值: {i0_0}")

            # 注意:I区为输入区,通常不建议写入,多数PLC会禁止写入
            # 以下代码可能失败,仅作示例
            try:
                set_bool(data, 0, 0, True)  # 尝试设置I0.0为True
                self.plc.write_area(snap7.client.Areas.PE, 0, 0, data)
                print("尝试写入I0.0为True(可能失败)")
            except Exception as e:
                print(f"写入I区失败: {str(e)}")

        except Exception as e:
            print(f"操作I区出错: {str(e)}")

    def read_write_q_area(self):
        """读写输出区(Q点)"""
        if not self.connected:
            print("未连接到PLC")
            return

        try:
            # 读取Q区:读取从字节0开始的1个字节(包含Q0.0-Q0.7)
            data = self.plc.read_area(snap7.client.Areas.PA, 0, 0, 1)
            q0_0 = get_bool(data, 0, 0)  # 获取Q0.0的值
            print(f"Q0.0 原始值: {q0_0}")

            # 写入Q0.0:翻转当前值
            new_value = not q0_0
            set_bool(data, 0, 0, new_value)
            self.plc.write_area(snap7.client.Areas.PA, 0, 0, data)
            
            # 验证写入结果
            data = self.plc.read_area(snap7.client.Areas.PA, 0, 0, 1)
            print(f"Q0.0 新值: {get_bool(data, 0, 0)}")

        except Exception as e:
            print(f"操作Q区出错: {str(e)}")

    def read_write_v_area(self):
        """读写变量存储区(V区)- S7-200/200SMART常用"""
        if not self.connected:
            print("未连接到PLC")
            return

        try:
            # 读取V区:字节(V0)和字(VW2)
            # 读取从V0开始的4个字节(V0-V3)
            data = self.plc.read_area(snap7.client.Areas.MK, 0, 0, 4)
            
            v0 = data[0]  # V0字节值
            vw2 = get_int(data, 2)  # VW2(V2-V3)的16位整数
            print(f"V0 原始值: {v0}, VW2 原始值: {vw2}")

            # 写入V区
            data[0] = 0xAA  # 写入V0字节
            set_int(data, 2, 1234)  # 写入VW2字
            self.plc.write_area(snap7.client.Areas.MK, 0, 0, data)
            
            # 验证写入结果
            data = self.plc.read_area(snap7.client.Areas.MK, 0, 0, 4)
            print(f"V0 新值: {data[0]}, VW2 新值: {get_int(data, 2)}")

        except Exception as e:
            print(f"操作V区出错: {str(e)}")

    def read_write_r_area(self):
        """读写过程映像区(R区)- S7-1200/1500常用"""
        if not self.connected:
            print("未连接到PLC")
            return

        try:
            # 读取R区:位(R0.0)和双字(RD4)
            data = self.plc.read_area(snap7.client.Areas.DB, 0, 4, 4)  # 读取RD4开始的4字节
            
            # 读取R0.0(需要先读取R0所在的字节)
            r0_data = self.plc.read_area(snap7.client.Areas.DB, 0, 0, 1)
            r0_0 = get_bool(r0_data, 0, 0)
            
            rd4 = get_dword(data, 0)  # RD4的32位整数
            print(f"R0.0 原始值: {r0_0}, RD4 原始值: {rd4}")

            # 写入R区
            set_bool(r0_data, 0, 0, True)  # 设置R0.0为True
            self.plc.write_area(snap7.client.Areas.DB, 0, 0, r0_data)
            
            set_dword(data, 0, 98765)  # 设置RD4为98765
            self.plc.write_area(snap7.client.Areas.DB, 0, 4, data)
            
            # 验证写入结果
            r0_data = self.plc.read_area(snap7.client.Areas.DB, 0, 0, 1)
            data = self.plc.read_area(snap7.client.Areas.DB, 0, 4, 4)
            print(f"R0.0 新值: {get_bool(r0_data, 0, 0)}, RD4 新值: {get_dword(data, 0)}")

        except Exception as e:
            print(f"操作R区出错: {str(e)}")

    def read_write_memory_areas(self):
        """批量测试各存储区的读写操作"""
        print("\n=== 测试I区 ===")
        self.read_write_i_area()
        
        print("\n=== 测试Q区 ===")
        self.read_write_q_area()
        
        print("\n=== 测试V区 ===")
        self.read_write_v_area()
        
        print("\n=== 测试R区 ===")
        self.read_write_r_area()

if __name__ == "__main__":
    # 配置PLC连接参数(根据实际情况修改)
    PLC_IP = "192.168.1.25"
    RACK = 0
    SLOT = 1  # S7-1500默认槽号为1,S7-1200通常为0

    plc_comm = PlcCommunication(PLC_IP, RACK, SLOT)
    
    if plc_comm.connect():
        plc_comm.read_write_memory_areas()
        plc_comm.disconnect()
    
相关推荐
不太会写4 小时前
又开始了 小程序定制
vue.js·spring boot·python·小程序
让我上个超影吧4 小时前
深入浅出 Java 中的 CompletableFuture:让异步编程变得简单
java·开发语言
聊聊MES那点事4 小时前
Cogent DataHub vs Kepware,两大工业数据中间件的深度对比分析
开发语言·中间件·opc·opc ua
好家伙VCC5 小时前
**发散创新:探索群体智能编程中的新境界**随着科技的飞速发展,群体智能逐渐成为编程领域的一大研究热点。本文将深入探讨群体智能的概念、优
java·python·科技
“抚琴”的人5 小时前
C#中获取程序执行时间
服务器·前端·c#
aramae5 小时前
数据结构与算法(递归)
开发语言·经验分享·笔记·算法
千码君20165 小时前
Go语言:记录一下Go语言系统学习的第一天
java·开发语言·学习·golang·gin·并发编程·编译语言
TwoAnts&DingJoy5 小时前
数据分析-泊松分布
python·机器学习·数据挖掘·数据分析·统计学·泊松分布