排错
遇到问题时先不要急着改代码。按这个顺序定位:安装能不能编译、宿主有没有启动、通道有没有打开、协议有没有回包、点表有没有值、界面有没有正确绑定。
先做三步快速判断
- 把真实串口换成
AddVirtualChannel,看程序结构是否能跑通。 - 打印通道状态
channel.State,确认是否进入Open。 - 把收到的数据先按十六进制打印,不要一开始就按文本解析。
channel.DataReceived += (_, e) =>
{
Console.WriteLine(Convert.ToHexString(e.Data.Span));
};
安装和包引用
| 现象 | 最可能原因 | 处理 |
|---|---|---|
dotnet 命令不存在 | 没装 .NET SDK,或 PATH 未刷新 | 安装 .NET 8 SDK,重新打开终端 |
| 找不到 Zeus 包 | nuget.org 不可访问,或包名写错 | dotnet add package Zeus.Communications |
找不到 AddVirtualChannel | 没引用 Zeus.Communications | 安装或引用通信包 |
找不到 AttachZeus | 没引用 UI 适配器 | WinForms 引 Zeus.Presentation.WinForms,WPF 引 Zeus.Presentation.Wpf |
| WinForms / WPF 包还原失败 | 目标框架不是 Windows 桌面 | 改成 net8.0-windows |
宿主和名称
| 现象 | 最可能原因 | 处理 |
|---|---|---|
找不到名为 xxx 的通道 | Channels.Get 的名称和注册名称不一致 | 看异常里列出的已注册通道名 |
通道名称已存在 | 注册了两个同名通道 | 改名,例如 meterBus、plcBus |
当前为 Created,无法写入 | 还没调用 StartAsync | 先启动宿主 |
| 关闭程序后端口仍被占用 | 宿主没释放 | 使用 await using,或让 AttachZeus 管理窗口生命周期 |
串口和 TCP
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 串口打开失败 | COM 口不存在或被占用 | 看设备管理器,关闭串口助手 |
| 串口能打开但无数据 | 接线、波特率、校验位或设备未回包 | 先用串口助手确认设备能通信 |
| 收到乱码 | 把二进制协议当文本显示 | 用 Convert.ToHexString 看原始字节 |
| TCP 连接失败 | IP、端口、防火墙或设备未监听 | 先用网络工具确认端口可连 |
| 对端断开后通道 Faulted | TCP 连接被关闭 | 默认会自动重连;也可再次 OpenAsync |
自定义帧
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 超时未收到完整应答 | 帧头、长度、校验或设备没有回包 | 抓原始字节,对照设备手册 |
| 超时未收到匹配应答 | 收到的帧不满足匹配器 | 打印响应载荷,检查序号、命令字、地址 |
| 校验失败后一直没数据 | 校验算法或覆盖范围不一致 | 确认校验是否覆盖长度域和载荷 |
| 载荷超过 255 字节 | 使用了 1 字节长度 | 改用 2 字节长度字段 |
Modbus
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | 从站地址、波特率、RTU/TCP/ASCII 类型不对 | 先用 ModbusSlaveResponder 验证主站逻辑 |
非法数据地址 | 地址偏移或数量不对 | 检查 40001 是否要写成地址 0 |
| CRC 失败 | 串口参数不一致或线路干扰 | 核对 9600/8N1/校验位,缩短线缆测试 |
| 事务号不匹配 | 同一 TCP 通道并发多路请求 | 串行请求,或为不同任务拆通道 |
| 读到的值比例不对 | 少了比例换算 | 在点表中使用 scale 或 raw => raw * 0.1 |
Siemens S7
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | TCP 102 端口不通,或 rack / slot 不匹配 | 先确认 PLC 可连,再按 CPU 槽位调整 rack / slot |
| 握手成功但读 DB 失败 | DB 未下载、地址越界,或 PLC 开启了优化块访问 | 检查 DB 号和偏移;需要外部访问时关闭优化访问或使用兼容地址 |
| Bool 值不对 | bit 写错,或把字节偏移和位偏移混在一起 | address 写字节偏移,bit 只写 0–7 |
| Real / Int 数值异常 | 数据类型或字节序理解不一致 | S7 按大端解析;确认点的 dataType 和 PLC 变量类型一致 |
| 写 I 区失败 | S7 输入区只读 | 改写 DB、M 或 Q 区,并把点标为 writable: true |
| 没有真实 PLC 也想联调 | 程序结构依赖真实设备 | 使用 S7SlaveResponder 挂在虚拟通道上先验证逻辑 |
Omron FINS
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | UDP/TCP 9600 端口、节点号或网络号不对 | 先用 FinsSlaveResponder 跑通主站,再核对 PLC FINS 设置 |
| TCP 首次请求失败 | 节点地址握手被 PLC 拒绝 | 设置 TcpRequestedClientNode,或关闭握手并手动配置节点号 |
| 读到结束码 | 内存区、地址或数量不被 PLC 支持 | 看异常里的 FINS 结束码,核对 CPU 手册 |
| 32 位值高低字反了 | 字序和 PLC 工程约定不一致 | 改 FinsOptions.WordOrder |
Omron Host Link
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | 单元号、串口参数或 TCP 透传端口不对 | 先用 HostLinkSlaveResponder 跑通主站,再核对 PLC Host Link 设置 |
| FCS 校验失败 | 波特率、校验位或对端协议模式不一致 | 用通信追踪看原始 ASCII 帧,确认收到的是 @ 开头、*\r 结尾的 Host Link 帧 |
| 读到结束码 | 内存区、地址或数量不被 PLC 支持 | 看异常里的 Host Link 结束码,核对 CPU 手册 |
Panasonic MEWTOCOL
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | 站号、串口参数或 TCP 透传端口不对 | 先用 MewtocolSlaveResponder 跑通主站,再核对 PLC MEWTOCOL-COM 设置 |
| BCC 校验失败 | 波特率、校验位或对端协议模式不一致 | 用通信追踪看原始 ASCII 帧,确认收到的是 % 开头、\r 结尾的 MEWTOCOL 帧 |
| 读到错误码 | 内存区、地址或数量不被 PLC 支持 | 看异常里的 MEWTOCOL 错误码,核对 CPU 手册 |
| X 区写回失败 | X 外部输入区只读 | 改写 Y/R/L 或数据寄存器区,并把点标为 writable: true |
EtherNet/IP
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | TCP 44818 端口、防火墙或 PLC EtherNet/IP 服务不可达 | 先用 EtherNetIpSlaveResponder 跑通主站,再核对现场网络 |
CIP 状态 0x04 | 标签路径错误或标签不存在 | 核对 tag、Program 作用域和 PLC 工程里的标签名 |
| 类型不匹配 | 配置的 dataType 与 PLC 标签类型不同 | 按 PLC 工程类型设置 bool、int、dint、real 等 |
| 写回失败 | 标签只读或点未标记可写 | 确认 PLC 标签权限,并设置 .Writable(...) 或 writable: true |
DL/T 645
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | 表地址、波特率、校验位或前导 0xFE 数量不匹配 | 先用 Dlt645SlaveResponder 跑通主站,再核对表计通信参数 |
| 校验和错误 | 串口参数不一致、线路干扰或接入的不是 DL/T 645 | 用通信追踪看原始帧,确认 68 ... 68 开头、16 结尾 |
返回异常码 0x02 | 表计不支持该数据项标识 | 核对电表手册中的 DI,例如组合有功总电能常用 0x00000000 |
| 数值小数位不对 | scale 与数据项格式不一致 | 按手册调整 dataLength 和 scale,例如电能常用 4 字节、0.01 |
IEC104
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| STARTDT 后超时 | TCP 2404 端口、防火墙或公共地址不匹配 | 先用 Iec104SlaveResponder 跑通主站,再核对现场网关配置 |
| 总召唤无点值 | IOA 或 ASDU 类型和点表不一致 | 用通信追踪确认返回的 IOA,并检查 dataType 是否匹配 |
MQTT
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| CONNECT 超时 | Broker 地址、端口、防火墙或监听状态不对 | 先确认 TCP 1883 或现场端口可连,再检查 Broker 日志 |
| CONNACK 拒绝 | ClientId、用户名密码或协议版本不被接受 | 核对账号、ACL 和 MQTT 3.1.1 支持 |
| 已订阅但收不到消息 | 主题过滤器、ACL、系统主题规则或发布主题不一致 | 对照实际主题,注意普通 # 不匹配 $ 开头系统主题 |
| 点表解析失败 | 发布载荷与 dataType 不匹配 | 检查布尔、整数、双精度文本格式或改用 bytes |
| 断线后没有恢复 | 通道未重新进入 Open,或禁用了自动重连 | 检查 mqttAutomaticReconnect 和通道重连配置 |
OPC UA
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| HEL/ACK 超时 | TCP 4840、防火墙或 Server 未监听 | 先用 OpcUaServerResponder 跑通主站,再核对现场端口 |
| SecurityPolicy 被拒绝 | Server 未开放 None,或要求证书加密 | 在 Server 上允许 SecurityPolicy None,或单独沟通证书适配 |
| BadIdentityTokenInvalid | 匿名策略或用户名密码不匹配 | 核对 opcUaUsername / opcUaPassword |
| BadNodeIdUnknown | NodeId 文本与地址空间不一致 | 用 UaExpert 对照 ns= 和 s= / i= |
| 点表没有值 | 数据类型或首次采集失败 | 检查 dataType 和点表错误快照 |
点表和采集
| 现象 | 最可能原因 | 处理 |
|---|---|---|
点尚无有效值 | 第一轮采集还没成功 | 订阅 Points.Changed,或稍后再读 |
| 点名在多台设备上重复 | 短名冲突 | 使用 oven.temperature 这种限定名 |
| 界面显示旧值但有错误 | 本轮采集失败,保留了上一次成功值 | 查看点快照的 Error |
| 总线很慢 | 采集间隔太短或地址太分散 | 加大间隔,让地址尽量连续 |
| DataGrid 闪烁或界面卡 | 每个点变化都刷新整表 | 整表订 BatchChanged;桌面可用 AsTableBindingSource。几个 Label 仍订 Changed。对照见 点表与采集 |
JSON 配置
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 找不到配置文件 | 工作目录不对,或文件没复制到输出目录 | 看异常中的绝对路径,设置 CopyToOutputDirectory |
channel 未在 channels 中声明 | 设备引用了不存在的通道 | 先声明通道,再声明设备 |
| 改了 COM 口后手里的通道引用失效 | 热更新重建了通道实例 | 事件订阅会自动迁移;保存的 IChannel 请重新 Channels.Get |
| 改了采集间隔但没生效 | JSON 语法错误或没有监视文件 | 看日志,确认 watch: true |
WinForms / WPF
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 控件跨线程异常 | 直接在 DataReceived 中改 UI | WinForms 用 BindText / BindState,WPF 用 MVVM 绑定源 |
| 界面状态不刷新 | 没绑定状态,或绑定发生太晚 | WinForms 调用 BindState,WPF 绑定 ChannelBindingSource.StateText |
| 关闭窗口后仍在采集 | 宿主没跟窗口生命周期绑定 | 使用 this.AttachZeus(...) |
| 点击发送失败 | 通道还没打开 | 看状态 Label 是否为 Open |
仍然定位不了
也可以加入 QQ 群 771421105。提问时把下面这些信息一并带上:
- Zeus 版本和运行环境。
- 使用的是虚拟通道、串口、TCP 还是 UDP。
- 串口参数或 TCP/UDP 地址。
- 发送的原始字节和收到的原始字节。
- 完整异常消息,不要只截第一行。
- 如果是 Modbus,提供从站地址、功能码、起始地址和数量。