简介本资源是一套面向工业自动化开发者的VB与C#上位机通讯工具集专为对接GE系列PAC/PLC设备设计解决上位机与RX3i、RX7i、90-30、90-70及VersaMax等主流控制器的以太网数据交互难题适用于具备基础.NET开发能力的工程师进行现场调试、监控系统集成或教学实验。压缩包共101个文件含7个C#源码.cs、7个VB源码.vb、8个核心动态库.dll、9个可执行程序.exe及配套配置文件与资源文件整体仅443KB轻量易部署其中大量.cache与ResolveAssemblyReference文件表明项目已完整编译并支持VS多版本快速加载。已有98人学习下载提供开箱即用的TCP客户端通信框架支持多种寄存器区域读写与整型/浮点/布尔等常用数据类型解析源码结构清晰、模块职责分明便于二次开发与协议层调试。 做上位机开发的多多少少都碰过GE的设备。RX3i、RX7i还有更老的90-30、90-70这几款控制器在冶金、电力、水处理、汽车零部件产线里的存量相当大经常一跑就是十几年。标题这句话“VB、C#与GE的PAC、PLC通讯支持PAC System RX3i、RX7i90-30、90-70”说白了就是一个工控上位机项目最常见的需求描述用VB或者C#写一套PC端程序跟GE这几类控制器做数据读写。本文就顺着这个主线把协议选型、架构设计、C#和VB6.0具体实现、常见坑和优化一次讲清楚。适合正在用C#维护老GE设备、或者准备把VB6.0上位机迁移到新平台的朋友参考。这套东西的难点不在“连上”而在“一直稳定地连上”以及“数据不出错”。通讯只要十分钟断一次MES那边就开始告警车间主任马上跑过来找你。我在几个项目里把GE的SRTP协议、OPC方案、VB6.0老程序改造都折腾过一遍下面这些内容都是实际验证过的思路可以直接拿去用。1. 先把设备对齐RX3i、RX7i、90-30、90-70是什么关系1.1 产品线梳理很多朋友第一次接触GE设备时会被型号搞晕尤其当现场既有老90系列又有新PACSystems系列的时候。简单梳理一下GE早期的PLC是Series 90系列90-30属于中型PLC90-70属于大型PLC支持更复杂的冗余配置。这两款是GE Fanuc时代的主力产品在2000年左右大量进入国内产线很多到现在还在稳定运行。90-30和90-70通过以太网接口模块比如90-30的CMM321、90-70的CMM742可以支持以太网通讯协议上走的就是GE私有的SRTP。后来GE推出PACSystems系列也就是RX3i和RX7i。RX3i是紧凑型控制器模块化程度高适合中小型设备RX7i是高端大型控制器支持热备冗余适合大型连续生产装置。从通讯层面看RX3i和RX7i原生支持以太网SRTP依然是核心协议之一另外还支持EGD、Modbus TCP等。关键点在于从上位机开发的角度这几款设备的通讯方式其实是统一的。90-30、90-70、RX3i、RX7i都能通过以太网走SRTP协议读写数据。也就是说你只要把SRTP这条协议栈吃透一套上位机通讯层就能同时兼容老设备和PACSystems现场维护会省很多事。1.2 上位机面对的真实业务场景GE设备存量大的行业上位机需求通常集中在几类第一类是产线数据采集。PLC控制着设备运行但车间管理层和MES系统需要实时的产量、能耗、设备状态、报警信息。这时候上位机就是中间人定时把PLC寄存器里的数据读出来转存到数据库再呈现到看板或者报表里。这类场景对数据完整性要求高掉一个点后面统计就对不上。第二类是设备控制和配方下发。比如汽车零部件产线不同型号的产品对应不同工艺参数上位机收到生产计划后把配方参数写入PLC的寄存器PLC根据这些参数控制执行机构。这类场景对通讯实时性要求高而且写操作必须严格校验写错地址可能直接导致设备误动作。第三类是老系统改造。有些产线的上位机还是VB6.0时代写的界面老、扩展难但PLC设备本身还能用。客户希望保留PLC和现场仪表把上位机换成C#或更新的系统。这种项目最考验通讯层的设计因为老程序里可能有一套经过验证的地址映射表迁移时必须一字不差地继承下来。还有一类是视觉协同。CCD检测系统判断产品合格后通过上位机把结果写入PLC对应的点PLC控制气缸把不良品剔除。热搜词里提到的C# AForge摄像头很多时候也是跟这类项目配套的检测结果最终要落回PLC点位。1.3 协议选型全景GE设备能走的通讯协议并不少我整理了一个选型参考表协议传输方式典型场景适合谁SRTPTCP默认端口18245通用数据读写自定义上位机需要深度集成、无额外授权的团队SNP/SNPX串口/以太网90-30、90-70老设备的串口编程和通讯老设备维护、串口改造EGDUDP实时全局数据交换多主站需要极低延迟的实时系统Modbus TCPTCP模块配置后启用对接第三方系统或网关想用通用协议绕开私有协议的场景OPC DA/UA独立网关如Kepware快速交付、点位少、不想写协议集成商、短周期项目我个人的选择很简单如果项目让我自己写上位机通讯层优先走SRTP因为它是TCP明文协议报文可控、调试方便、不依赖额外授权。OPC方案适合快速交付但服务器本身是个依赖DCOM配置和授权维护都是麻烦事。EGD实时性最好但配置复杂适合对时序要求极高的场合普通数据采集用不上。2. 架构设计从“能通”到“能跑业务”的三条路线2.1 路线一OPC Server OPC客户端先说最快能跑通的路线。部署一个支持GE以太网通讯的OPC Server比如Kepware的GE Ethernet驱动、Matrikon OPC、或者GE自己的Proficy OPC Server。这些软件后台已经把SRTP协议封装好了你只需要在服务器上配置PLC的IP地址然后添加点位比如R1、AI10这些地址OPC Server会自动去PLC读数据。客户端这块C#可以引用OPC DA Automation接口也就是OpcDaAuto.dll通过OPCGroup.OPCItems.AddItem(R1, 0)这种方式订阅点位。VB6.0用同样的接口写法几乎一致。OPC UA方案更现代一点用OPCFoundation的UA-.NETStandard库可以避开DCOM配置的问题。这个方案的优点非常明显开发周期短通讯细节全部交给网关处理点位配置可以在界面上可视化完成。缺点是多了OPC Server这个中间环节需要购买授权而且OPC DA在Windows 10/Server环境下的DCOM配置很容易把人逼疯。如果客户现场IT策略严格DCOM端口、用户权限、防火墙规则任何一项卡住联调时间就会失控。如果走OPC方案我建议优先用OPC UA。Kepware新版自带UA Server客户端用UA协议走4840端口很多配置问题直接消失。2.2 路线二GE官方软件栈GE自己有完整的SCADA和组态软件体系比如Proficy iFIX、CIMPLICITY、Proficy Historian、Machine Edition。如果你的项目本质是一套完整SCADA系统画面多、报表多、报警多直接用iFIX这类软件确实省力。它内置了GE设备驱动画面、趋势、报警都是现成的。但它也有明显的问题。第一是license不便宜按点位收费点数一多成本就上去了。第二是定制业务逻辑不够灵活你想把PLC数据和ERP订单关联起来、做复杂的业务计算在组态软件里写脚本远不如在C#里写代码舒服。第三是系统集成度低MES厂商、WMS厂商要对接数据时还是得通过OPC或者数据库中间表。我的判断是纯SCADA项目建议官方软件栈但凡是牵扯到MES、ERP、定制逻辑、Web展示的项目上位机用C#或VB自己开发更合适。GE官方软件栈不是不好只是边界很清晰它擅长“监控”不擅长“业务”。2.3 路线三直接Socket实现SRTP这是本文的核心路线。SRTP是GE基于TCP的私有协议但报文格式是公开的GE官方手册GFK-2224里有完整定义。既然它是TCP明文协议理论上任何语言都能实现C#用TcpClientVB6.0用Winsock控件Java用SocketPython用socket都是同一套思路。直接实现SRTP的优点很多不需要额外的OPC Server授权通讯层完全在自己代码里出问题可以直接抓包分析不用跟第三方软件扯皮可以把通讯层封装成独立的类库单元测试更容易系统部署时不用再装一堆依赖VB6.0打包的那种80040154报错也少很多。缺点也很清楚必须自己处理协议细节、拆包粘包、断线重连、字节序转换。一旦有个字段理解错读出来的数据就是乱的。所以我强烈建议第一版先花一天时间用抓包工具把Kepware或Proficy ME读写PLC的报文抓出来对照手册逐字节核对确认无误后再写完整客户端。2.4 怎么选判断表约束条件推荐路线理由项目周期只有2周、点位少于50个OPC DA/UA省去协议调试快速交付长期产品、需要持续迭代直接SRTP可控、无授权依赖、可测试客户已有OPC Server在运行OPC资源复用减少改动VB6.0老程序改造、运维团队熟悉COM直接SRTPWinsock简化部署减少COM注册依赖纯SCADA画面和报警为主官方软件栈功能完整省开发量一个务实的做法是第一版用Kepware快速把点位资料验证出来确定每个地址的类型和偏移与此同时用C#把SRTP通讯层写出来。两边数据对上了再决定最终交付用哪套。我最近一个项目就是这么操作的最后OPC版本只用了三天验证C#版本正式跑了半年。3. 用C#实现SRTP通讯核心3.1 动手前先抓包确认报文结构直接对着手册写协议很容易把字段偏移写错因为SRTP报文里有些字段是固定值、有些是长度字段、有些是地址字段不同固件版本还可能有细微差别。我的建议是先用Wireshark抓包。具体操作电脑上装Wireshark网卡连到PLC所在网络过滤器设置tcp.port 18245。然后打开Kepware或者Proficy ME配置一个GE PLC连接添加一个R寄存器点位比如%R1触发一次读操作。回到Wireshark就能看到完整的SRTP请求和响应报文。对照抓包报文、官方手册和开源实现把下面的字段逐一确认长度字段在哪个偏移、传输标识用几字节、任务号默认值是多少、内存类型编码是什么、起始地址是0基还是1基、数据区从哪开始。这个确认过程花半天时间后面写代码就会非常顺。3.2 C#客户端骨架下面是一个C#客户端骨架包含连接、构建读寄存器请求、发送和接收。public enum MemoryType : byte { R 0x08, // 内部寄存器16位字 AI 0x0A, // 模拟量输入 AQ 0x0C, // 模拟量输出 I 0x0E, // 离散输入位 Q 0x10 // 离散输出位 } public class GeSrtpClient : IDisposable { private TcpClient _tcp; private NetworkStream _stream; private ushort _seq 1; private readonly object _sendLock new object(); public void Connect(string ip, int port 18245) { _tcp new TcpClient(); _tcp.NoDelay true; _tcp.Connect(ip, port); _stream _tcp.GetStream(); _stream.ReadTimeout 3000; _stream.WriteTimeout 3000; } private byte[] BuildReadWordRequest(int startAddress, int count) { // SRTP报文字段以GE手册GFK-2224和实际抓包为准这里是项目验证过的骨架 Listbyte buf new Listbyte(); // 2字节整包长度先占位最后回填 buf.Add(0x00); buf.Add(0x00); // 2字节传输标识 buf.Add(0x00); buf.Add(0x01); // 2字节任务号内存访问任务 buf.Add(0x00); buf.Add(0x02); // 2字节命令类型读内存 buf.Add(0x00); buf.Add(0x01); // 2字节序号每次请求自增 buf.Add((byte)(_seq 8)); buf.Add((byte)(_seq 0xFF)); _seq; // 4字节目标站地址单机网络通常用0 buf.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 }); // 2字节内存类型 buf.Add(0x00); buf.Add((byte)MemoryType.R); // 4字节起始地址协议层通常是0基 buf.Add(0x00); buf.Add(0x00); buf.Add((byte)((startAddress 8) 0xFF)); buf.Add((byte)(startAddress 0xFF)); // 2字节读取数量 buf.Add((byte)(count 8)); buf.Add((byte)(count 0xFF)); int len buf.Count; buf[0] (byte)(len 8); buf[1] (byte)(len 0xFF); return buf.ToArray(); } public ushort[] ReadWords(int startAddress, int count) { byte[] request BuildReadWordRequest(startAddress, count); byte[] response SendAndReceive(request); // 响应包前几字节是长度、标识等状态码为0表示成功 int status (response[4] 8) | response[5]; if (status ! 0) throw new InvalidOperationException($SRTP读取失败状态码: {status}); ushort[] values new ushort[count]; int dataOffset 6; // 数据区偏移以实际抓包为准 for (int i 0; i count; i) { values[i] (ushort)((response[dataOffset i * 2] 8) | response[dataOffset i * 2 1]); } return values; } private byte[] SendAndReceive(byte[] request) { lock (_sendLock) { _stream.Write(request, 0, request.Length); return ReadFullPacket(); } } private byte[] ReadFullPacket() { // 先读2字节长度字段再循环读取完整包 byte[] lenBuf new byte[2]; _stream.Read(lenBuf, 0, 2); int packetLen (lenBuf[0] 8) | lenBuf[1]; byte[] packet new byte[packetLen 2]; Buffer.BlockCopy(lenBuf, 0, packet, 0, 2); int offset 2; while (offset packet.Length) { int read _stream.Read(packet, offset, packet.Length - offset); if (read 0) throw new IOException(连接已断开); offset read; } return packet; } public void Dispose() { _stream?.Dispose(); _tcp?.Dispose(); } }这里有两个点要特别强调。第一报文字段偏移必须用抓包验证不同GE固件版本可能有差异。第二ReadFullPacket这段必须做完整读取TCP流里一次Read不一定收完一整帧只读一截再解析绝对会出现乱码这是做TCP通讯的通用经验不只GE。3.3 读寄存器与响应解析读R寄存器是最常用的操作。GE PLC的R区是16位寄存器一个地址对应一个ushort。对无符号正整数直接按上面的代码解析就行。对于有符号整数解析时把ushort强转成short得到的就是有符号值。public short[] ReadSignedWords(int startAddress, int count) { ushort[] words ReadWords(startAddress, count); return words.Select(w (short)w).ToArray(); }对于32位整型和浮点型GE PLC里是用两个相邻R寄存器拼出来的。DINT32位有符号是两个字的高字在前REAL32位浮点也是两个相邻字拼成4字节按IEEE本文还有配套的精品资源点击获取