跳到主要内容

EtherNet/IP

Zeus 的 EtherNet/IP 模块面向 Allen-Bradley / Rockwell PLC,支持 TCP 44818 上的 Register Session、SendRRData、CIP Read Tag / Write Tag,以及 Get Attribute Single / Set Attribute Single。当前覆盖常用标量标签,适合把 PLC 标签接入点表采集和按点名写回。

没硬件时先跑虚拟 PLC

var memory = new EtherNetIpSlaveMemory();
memory.SetTag("Temperature", EtherNetIpDataType.Int, (short)253);
memory.SetTag("Running", EtherNetIpDataType.Bool, true);

await using var app = ZeusHost.Create(builder =>
{
builder.AddAcquisition(TimeSpan.FromMilliseconds(100));
builder.AddVirtualChannel("enip-link", new EtherNetIpSlaveResponder(memory));
builder.AddEtherNetIp("plc", "enip-link", points: map => map
.Int("temperature", "Temperature", scale: 0.1).Writable("temperature")
.Bool("running", "Running").Writable("running"));
});

await app.StartAsync();
var temperature = app.Points.Get<double>("temperature");
await app.Points.WriteAsync("temperature", 18.6);

这段代码里:

代码含义
EtherNetIpSlaveMemory虚拟 PLC 的标签和 CIP 属性内存映像
EtherNetIpSlaveResponder(memory)模拟 EtherNet/IP Register Session 与 CIP 标签应答
.Int(..., 0.1)Temperature 原始 INT 乘以 0.1 后进入点表;写回时反算
.Writable(...)允许通过 app.Points.WriteAsync(...) 按点名写回

省略 memory 时,默认虚拟 PLC 会预置 TemperatureRunningProgram:Main.Speed 三个演示标签,便于 JSON 示例直接跑通。

可运行示例:samples/Zeus.Samples.Console.EtherNetIp

连接真实 PLC

EtherNet/IP 常用端口是 44818。通道只负责 TCP 收发,CIP 会话由 EtherNetIpDevice 处理:

await using var app = ZeusHost.Create(builder =>
{
builder.AddTcpClient("enip-link", "192.168.1.10", 44818);
builder.AddEtherNetIp("plc", "enip-link", points: map => map
.Int("temperature", "Temperature", scale: 0.1)
.Bool("running", "Running"));
});

如果标签在 Program 作用域下,标签名按 PLC 工程里的完整路径写,例如 Program:Main.Speed。Zeus 会按点号拆成 CIP Symbol Segment。

读写 API

var plc = app.Devices.Get<EtherNetIpDevice>("plc");

var temperature = await plc.ReadTagAsync("Temperature", EtherNetIpDataType.Int, scale: 0.1);
await plc.WriteTagAsync("Temperature", EtherNetIpDataType.Int, 18.6, scale: 0.1);

var running = await plc.ReadTagAsync("Running", EtherNetIpDataType.Bool);
await plc.WriteTagAsync("Running", EtherNetIpDataType.Bool, true);

byte[] identityName = await plc.GetAttributeSingleAsync(classId: 0x01, instanceId: 1, attributeId: 7);
await plc.SetAttributeSingleAsync(classId: 0x64, instanceId: 1, attributeId: 3, new byte[] { 0x01 });

支持的标量类型:

JSON / APICIP 类型
bool / BoolBOOL 0x00C1
sint / SIntSINT 0x00C2
int / IntINT 0x00C3
dint / DIntDINT 0x00C4
lint / LIntLINT 0x00C5
usint / USIntUSINT 0x00C6
uint / UIntUINT 0x00C7
udint / UDIntUDINT 0x00C8
ulint / ULIntULINT 0x00C9
real / RealREAL 0x00CA
lreal / LRealLREAL 0x00CB

点表采集

builder.AddEtherNetIp("plc", "enip-link", points: map => map
.Int("temperature", "Temperature", scale: 0.1).Writable("temperature")
.DInt("speed", "Program:Main.Speed")
.Real("flow", "Flow")
.Bool("running", "Running").Writable("running"));

EtherNet/IP 标签本身已经有名称,点表名可以更偏业务,例如把 PLC 的 Program:Main.Speed 暴露为 Zeus 点 speedscale 仅用于数值标签,BOOL 不允许配置报警限或缩放。

JSON 配置

{
"channels": [
{ "name": "enip-link", "type": "tcp", "host": "192.168.1.10", "port": 44818 }
],
"devices": [
{
"name": "plc",
"channel": "enip-link",
"type": "ethernet-ip",
"points": [
{ "name": "temperature", "tag": "Temperature", "dataType": "int", "scale": 0.1, "writable": true },
{ "name": "running", "tag": "Running", "dataType": "bool", "writable": true },
{ "name": "speed", "tagName": "Program:Main.Speed", "dataType": "dint" }
]
}
]
}

虚拟 EtherNet/IP PLC:

{ "name": "enip-link", "type": "virtual", "responder": "ethernet-ip" }

如果 tag / tagName 省略,Zeus 会使用 name 作为 PLC 标签名。

常见问题

现象最可能原因处理
一直超时IP、端口 44818、防火墙或 PLC EtherNet/IP 服务不可达先用 EtherNetIpSlaveResponder 跑通主站逻辑,再核对现场网络
返回 CIP 状态 0x04标签路径错误或标签不存在核对标签名、Program 作用域和大小写
类型不匹配JSON / API 的 dataType 和 PLC 标签类型不同按 PLC 工程里的标签类型设置 EtherNetIpDataType
写回没执行点没有 .Writable(...) 或 JSON 没设 writable: true标记点为可写,并确认 PLC 标签允许外部写入
BOOL 配了 scale 或报警限BOOL 不是数值点移除 scalelowAlarmLimithighAlarmLimit

下一步:周期读取数据看 点表与采集