DL/T 645
Zeus 的 DL/T 645 模块面向电能表和能耗采集设备,支持 DL/T 645-2007 常用数据项读取与写入。协议层已经处理表地址反序、帧前导 0xFE、双 0x68 帧头、0x33 数据偏移、校验和、异常码,以及低字节在前的 BCD 数据解码。
无硬件先跑通
const string meterAddress = "000000000001";
var memory = new Dlt645SlaveMemory();
memory.SetBcd(0x00000000, 1234.56, byteLength: 4, scale: 0.01);
memory.SetBcd(0x02010100, 220.5, byteLength: 2, scale: 0.1);
await using var app = ZeusHost.Create(builder =>
{
builder.AddVirtualChannel("meter-link", new Dlt645SlaveResponder(meterAddress, memory));
builder.AddDlt645(
"meter",
"meter-link",
new Dlt645Options { MeterAddress = meterAddress, WakeUpPreambleCount = 0 },
points: map => map
.Bcd("energy", 0x00000000, dataLength: 4, scale: 0.01)
.Bcd("voltageA", 0x02010100, dataLength: 2, scale: 0.1));
});
await app.StartAsync();
| 组件 | 含义 |
|---|---|
Dlt645SlaveMemory | 虚拟表计的数据项映像,键是四字节 DI |
Dlt645SlaveResponder(address, memory) | 模拟一个指定表地址的 DL/T 645 表计 |
AddDlt645("meter", "meter-link", options) | 在已有通道上登记 DL/T 645 设备 |
.Bcd("energy", 0x00000000, 4, 0.01) | 把组合有功总电能数据项映射成点表点 |
可运行示例:samples/Zeus.Samples.Console.Dlt645。
接真实表计
DL/T 645 通常走 RS-485 串口。通道只负责收发字节,表地址和协议帧由 Dlt645Device 处理:
await using var app = ZeusHost.Create(builder =>
{
builder.AddSerialPort("meter-link", "COM3", 2400);
builder.AddDlt645(
"meter",
"meter-link",
new Dlt645Options
{
MeterAddress = "000000000001",
WakeUpPreambleCount = 4
},
points: map => map.TotalActiveEnergy("energy"));
});
一些 TCP/串口服务器会透传 DL/T 645 帧,这时把通道换成 TCP 即可:
builder.AddTcpClient("meter-link", "192.168.1.50", 5000);
builder.AddDlt645("meter", "meter-link", new Dlt645Options { MeterAddress = "000000000001" });
直接读写数据项
var meter = app.Devices.Get<Dlt645Device>("meter");
var energy = await meter.ReadBcdAsync(0x00000000, byteLength: 4, scale: 0.01);
var voltageA = await meter.ReadBcdAsync(0x02010100, byteLength: 2, scale: 0.1);
var raw = await meter.ReadDataAsync(0x04000401);
await meter.WriteBcdAsync(0x04000101, 88.8, byteLength: 2, scale: 0.1);
ReadDataAsync 返回的数据不含四字节 DI,也不含协议里的 0x33 偏移。BCD 数值按低字节在前解析,例如 4 字节、scale: 0.01 常用于 XXXXXX.XX 格式电量。
点表采集
builder.AddAcquisition(TimeSpan.FromSeconds(1));
builder.AddDlt645("meter", "meter-link", new Dlt645Options { MeterAddress = "000000000001" }, points: map => map
.Bcd("energy", 0x00000000, dataLength: 4, scale: 0.01, alarmLimits: new PointAlarmLimits(high: 10000))
.Bcd("voltageA", 0x02010100, dataLength: 2, scale: 0.1)
.RawBytes("status", 0x04000401, dataLength: 1));
| 点类型 | 点表值 | 说明 |
|---|---|---|
Bcd | double | 按 scale 换算后的工程值,支持报警限和写回 |
RawBytes | byte[] | 保留原始数据字节,适合状态字或厂家扩展数据项 |
常用快捷方法:
map.TotalActiveEnergy("energy"); // DI 00000000, 4 字节, 0.01 kWh
map.VoltageA("voltageA"); // DI 02010100, 2 字节, 0.1 V
map.CurrentA("currentA"); // DI 02020100, 3 字节, 0.001 A
JSON 配置
{
"channels": [
{
"name": "meter-link",
"type": "serial",
"portName": "COM3",
"baudRate": 2400
}
],
"devices": [
{
"name": "meter",
"channel": "meter-link",
"type": "dlt645",
"meterAddress": "000000000001",
"wakeUpPreambleCount": 4,
"points": [
{ "name": "energy", "address": "0x00000000", "dataType": "bcd", "dataLength": 4, "scale": 0.01 },
{ "name": "voltageA", "address": "0x02010100", "dataType": "bcd", "dataLength": 2, "scale": 0.1 },
{ "name": "status", "address": "0x04000401", "dataType": "raw", "dataLength": 1 }
]
}
]
}
无硬件联调时,把通道换成:
{
"name": "meter-link",
"type": "virtual",
"responder": "dlt645",
"meterAddress": "000000000001"
}
可直接复制的配置样例位于 samples/Zeus.Samples.Console.Config/zeus-dlt645.json。
常见数据项
| 数据项 | 常见含义 | 建议声明 |
|---|---|---|
0x00000000 | 当前组合有功总电能 | dataLength: 4, scale: 0.01 |
0x02010100 | A 相电压 | dataLength: 2, scale: 0.1 |
0x02020100 | A 相电流 | dataLength: 3, scale: 0.001 |
不同厂家会扩展数据项,最终以表计通信规约或点表手册为准。
排错
| 现象 | 最可能原因 | 处理 |
|---|---|---|
| 一直超时 | 表地址、波特率、校验位或前导 0xFE 数量不匹配 | 先用虚拟表计跑通,再对照现场参数 |
| 校验和错误 | 串口参数不一致或线路干扰 | 打开通信追踪,确认原始帧和校验范围 |
异常码 0x02 | 表计没有该数据项 | 核对数据项 DI 和表计型号 |
| 数值差 10/100 倍 | scale 不匹配 | 按手册调整 scale 和 dataLength |