ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

S7-300以太网TCP通讯全攻略:从选型到上位机联调实战

S7-300以太网TCP通讯全攻略:从选型到上位机联调实战 简介面向工控上位机开发人员西门子S7-300 PLC与上位机以太网TCP通讯的C#解决方案适用于设备数据采集、产线监控等需要稳定读写PLC寄存器的场景。基于.NET4.0框架模块化设计以类似OPC的Tag标签方式直接读写I、Q、PI、PA、M、DB等寄存器XML配置标签实时刷新内置断线重连机制单机可同时接入至少10路PLC每路读写点数不超过20000点通讯稳定可靠。压缩包共26个文件、约174KB以9个.cs源码文件、XML配置文件、resx资源文件及exe可执行程序为主并附带使用说明docx文档和VS2010测试Demo便于二次开发与快速验证。已有3486人学习下载适合需要快速搭建S7-300以太网通讯或在其基础上扩展功能的中高级工程师。 说实话接到这个项目时第一反应是松了口气——还好不是让 S7-200 走 PPI 转以太网那种绕弯子的方案。S7-300 加以太网 TCP 通讯放在工业现场属于“经典中的经典”老产线上全是 300 站上位机要做数据采集、配方下发、状态监控最稳妥也最通用的路就是走以太网。这篇文章我就把整套方案从选型、原理、PLC 侧配置到上位机代码和联调排障全部过一遍踩过的坑也一并交代清楚适合正要接手这类项目的电气工程师、上位机开发以及想搞懂 PLC 以太网通讯原理的入门朋友。1. 项目背景与技术选型思路1.1 为什么最终走以太网 TCP原来这套设备是传统的 MPI 或者 DP 总线现场值班室看数据靠触摸屏IT 部门要把产量和设备状态拉进 MES发现根本没法接。中间有人提过用串口服务器把 MPI 转成以太网但试下来有两个硬伤一是 MPI 电缆距离和抗干扰都有限二是串口服务器转出来的数据协议比较尴尬上位机还得自己解析一层。所以最后我们定下方案直接用 S7-300 自带的以太网能力走 TCP/IP 协议跟上位机通讯。你可能会问为什么不走 UDP或者为什么不干脆换 Modbus TCP我的回答是S7-300 原生支持的是 S7 协议族跑在 TCP 的 102 端口上这是西门子的标准接口上位机这边只需用现成的通讯库就能对接。虽然 Modbus TCP 在第三方设备里很流行但要让 300 站做 Modbus 从站还得额外配协议模块或者做数据映射属于自己给自己加活。更何况如果将来还要跟康耐视的 Insight 相机、海康的 VisionMaster 这类视觉系统集成大家都是基于以太网 TCP/IP 的起码网络架构层面是统一的省去一堆串口转接的麻烦。1.2 三种通信路径怎么选同一个设备实现上位机和 S7-300 的以太网通讯其实有三条主流路径不需要每条都精通但你得知道怎么选。方案硬件要求PLC侧编程量数据量适用场景CP343-1 FC5/FC6AG_SEND/AG_RECV需要 CP343-1 通讯处理器中等需要调用通讯功能块中等单帧几百字节老 300 站只有 MPI/DP 接口想加以太网集成 PN 口 CPU FB14/FB15PUT/GETCPU 自带 Profinet 口少建好连接后直接读写较小适合变量级读写315-2PN/DP 这类自带 PN 口的 CPU第三方面转网关 Modbus TCP需要额外网关少但要做数据映射较小不想动 PLC 程序只做数据采集的过渡方案实际项目里如果 CPU 自带 PN 口强烈建议直接走 PUT/GETPLC 侧几乎不用写通讯逻辑。但很多在用设备是老 300只有一个 MPI 口那就老老实实加一块 CP343-1用 AG_SEND/AG_RECV 做数据收发。这套方案的好处是数据由 PLC 主动拼帧、主动发送上位机只负责接收和解析逻辑非常清晰。注意网上有人建议通过工业以太网交换机做跨网段路由从技术上讲没问题但现场调试时跨网段会引入路由表、网关、防火墙等一堆变量。我建议除非万不得已上位机网卡和 PLC 保持同一网段能省掉 80% 的“搜不到设备”问题。2. TCP通讯原理与S7协议关键知识点2.1 三次握手与 PLC 连接建立过程很多刚入门的朋友容易卡在这里明明我 ping 得通 PLC为什么上位机连不上原因就是以太网通讯并不只是“网络通”就行TCP 这条连接必须通过三次握手建立起来而且 PLC 这边不是随便任何一个端口都开放着等你连。三次握手通俗说就是客户端先发一个 SYN 包说“我要连你”服务器回一个 SYNACK 说“好的我准备好了”客户端再回一个 ACK 说“收到咱俩开始吧”。握手完成TCP 连接才建立。对于 S7-300 来说PLC 侧的 CPU 或者 CP343-1 会在 102 端口上监听等上位机主动来连。握手成功后数据交互才正式开始。但这里有个关键点S7-300 并不直接传输裸的 TCP 数据它在 TCP 之上还封装了一层 ISO-on-TCPRFC1006把 TPKT 头部和 COTP 头部加在数据前面。简单理解就是TCP 是高速公路S7 协议是跑在这条路上的标准集装箱车你光看见路上有车没用还得看车上装的是什么规格的箱子。用 Wireshark 抓包时你会看到 TCP 层之上还有 TPKT、COTP再往上才是 S7 Communication 层这就是为什么我们用现成库而不是自己写一个 TCP 客户端去“硬收”数据。2.2 S7 协议的读写报文流程与字节序S7 协议本身的报文结构并不复杂一次读操作大概是这样的过程上位机发送一个 Job 请求请求头部包含协议 ID、功能码读是 04写是 05、要访问的数据区DB 号、起始地址、长度。PLC 收到后返回 ACK 或者带数据的响应帧。上位机解析响应帧从数据区里取出真实值。举一个最直观的例子我要读 DB1.DBW0这个地址是 DB 块第 0 字节和第 1 字节组成的字。S7 协议里这个地址是按大端Big-Endian排的也就是说高位字节在前、低位字节在后。而我们 x86 架构的上位机C#、LabVIEW、Python 都一样默认是小端Little-Endian低位在低地址。所以如果你用裸 socket 自己解析报文读出来这两个字节必须交换一下顺序否则数值直接翻车。这还只是最简单的字。如果是实数Real、32 位整数、字符串字节序问题会更绕。我的经验是要么使用成熟的通讯库它们会处理字节序要么在 PLC 侧和上位机侧约定好“固定用大端拼帧”所有数据在协议层面做成字节数组双方按同一个模板解析。提示不要试图在一个上位机通讯模块里同时兼容“裸 TCP 收数据”和“S7 协议解析”除非你真的把 RFC1006 和 S7 协议文档啃透了。生产项目用现成库把精力花在业务数据处理上才是正路。3. PLC侧配置与通讯程序实现3.1 硬件组态与网络规划不管用 CP343-1 还是 CPU 集成 PN 口第一步都是在 STEP7老项目或 TIA Portal新项目里把硬件组态做好。组态的重点不是把模块拖进去就完事关键是分配 IP 地址、确认插槽位置、生成系统数据块。IP 地址这块我吃过一次亏现场工程师把 CP343-1 的 IP 设成了 192.168.0.10上位机电脑是 192.168.0.20看起来同一网段没问题但实际调试时老是间歇性掉线。最后查出来是车间交换机上还挂了一台打印机静态 IP 正好是 192.168.0.10两台设备冲突了。所以网络规划一定要先扫描一遍现场有哪些 IP 在用不要想当然。如果你用的是带 PN 口的 CPU比如 315-2PN/DP上位机通讯时常见的参数是 Rack0、Slot2因为 S7-300 的 CPU 通常安装在 0 号机架的 2 号槽位1 号槽往往是电源。如果你用 CP343-1 模块Rack 和 Slot 要以硬件组态里的实际槽位为准有可能是 2 也有可能是 4连不上的时候优先核对这组参数。3.2 AG_SEND/AG_RECV 功能块调用要点老 300 站走 CP343-1 时标准做法是在 OB1 里调用 AG_SENDFC5和 AG_RECVFC6这两个通讯功能块。别被它们吓住引脚其实就那么几个REQ发送请求一般用一个定时器或者 M 区位上升沿触发一次发送。ID连接号在组态 CP343-1 的通讯连接属性里配置PLC 程序和上位机必须对应同一个连接号。LEN发送或接收的数据长度单位是字节。DATA数据区最好是独立的 DB 块不要直接拿临时变量。DONE/ERROR/STATUS状态反馈ERROR 和 STATUS 可以用来查通讯故障。我用 AG_SEND 踩过最深的坑是数据区必须用固定长度。如果发送数据长度在程序里动态变化比如这轮发 10 个字节、下轮发 20 个字节接收端解析时很容易错位甚至丢帧。后来我把通讯数据一律做成固定长度的结构体比如发一个 64 字节的数组不足部分补零上位机按固定长度解析问题立刻消失。3.3 PUT/GET 方式与集成 PN 口如果你的 CPU 自带 PN 口那么恭喜你PLC 侧的工作量能减少一大半。你只需要在组态里建立一个 S7 连接然后在程序里调用 FB15PUT和 FB14GET把数据写给伙伴或者从伙伴读过来。如果你不想在 PLC 里写任何通讯逻辑甚至可以在 CPU 属性里把“允许从伙伴读取/写入”打开上位机直接通过 S7 协议读写 DB 块、M 区PLC 程序完全不用管通讯。这种方案适合中小数据量的场景比如上位机监控几十个变量、下发几条配方。但如果要做大规模数据采集我还是建议在上位机侧做分块读取并且在上位机程序里做好缓存和队列否则直接在 UI 线程里频繁读写 DB 块界面卡死是必然的。4. 上位机通讯程序开发实战4.1 开发库选型上位机开发我用的语言是 C#选库时对比过三个方案方案特点适用人群S7netplus开源、一直在维护、NuGet 直接装、支持 300/1200/1500推荐大多数项目使用Sharp7性能不错、API 偏底层、文档相对少需要大量底层控制或嵌入式场景自己写 S7 协议栈学习价值高、但坑多协议细节容易踩雷仅推荐用于学习 RFC1006 和 S7 协议原理实际项目里我一直用 S7netplus原因倒不是它功能最全而是社区活跃踩过的坑在 GitHub issue 里基本都能搜到这对现场调试来说太重要了。安装方式就一行命令Install-Package S7netplus。4.2 连接、读取与断线重连的关键代码C# 侧连接 S7-300 的核心代码非常简单但是参数不能错using (var plc new Plc(CpuType.S7300, 192.168.0.10, 0, 2)) { plc.Open(); if (plc.IsConnected) { Console.WriteLine(连接成功); } }注意这里CpuType.S7300表示连接的是 S7-300 系列0是 Rack2是 Slot连不上时优先检查这两个参数。连接成功后读变量可以直接按地址字符串来读// 读 DB1.DBW0字 ushort dbw0 (ushort)plc.Read(DB1.DBW0); // 读 DB1.DBX0.0位 bool bit0 (bool)plc.Read(DB1.DBX0.0); // 读 M 区M0.0 这个位 bool m0 (bool)plc.Read(M0.0); // 读 I 区和 Q 区 byte inputByte (byte)plc.Read(I0.0); byte outputByte (byte)plc.Read(Q0.0);如果一次要读一大段连续数据用ReadBytes更高效比如读 DB1 从第 0 字节开始的 64 个字节byte[] data plc.ReadBytes(DataType.DataBlock, 1, 0, 64);这里要特别提醒PDU 长度限制是真实存在的。S7-300 的 PDU 协商长度通常是 240 字节左右也就是说一次读写操作里能承载的有效数据很有限。如果你一次性读几百个字节库可能直接报错或者只返回一部分。解决办法就是分块读比如每 200 字节一块循环读完再拼接。断线重连是现场项目里必须考虑的。S7netplus 的 Open 方法不是线程安全的你不能在 UI 线程里反复调否则界面会冻住。我一般用一个后台线程跑循环每隔几百毫秒检查一次plc.IsConnected如果断了就尝试用带退避策略的方式重新 Openwhile (true) { if (!plc.IsConnected) { Thread.Sleep(3000); // 先等 3 秒再重连避免风暴 try { plc.Open(); } catch { /* 记日志继续等 */ } } // 正常读数据... }4.3 多线程刷新与数据管理上位机通讯程序最容易烂的地方不是连不上而是“连上了但界面和数据越来越乱”。我的做法是这样的后台线程只负责数据采集把采到的原始数据丢进一个队列或者共享对象里UI 线程用定时器从共享对象里取最新值显示。这样就算通讯短暂卡顿界面也不会跟着抖动。另外日志一定要留全。很多现场问题当时复现不了等回到办公室才暴露出来。我会在上位机里加一个简单的日志模块把连接成功、断开、超时、收发字节数、异常堆栈全部写到本地文件时间精确到毫秒。后面联调时哪怕现场没有 Wireshark凭着日志和 PLC 侧的 STATUS 码也能定位一大半问题。5. 联调经验与常见问题排查5.1 连接不上的原因清单这恐怕是出现频率最高的一类问题。我整理过一个速查表每次联调直接按表排查现象可能原因解决办法Ping 不通网线没插好、IP 不在同一网段、网卡被禁用先解决物理链路和网段问题再来谈通讯Ping 通但端口连不上PLC 侧没有组态以太网通讯、S7 服务未启用、防火墙拦截检查 PLC 硬件组态和 CPU 或 CP 属性里的服务配置连接被重置Connection ResetRack/Slot 参数错误、TSAP 配置不对、PLC 拒绝连接核对 Rack/Slot确认 PLC 通讯连接是否建立Open 一直超时Windows 防火墙拦截出站、上位机有多个网卡路由混乱防火墙放行 102 端口禁用多余网卡连上后读不到数据地址写错、DB 号不对、PLC 侧数据块未分配先用 PLC 编程软件在线监控确认地址有效性这里想单独说一下防火墙。Windows 默认防火墙一般拦入站不拦出站但如果你的上位机是被动接收比如做 TCPListener 服务器就必须在防火墙里加一条入站规则放行 102 端口。另外很多人用笔记本做调试笔记本的 Wi-Fi 和有线网卡同时开着路由表乱掉会导致数据包走了错误网卡这时把 Wi-Fi 禁用只保留和 PLC 相连的有线网卡是最省心的。5.2 连接频繁断开与重连风暴通讯程序最让人头疼的是“连得快、断得也快”业务还没跑热就掉了。这类问题常见原因有三个第一个是没有心跳机制。TCP 连接长时间没有数据包中间设备防火墙、交换机、路由器可能把连接当作空闲状态回收掉。解决办法是上位机做一个周期心跳比如每隔 5 秒读一次 PLC 的某个状态字既能确认连接活着又能顺带刷新数据。第二个是重连逻辑写得太激进。有些工程师断开后立刻重连失败再重连形成一个紧密循环轻则日志刷屏重则把 PLC 的通讯资源耗光导致其他上位机也连不上。我建议重连必须加退避比如第一次断线等 3 秒第二次等 5 秒最多等 30 秒封顶。第三个是 TCP 挥手后端口进入 TIME_WAIT 状态旧连接占用了本地端口重新连接时绑定失败。之前在抓某个服务端程序日志时看到过这样的报错bind: only one usage of each socket address就是端口被占用没释放。上位机作为服务器场景下可以设置SocketOptionName.ReuseAddress或者直接换一个端口。5.3 用 Wireshark 抓包定位问题最后说一个定位问题的利器Wireshark。哪怕你用现成库也建议学会抓包因为很多问题从代码层面根本看不出原因抓到包一眼就明白。过滤规则很简单PLC 通讯默认走 102 端口所以输入tcp.port 102即可。重点看三个东西三次握手是否完成。如果只看到 SYN看不到 SYNACK说明 PLC 侧根本没响应多半是 IP 不通或者 PLC 没开 102 端口。握手完成后是否有 TPKT/COTP 层。如果 TCP 都连上了但一直看不到 TPKT说明对方可能不是标准的 S7 服务或者连接的端口不对。S7 Job 和响应是否成对出现。有请求没响应说明 PLC 侧通讯功能块没跑起来有响应但解析出来全是乱码再去查字节序和地址长度。有一次现场就是靠抓包定位到问题的上位机 Display 里地址写成了DB1.DBW1起始地址是奇数S7 协议里字访问要求偶数地址PLC 直接报错并回了错误帧Wireshark 里能看到响应帧带了一个错误代码这才顺藤摸瓜找到问题。坦白说做完这类 S7-300 以太网通讯项目我的最大感受是真正卡住进度的往往不是代码而是那些“看起来不重要”的细节——IP 冲突、Rack/Slot 参数、防火墙策略、PDU 长度限制。调试时每一次只改一个变量改完在抓包里能立刻看到变化这样推进最稳妥。如果你正在做类似项目建议先拿一台真实 PLC 或者模拟器把连接流程跑通再往上加业务逻辑一上来就堆业务代码出了问题根本分不清是网络问题还是程序问题。本文还有配套的精品资源点击获取
返回列表