Omron FINS
Zeus 的 FINS 模块面向 Omron PLC,支持 FINS/UDP 与 FINS/TCP。协议层已经处理 FINS 头、FINS/TCP 节点地址握手、SID 匹配、结束码异常、Memory Area Read/Write/Fill 和 Multiple Memory Area Read。
没硬件时先跑虚拟 PLC
var memory = new FinsSlaveMemory();
memory.DataMemoryWords[100] = 253;
memory.CioWords[10] = 0x0001;
await using var app = ZeusHost.Create(builder =>
{
builder.AddAcquisition(TimeSpan.FromMilliseconds(100));
builder.AddVirtualChannel("fins-link", new FinsSlaveResponder(FinsTransport.Udp, memory));
builder.AddOmronFinsUdp("plc", "fins-link", new FinsOptions
{
SourceNode = 10,
DestinationNode = 1
}, points: map => map
.DmWord("temperature", address: 100, scale: 0.1).Writable("temperature")
.CioBit("running", address: 10, bitOffset: 0).Writable("running"));
});
await app.StartAsync();
var temperature = app.Points.Get<double>("temperature");
await app.Points.WriteAsync("temperature", 18.6);
这段代码里:
| 代码 | 含义 |
|---|---|
FinsSlaveMemory | 虚拟 PLC 的 CIO/WR/HR/AR/DM/EM/TIM-CNT 内存映像 |
FinsSlaveResponder(Udp, memory) | 模拟 FINS/UDP PLC |
SourceNode = 10 | 本机 FINS 节点号 SA1 |
DestinationNode = 1 | PLC FINS 节点号 DA1 |
.DmWord(..., 0.1) | D100 原始字乘以 0.1 后进入点表;写回时反算 |
可运行示例:samples/Zeus.Samples.Console.Fins。
连接真实 PLC
FINS/UDP 常用端口是 9600:
await using var app = ZeusHost.Create(builder =>
{
builder.AddUdpClient("fins-link", options =>
{
options.Host = "192.168.250.1";
options.Port = 9600;
});
builder.AddOmronFinsUdp("plc", "fins-link", new FinsOptions
{
SourceNode = 10,
DestinationNode = 1
});
});
FINS/TCP 同样常用 9600。TCP 连接建立后,Zeus 默认发送节点地址握手,并把返回的客户端节点号和服务端节点号写回本次会话:
builder.AddTcpClient("fins-link", "192.168.250.1", 9600);
builder.AddOmronFinsTcp("plc", "fins-link", new FinsOptions
{
TcpRequestedClientNode = 10
});
如果现场 PLC 禁用了自动节点分配,也可以设置 UseTcpNodeAddressHandshake = false,并手动提供 SourceNode 与 DestinationNode。
读写 API
var plc = app.Devices.Get<FinsDevice>("plc");
var dm = await plc.ReadDataMemoryWordsAsync(100, 2);
await plc.WriteDataMemoryWordsAsync(110, [10, 20, 30]);
var bits = await plc.ReadCioBitsAsync(10, bitOffset: 0, count: 8);
await plc.WriteCioBitsAsync(10, bitOffset: 0, [true, false, true]);
await plc.FillWordsAsync(FinsMemoryAreaCode.DataMemoryWord, 200, 10, 0x55AA);
var values = await plc.ReadMultipleAsync([
new FinsMemoryAddress(FinsMemoryAreaCode.DataMemoryWord, 100),
new FinsMemoryAddress(FinsMemoryAreaCode.CioBit, 10, 0)
]);
也可以直接发任意 FINS 命令:
byte[] data = await plc.ExecuteAsync(command: 0x0101, data: requestData);
支持的内存区
| 区域 | 字代码 | 位代码 | 点表便捷方法 |
|---|---|---|---|
| CIO | CioWord | CioBit | .CioWord(...) / .CioBit(...) |
| WR | WorkWord | WorkBit | .WorkWord(...) / .WorkBit(...) |
| HR | HoldingWord | HoldingBit | .HoldingWord(...) / .HoldingBit(...) |
| AR | AuxiliaryWord | AuxiliaryBit | .AuxiliaryWord(...) / .AuxiliaryBit(...) |
| DM | DataMemoryWord | DataMemoryBit | .DmWord(...) / .DmBit(...) |
| TIM/CNT | TimerCounterValue | TimerCounterFlag | .TimerCounterValue(...) / .TimerCounterFlag(...) |
| 当前 EM | CurrentEmWord | CurrentEmBit | .CurrentEmWord(...) / .CurrentEmBit(...) |
| EM Bank 0–18 | EmBankWord(bank) | EmBankBit(bank) | .EmWord(...) / .EmBit(...) |
点表采集
builder.AddOmronFinsUdp("plc", "fins-link", new FinsOptions
{
SourceNode = 10,
DestinationNode = 1,
WordOrder = FinsWordOrder.HighWordFirst
}, points: map => map
.DmWord("temperature", 100, 0.1).Writable("temperature")
.Int16("pressure", FinsMemoryAreaCode.DataMemoryWord, 120)
.Real("flow", FinsMemoryAreaCode.DataMemoryWord, 130)
.CioBit("running", 10, 0).Writable("running"));
FINS 原始字是 16 位。UInt32、Int32 和 Real 占两个连续字,字序由 FinsOptions.WordOrder 控制,默认高字在前。
JSON 配置
{
"channels": [
{ "name": "fins-link", "type": "udp", "host": "192.168.250.1", "port": 9600 }
],
"devices": [
{
"name": "plc",
"channel": "fins-link",
"type": "omron-fins-udp",
"sourceNode": 10,
"destinationNode": 1,
"points": [
{ "name": "temperature", "area": "dm", "address": 100, "dataType": "word", "scale": 0.1, "writable": true },
{ "name": "running", "area": "cio", "address": 10, "bit": 0, "dataType": "bit", "writable": true }
]
}
]
}
虚拟 FINS PLC:
{ "name": "fins-link", "type": "virtual", "responder": "fins", "transport": "udp" }
可直接复制的真实 UDP / TCP 配置样例位于 samples/Zeus.Samples.Console.Config/zeus-fins-udp.json 和 samples/Zeus.Samples.Console.Config/zeus-fins-tcp.json。
常见问题
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | UDP/TCP 端口、节点号或网络号不对 | 先用 FinsSlaveResponder 跑通,再查 PLC FINS 设置 |
| TCP 首次请求失败 | 节点地址握手被 PLC 拒绝 | 设置 TcpRequestedClientNode,或关闭握手并手动配置节点号 |
| 读到结束码 | 内存区、地址或数量不被 PLC 支持 | 看异常里的 FINS 结束码,核对 CPU 手册 |
| 32 位值高低字反了 | 字序和 PLC 工程约定不一致 | 改 FinsOptions.WordOrder |
| 写回没执行 | 点没有 .Writable(...) 或 JSON 没设 writable: true | 标记点为可写 |
下一步:周期读取数据看 点表与采集。