C#项目连接S7-PLCSIM Advanced读写操作
一.设置
1.S7-PLCSIM Advanced V5.0 配置
1.1S7-PLCSIM Advanced 配置
2.设置 PG/PC 接口
在西门子 PLC 编程或仿真时,设置 PG/PC 接口是确保电脑与 PLC(或仿真器)正常通信
- 打开 Windows 控制面板(可通过 Win+R 输入
control
快速打开)。 - 切换到 “小图标” 视图,找到并点击 “Set PG/PC Interface”(西门子专用设置,安装 TIA Portal 或 PLCSIM 后会出现)。
-
Siemens PLCSIM Virtual Ethernet Adapter.TCPIP.1
- 基于TCP/IP 协议的虚拟接口,支持标准 S7 协议(端口 102),是连接 PLCSIM 仿真 PLC(如 S7-1200/1500)的首选接口,兼容性好,支持 PUT/GET 通信。
-
Siemens PLCSIM Virtual Ethernet Adapter.TCPIP.Auto.1
- 自动适配的 TCP/IP 虚拟接口,会尝试自动匹配通信参数,适合新手或不确定具体配置的场景,但稳定性略逊于
TCPIP.1
。
- 自动适配的 TCP/IP 虚拟接口,会尝试自动匹配通信参数,适合新手或不确定具体配置的场景,但稳定性略逊于
Siemens PLCSIM Virtual Ethernet Adapter.
ISO.1
,但 S7-1200/1500 通常无需此接口
3.配置网络
选择接口后,点击 “属性” 按钮,确认以下设置:
- IP 地址:确保虚拟网卡的 IP 与仿真 PLC 在同一网段(如 PLC 为
192.168.1.25
,虚拟网卡可设为192.168.1.10
)。 - 子网掩码:统一设为
255.255.255.0
。 - 其他参数:保持默认(无需修改网关、DNS 等)
2.PLC的配置
2.1修改IP
2.2 允许 PUT/GET 通信访问
- 在设备组态界面中,选中左侧机架上的PLC(如 S7-1500 CPU)。
- 在右侧 “属性” 面板中,找到 **“常规”→“防护与安全”→“连接机制”**。
- 勾选 **“允许来自远程伙伴的 PUT/GET 通信访问”**(该选项用于开启外部设备的读写权限)。
2.3 启用 “块编译过程中支持仿真” 选项
- 在 TIA Portal 项目树中,右键点击项目名称(如 “CPSim”),选择 **“属性”**。
- 在弹出的属性窗口中,选择 **“PLC 保护和优化”** 选项卡。
- 勾选 **“块编译过程中支持仿真”**(需确保该选项在项目属性的 “PLC 保护和优化” 中可见,不同版本界面可能略有差异)。
- 点击 **“确定”** 保存设置。
3.VisionStudio 中添加 S7NetPlus 管理
3.1 使用 NuGet 包管理器控制台
- 打开 Visual Studio,点击顶部菜单「工具」→「NuGet 包管理器」→「程序包管理器控制台」。
- 在控制台中输入以下命令并回车:
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 位)
-
注意事项:
- I 区:输入区通常由外部信号控制,写入可能失败(取决于 PLC 型号)
- W 区:临时变量区,仅在 PLC 程序执行时有效,不保存数据
- 兼容性:部分区域(如 V 区)主要用于 S7-200/200SMART,S7-1200/1500 更常用 DB 区和 M 区
- 权限:确保 PLC 已开启 "允许 PUT/GET 通信"(见之前的配置步骤)
-
数据类型对应:
- 位(bool):
I0.0
、Q0.0
等 - 字节(byte):
V0
、R0
等 - 字(16 位整数):
VW2
、WW2
等 - 双字(32 位整数):
VD4
、RD4
等
- 位(bool):
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通常为0Plc 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.0Console.WriteLine($"I0.0 原始值: {i0_0}");// 注意:I区为输入区,通常不建议写入,部分PLC可能禁止写入// plc.Write("I0.0", true); // 多数情况下会失败// 2. 读写输出区(Q点):数字量输出bool q0_0 = (bool)plc.Read("Q0.0"); // 读取Q0.0Console.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();}
}
import snap7
from snap7.util import *
import timeclass PlcCommunication:def __init__(self, ip, rack=0, slot=1):self.plc = snap7.client.Client()self.ip = ipself.rack = rackself.slot = slotself.connected = Falsedef connect(self):"""连接到PLC"""try:self.plc.connect(self.ip, self.rack, self.slot)self.connected = Trueprint(f"成功连接到PLC: {self.ip}")return Trueexcept Exception as e:print(f"连接PLC失败: {str(e)}")self.connected = Falsereturn Falsedef disconnect(self):"""断开与PLC的连接"""if self.connected:self.plc.disconnect()self.connected = Falseprint("已断开与PLC的连接")def read_write_i_area(self):"""读写输入区(I点)- 通常为只读"""if not self.connected:print("未连接到PLC")returntry:# 读取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为Trueself.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")returntry:# 读取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_0set_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")returntry:# 读取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")returntry:# 读取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为Trueself.plc.write_area(snap7.client.Areas.DB, 0, 0, r0_data)set_dword(data, 0, 98765) # 设置RD4为98765self.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 = 0SLOT = 1 # S7-1500默认槽号为1,S7-1200通常为0plc_comm = PlcCommunication(PLC_IP, RACK, SLOT)if plc_comm.connect():plc_comm.read_write_memory_areas()plc_comm.disconnect()