点表与采集
点表就是把设备里的寄存器、线圈或其它数据,命名成业务能理解的点。比如把 Modbus 地址 0 命名为 temperature。
采集循环就是 Zeus 按固定间隔帮你读取这些点。你不需要自己写 while true、Task.Delay、重试和界面刷新。
先看完整例子
var memory = new ModbusSlaveMemory();
memory.HoldingRegisters[0] = 185;
memory.HoldingRegisters[1] = 200;
await using var app = ZeusHost.Create(builder =>
{
builder.AddAcquisition(TimeSpan.FromMilliseconds(500));
builder.AddVirtualChannel("bus", new ModbusSlaveResponder(1, ModbusTransport.Rtu, memory));
builder.AddModbusRtu("oven", "bus", unitId: 1, points: map =>
{
map.HoldingRegister("temperature", 0, raw => raw * 0.1);
map.HoldingRegister("setpoint", 1, raw => raw * 0.1);
map.Coil("heater", 2);
});
});
app.Points.Changed += (_, e) =>
{
Console.WriteLine($"{e.Current.QualifiedName} = {e.Current.Value}");
};
await app.StartAsync();
var temperature = app.Points.Get<double>("temperature");
这段代码怎么理解
| 代码 | 含义 |
|---|---|
AddAcquisition(500ms) | 每 500 ms 采集一轮 |
HoldingRegister("temperature", 0, raw => raw * 0.1) | 地址 0 的保持寄存器叫 temperature,原始值乘以 0.1 |
Coil("heater", 2) | 地址 2 的线圈叫 heater |
app.Points.Changed | 点值或错误变化时触发 |
app.Points.Get<double>("temperature") | 读取当前最新温度 |
为什么不要自己写循环
你当然可以自己写:
while (true)
{
var values = await oven.ReadHoldingRegistersAsync(0, 2);
await Task.Delay(500);
}
但实际项目很快会遇到:
- 多个点地址连续,应该合并读取。
- 某轮读取失败,界面还要保留上一次成功值。
- 多个设备需要统一间隔。
- UI 要订阅变化,而不是到处主动拉取。
Zeus 的点表采集就是为这些场景准备的。
点名怎么查
如果整个宿主里只有一个 temperature,可以直接写:
var value = app.Points.Get<double>("temperature");
如果多台设备都有 temperature,使用完整名:
var ovenTemperature = app.Points.Get<double>("oven.temperature");
var tankTemperature = app.Points.Get<double>("tank.temperature");
尚无有效值怎么办
StartAsync 返回后,第一轮采集可能还在进行。稳妥写法是订阅变化:
app.Points.Changed += (_, e) =>
{
if (e.Current.Error is null)
{
Console.WriteLine($"{e.Current.QualifiedName} = {e.Current.Value}");
}
else
{
Console.WriteLine($"{e.Current.QualifiedName} 采集失败:{e.Current.Error.Message}");
}
};
或者使用 TryGet:
if (app.Points.TryGet<double>("temperature", out var value))
{
Console.WriteLine(value);
}
绑定到界面
WinForms / WPF 都可以直接绑定点:
app.Points.BindTo("temperature", temperatureLabel, value => $"{value:F1} ℃");
这样界面只关心显示格式,不需要关心采集线程和设备协议。
采集优化
Zeus 会尽量把同一设备上连续的地址合并读取。
| 点声明 | 读取效果 |
|---|---|
| 地址 0、1、2 连续 | 可以合并成一次读取 |
| 地址 0、100 分散 | 通常需要分开读取 |
| 不同设备 | 分别按设备读取 |
总线较慢时,优先让常用点地址连续,并适当加大采集间隔。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
尚无有效值 | 第一轮采集还没成功 | 订阅 Changed,或稍后再 Get |
| 点名冲突 | 多台设备有同名点 | 使用 设备名.点名 |
| 界面值不更新 | 没声明点,或采集循环没启用 | 确认 AddAcquisition 和 points 都写了 |
| 某轮失败但界面还有旧值 | Zeus 保留上一次成功值 | 查看点快照里的 Error |
| 总线被采集打满 | 间隔太短或地址太分散 | 加大间隔,合并连续地址 |
下一步:把点表写进文件看 JSON 配置。