C# 上位机连西门子 S7-1200/1500,绕来绕去就三条路:走 S7 协议(Sharp7 / S7.Net 这类开源库)、走 PLC 自带的 OPC UA Server、走西门子官方 .NET 通信库。选型一句话:点位少、要快、不想花钱,用 S7 协议;车间里不止西门子一种 PLC、或者要跨网段跨防火墙,用 OPC UA;预算充足又想要官方兜底,上官方库。真正让新手卡住的是前两条路上的两个开关——PUT/GET 和"优化的块访问",这篇把坑位和代码一起交代清楚。

三条路各是什么脾气?先看这张对比

路线 A · 最常用 S7 协议(Sharp7 / S7.Net)

直接说 S7comm 协议,读写 DB 区、I/Q/M 区,一个 TCP 连接(102 端口)搞定。开源免费,读写延迟毫秒级,是定制上位机的默认选择。

免费毫秒级仅限西门子需开PUT/GET
路线 B · 最通用 OPC UA Server

1200/1500 固件里自带 OPC UA 服务器,变量在博图里导出成节点。协议开放,以后换 AB、三菱也能一套代码吃下来,还带证书加密。

跨品牌自带加密配置略重1200需V4.4+
路线 C · 最省心 西门子官方通信库

SIMATIC S7 Communication Library for .NET,官方维护、有技术支持,但按站点授权收费,且绑定西门子生态,小项目性价比不高。

官方兜底按站收费绑定西门子
对比项S7 协议OPC UA官方库
费用0(开源)0(固件自带)按站点授权
单次读延迟2~8 ms(同网段)10~30 ms(订阅模式更低)与 S7 协议相当
跨品牌能力无,只认西门子强,协议国际标准
PLC 侧前置条件勾选 PUT/GET、关优化块访问激活 OPC UA 服务器、配证书同 S7 协议
适合场景定制上位机、产线专机多品牌车间、MES 对接甲方点名要官方支持

▲ 我们近两年的项目里,八成走路线 A,两成走路线 B。路线 B 越来越多是因为甲方 MES 团队想直接订阅变量,不想让上位机当二传手。

为什么连上了却读不到数?两个开关先查

说实话,S7-1200 项目一半的"通信故障"根本不是通信问题,是博图里两个默认设置在拦你。第一次去现场,程序连上了、读 DB 却报错,排查半天最后发现是这两个地方:

开关一:PUT/GET 访问没勾

博图 → 设备组态 → CPU 属性 → 防护与安全 → 连接机制,勾选 允许来自远程对象的 PUT/GET 通信。不勾,第三方客户端一律吃闭门羹。1500 同理,且 1500 还有访问级别密码,通信库要填对密码等级。

开关二:数据块勾了"优化的块访问"

博图里新建 DB 默认勾选 优化的块访问,此时变量没有绝对偏移地址,只有符号,S7 协议按地址读直接失败。给上位机用的 DB,右键属性里把这个勾去掉,让每个变量露出 DB1.DBW0 这种偏移地址。

这两个设置改完都要重新下载并重启 PLC 才生效——现场经常有人改了没下载,白忙一场。另外 1500 的 DB 若开了"仅符号访问",效果和优化块一样,第三方库读不了,一并关掉。

Sharp7 还是 S7.Net?连接与读写代码长这样

两个库我们都大量用过:Sharp7 轻、无依赖、一个 cs 文件就能塞进项目;S7.Net 的 API 更顺手,支持异步,类型转换帮你做了。小工具选 Sharp7,正经上位机选 S7.Net。连接和读写的骨架代码:

// S7.Net 方式(NuGet: S7netplus)
var plc = new Plc(CpuType.S71200, "192.168.0.10", 0, 1); // 机架0 槽1
if (plc.Open() != ErrorCode.NoError)
    throw new IOException($"连接失败: {plc.Open()}");

// 读:DB1 偏移0处的 float、DB1.DBW10 的 short、M0.0 的 bool
float  temp  = (float)plc.Read("DB1.DBD0");
short  count = (short)plc.Read("DB1.DBW10");
bool   run   = (bool)plc.Read("M0.0");

// 写:启动命令位
plc.Write("DB1.DBX12.0", true);

// Sharp7 方式:一个类文件,手动管缓冲区
var cli = new S7Client();
int err = cli.ConnectTo("192.168.0.10", 0, 1);
byte[] buf = new byte[4];
cli.DBRead(1, 0, 4, buf);               // DB1 偏移0 读4字节
float v = S7.GetFloatAt(buf, 0);        // 手动转 float
地址写法的一个坑:博图里看到的 DB1.DBD0 是"字节偏移",不是"寄存器号"。有人拿 Modbus 的习惯来套,写出一堆 ÷2 的地址,读出来的数全对不上。S7 协议里 DBD0、DBD4 就是挨着排的字节偏移,float 占 4 字节、word 占 2 字节,照着偏移顺着排就行。

轮询 200 个点卡成 PPT?批量读与重连是必修课

S7 协议一次 PDU 能带的数据量有限(1200 协商下来通常 240 字节左右),200 个点如果一个个读,就是 200 次 TCP 往返,轮询一圈秒级起步。做法很简单:把地址连续的点合并成段,一段一笔读。比如 DB1 里 0~199 字节全是采集数据,一笔 DBRead(1, 0, 200) 全拿回来,再在内存里按偏移解析,200 个点一笔解决。我们有个昆山的项目,合并前后轮询周期从 3.2 秒掉到 90 毫秒,就这一招。

再就是断线重连。车间交换机重启、网线被叉车碰掉、PLC 停机下载程序,连接断是常态。S7.Net 的 Plc 对象断了之后 Open 状态不可靠,我们的惯例是:读操作包一层捕获,失败即 Close + 重建对象 + 重连,重连间隔 2 秒起步指数退避,别拿死循环 100ms 重试去轰 PLC。还有一点容易漏:重连成功后第一笔读要丢弃或校验,防止拿到半截缓冲数据。

收尾:去现场前对着这张表过一遍

检查项位置 / 动作
PUT/GETCPU 属性 → 防护与安全 → 勾选,下载重启
优化块访问上位机用的每个 DB → 属性 → 取消勾选,下载重启
IP 与网段工控机与 PLC 同网段,ping 通再谈通信
机架/槽号1200/1500 一律机架 0 槽 1(或 0),别照抄 300 的 0/2
防火墙102 端口放行;OPC UA 走 4840
连接数上限1200 的连接资源有限,上位机 + 触摸屏 + 网关别超限

选型这事其实没有玄学:单一西门子设备、要低延迟、预算紧,就 S7 协议;多品牌、要长期演进,一开始就上 OPC UA。如果你手上正好有个 1200 连不上,先别怀疑代码,去博图里把上面两个开关看一眼——我打赌八成在那。