三菱 MC
Zeus 的 MC 模块支持 Mitsubishi MC Protocol 1E / 3E / 4E,适合通过以太网读写三菱 PLC 的常用软元件。默认使用 3E Binary;也可以切到 ASCII 编码或 1E / 4E 帧。当前覆盖 X/Y/M 位软元件、D/W/R/ZR 字软元件,以及 3E / 4E 随机读写。
安装
dotnet add package Zeus.Communications
dotnet add package Zeus.Protocols.Mc
连接真实 PLC
MC 通常跑在 TCP 通道上。通道只负责搬运字节,协议设备挂在通道之上:
await using var app = ZeusHost.Create(builder =>
{
builder.AddTcpClient("plc-link", "192.168.1.10", 5000);
builder.AddMitsubishiMc("plc", "plc-link");
});
await app.StartAsync();
var plc = app.Devices.Get<McDevice>("plc");
var d100 = await plc.ReadDataRegistersAsync(address: 100, points: 2);
var y20 = await plc.ReadOutputRelaysAsync(address: 0x20, points: 8);
await plc.WriteDataRegistersAsync(address: 200, values: [123, 456]);
await plc.WriteOutputRelaysAsync(address: 0x20, values: [true, false, true, false]);
AddMitsubishiMc3E 仍然保留,等价于默认 3E Binary。新代码推荐用更通用的 AddMitsubishiMc。
如果现场 PLC 的帧类型、编码、网络号、PC 号、I/O 号或站号不是默认值,可以传入 Mc3EOptions:
builder.AddMitsubishiMc("plc", "plc-link", new Mc3EOptions
{
FrameType = McFrameType.Frame3E,
DataEncoding = McDataEncoding.Binary,
NetworkNumber = 0x00,
PcNumber = 0xFF,
IoNumber = 0x03FF,
StationNumber = 0x00,
MonitoringTimer = 0x0010
});
常见切换方式:
// 3E ASCII
builder.AddMitsubishiMc("plc", "plc-link", new Mc3EOptions
{
FrameType = McFrameType.Frame3E,
DataEncoding = McDataEncoding.Ascii
});
// 4E Binary / ASCII,可按需设置序列号
builder.AddMitsubishiMc("plc", "plc-link", new Mc3EOptions
{
FrameType = McFrameType.Frame4E,
DataEncoding = McDataEncoding.Binary,
SerialNumber = 0x0001
});
// 1E Binary / ASCII,主要用于较旧设备或旧配置
builder.AddMitsubishiMc("plc", "plc-link", new Mc3EOptions
{
FrameType = McFrameType.Frame1E,
DataEncoding = McDataEncoding.Ascii
});
读写常用软元件
常用 API 已按三菱软元件名包装:
var d = await plc.ReadDataRegistersAsync(100, 4);
await plc.WriteDataRegistersAsync(100, [10, 20, 30, 40]);
var m = await plc.ReadInternalRelaysAsync(100, 8);
await plc.WriteInternalRelaysAsync(100, [true, false, true, false]);
var x = await plc.ReadInputRelaysAsync(0x10, 8);
var y = await plc.ReadOutputRelaysAsync(0x20, 8);
await plc.WriteOutputRelaysAsync(0x20, [true, false, true, false]);
var w = await plc.ReadLinkRegistersAsync(100, 2);
await plc.WriteLinkRegistersAsync(100, [1000, 1001]);
var r = await plc.ReadFileRegistersAsync(100, 2);
await plc.WriteFileRegistersAsync(100, [2000, 2001]);
var zr = await plc.ReadExtendedFileRegistersAsync(100, 2);
await plc.WriteExtendedFileRegistersAsync(100, [3000, 3001]);
需要直接按软元件代码调用时,也可以使用泛型读写方法:
var words = await plc.ReadWordsAsync(McDeviceCode.DataRegister, 100, 2);
var bits = await plc.ReadBitsAsync(McDeviceCode.InternalRelay, 100, 8);
await plc.WriteBitsAsync(McDeviceCode.InputRelay, 0x40, [true, false, true]);
真实 PLC 上 X 输入继电器通常由现场输入状态驱动,便捷 API 只提供读取;如果设备或仿真环境允许写入,可使用通用 WriteBitsAsync。
随机读写
3E / 4E 帧支持在一次事务中访问多个不连续软元件。随机读取可同时返回单字和双字结果;随机写入按 MC 协议分为字/双字写入和位写入:
var random = await plc.ReadRandomAsync(
wordDevices:
[
new McDeviceAddress(McDeviceCode.DataRegister, 100),
new McDeviceAddress(McDeviceCode.LinkRegister, 10)
],
doubleWordDevices:
[
new McDeviceAddress(McDeviceCode.DataRegister, 200)
]);
var d100 = random.WordValues[0];
var w10 = random.WordValues[1];
var d200D201 = random.DoubleWordValues[0];
await plc.WriteRandomWordsAsync(
wordValues:
[
new McWordWrite(McDeviceCode.DataRegister, 110, 1234),
new McWordWrite(McDeviceCode.LinkRegister, 11, 5678)
],
doubleWordValues:
[
new McDoubleWordWrite(McDeviceCode.DataRegister, 210, 0x12345678)
]);
await plc.WriteRandomBitsAsync(
[
new McBitWrite(McDeviceCode.InternalRelay, 100, true),
new McBitWrite(McDeviceCode.OutputRelay, 0x20, false)
]);
随机读写仅适用于 3E / 4E;1E 帧继续支持上面的连续批量读写。
没 PLC 时先联调
McSlaveResponder 可以挂到虚拟通道上,模拟一个 MC PLC。它会自动识别 1E / 3E / 4E 和 Binary / ASCII 请求:
var memory = new McSlaveMemory();
memory.DataRegisters[100] = 1234;
memory.InternalRelays[10] = true;
await using var app = ZeusHost.Create(builder =>
{
builder.AddVirtualChannel("plc-link", new McSlaveResponder(memory));
builder.AddMitsubishiMc("plc", "plc-link");
});
这样可以先验证业务代码、界面绑定和通信追踪,再把虚拟通道换成 AddTcpClient。
用 JSON 配置
安装 Zeus.Configuration 后,可以把通道和 MC 设备放进 zeus.json:
{
"channels": [
{
"name": "plc-link",
"type": "tcp",
"host": "192.168.1.10",
"port": 5000
}
],
"devices": [
{
"name": "plc",
"channel": "plc-link",
"type": "mitsubishi-mc",
"frameType": "4e",
"encoding": "ascii",
"serialNumber": 1,
"networkNumber": 0,
"pcNumber": 255,
"ioNumber": 1023,
"stationNumber": 0,
"monitoringTimer": 16,
"points": [
{ "name": "temperature", "deviceCode": "D", "address": 100, "scale": 0.1, "writable": true },
{ "name": "run", "deviceCode": "M", "address": 10, "writable": true },
{ "name": "ready", "deviceCode": "X", "address": "0x10" },
{ "name": "recipe", "deviceCode": "ZR", "address": 0 }
]
}
]
}
程序里读取后仍然从设备目录取 McDevice:
await using var app = ZeusHost.Create(builder => builder.AddJsonFile("zeus.json"));
await app.StartAsync();
var plc = app.Devices.Get<McDevice>("plc");
var d100 = await plc.ReadDataRegistersAsync(100, 2);
声明 points 后会自动接入周期采集和点表写回:
var temperature = app.Points.Get<double>("temperature");
await app.Points.WriteAsync("run", true);
await app.Points.WriteAsync("temperature", 12.3);
MC 点使用 deviceCode 指定软元件:D、M、X、Y、W、R、ZR。其中 X 输入继电器只读,不能设置 writable: true;ZR 仅 3E / 4E 支持。地址可以写十进制数,也可以写字符串形式的十六进制,例如 "0x10"。
无硬件时可以把通道改成虚拟 MC PLC:
{
"name": "plc-link",
"type": "virtual",
"responder": "mc"
}
JSON 已支持声明和热更新 MC 设备,也支持 MC points 点表映射、周期采集和按点名写回。
当前范围
| 能力 | 状态 |
|---|---|
| 3E Binary / ASCII 帧 | 已支持 |
| 4E Binary / ASCII 帧 | 已支持 |
| 1E Binary / ASCII 帧 | 已支持常用批量读写;1E 不支持原始 ExecuteAsync 命令 |
| D 数据寄存器批量读写 | 已支持 |
| M 内部继电器批量读写 | 已支持 |
| X 输入继电器批量读取 | 已支持 |
| Y 输出继电器批量读写 | 已支持 |
| W 链接寄存器批量读写 | 已支持 |
| R 文件寄存器批量读写 | 已支持 |
| ZR 扩展文件寄存器批量读写 | 3E / 4E 已支持 |
| 随机读取、随机字/双字写入、随机位写入 | 3E / 4E 已支持 |
| JSON 点表 / 周期采集 / 点名写回 | 已支持 |
| 虚拟 PLC / 无硬件联调 | 已支持 |
常见问题
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 连接失败 | IP、端口、防火墙或 PLC 以太网设置不对 | 先确认 TCP 端口能连通 |
| 返回结束码 | 地址越界、软元件类型不支持或 PLC 拒绝访问 | 看 McException.EndCode,再对照 PLC 手册 |
| 读到的数据错位 | 地址基准和设备文档不一致 | 确认 D100 是否应直接写 address: 100;X/Y 常按十六进制编号理解,例如 X10 可写 "address": "0x10" |
| 一直超时 | PLC 未启用对应 MC 帧型、编码或端口不是 MC 协议 | 用 McSlaveResponder 先确认主站代码,再核对 FrameType / DataEncoding |