DC 配置
什么是 DC?
DC(分布式时钟)是 EtherCAT 的硬件级时间同步机制。它让网络中所有从站共享同一个时间基准,使各从站能在完全相同的时刻执行动作。
- 多轴同步运动 — 所有伺服驱动器在同一时刻更新位置指令,消除轴间抖动,轨迹插补更平滑
- IO 同步采样 — 所有输入输出在同一时刻,主站读取时数据一致,适合高速控制和测量
- 精确 I/O 时间戳 — 输入数据带有硬件时间戳,主站可精确知道采样发生的物理时刻
- 确定性输出 — 输出在固定时刻生效,不受 EtherCAT 帧到达时间的抖动影响
- 单个从站的 DC 配置请参见 从站 DC 同步
- DC 同步监控请参考 主站诊断 - DC 同步
属性
| 函数 | 类型 | 读写 | 说明 |
|---|---|---|---|
| GetSlaveHasDC(mi, si) | BOOL | 只读 | 单从站是否支持 DC |
| GetMasterDCTime(mi) | uint64_t | 只读 | 主站 DC 系统时间(纳秒,2000-01-01 纪元) |
| GetReferenceClockSlave(mi) | uint16_t | 只读 | 参考时钟从站索引(1-based),0=无 DC |
方法
ConfigureDCAll()
int ConfigureDCAll(uint16_t master_index, uint32_t sync0_ns, uint32_t sync1_ns);
int AutoCalculateDCShift(uint16_t master_index);
void SetMasterDCCycleTime(uint16_t master_index, uint32_t time_ns);
void SetMasterLoopCycleTime(uint16_t master_index, uint32_t time_ns);
ConfigureDCAll() 为所有 DC 从站配置 DC 同步(参数单位纳秒),内部自动完成传播延迟测量、偏移计算、SYNC0/SYNC1 写入。sync0_ns=0 表示禁用 DC,sync1_ns 是相对于 SYNC0 的增量时间。AutoCalculateDCShift() 基于传播延迟自动计算每个 DC 从站的最优相位偏移。返回成功配置的从站数。
示例:
dll.SetMasterLoopCycleTime(master, 125000); /* PDO 周期 125μs (WDK 推荐) */
int n = dll.ConfigureDCAll(master, 125000, 0);
dll.AutoCalculateDCShift(master);
printf("配置了 %d 个 DC 从站\n", n);
- SYNC0 与 LoopCycle 应保持一致或为其整数倍
- 过采样例外 — Oversampling 设备 SYNC0 < LoopCycle,需设备硬件和 PDO 映射专门支持
SetSyncBySlaveIndex()
void SetSyncBySlaveIndex(uint16_t master_index, uint16_t slave_index,
uint32_t sync0_ns, uint32_t sync1_ns, int32_t shift_ns);
配置单个从站的 DC 同步参数(shift_ns 相位偏移)。仅在需要对个别从站设置不同参数时使用。
EnableContinuousMeasurement()
void EnableContinuousMeasurement(uint16_t master_index, BOOL enable, uint32_t interval_sec);
启用或禁用持续传播延迟测量(ETG.1500 5.13.2)。启用后主站定期重新测量传播延迟,适用于温度漂移等导致延迟变化的场景。interval_sec=0 使用默认间隔。
示例:
dll.EnableContinuousMeasurement(master, TRUE, 60); /* 每 60 秒重新测量 */
默认情况下 DC 偏移在 ConfigureDCAll() 时一次性计算。仅在长时间运行且环境温度变化较大时启用此功能。
传播延迟
int UpdatePropagationDelays(uint16_t master_index);
int32_t GetSlavePropagationDelay(uint16_t master_index, uint16_t slave_index);
int32_t GetMaxPropagationDelay(uint16_t master_index);
UpdatePropagationDelays() 触发一次全网传播延迟测量。GetSlavePropagationDelay() 返回单从站延迟(纳秒),GetMaxPropagationDelay() 返回网络最大延迟。
同步窗口监控
主站每秒自动检查各 DC 从站的时间偏差。当从站偏差超出 SyncWindowThreshold 阈值时触发 DCSyncLost 回调。
void SetSyncWindowThreshold(uint16_t master_index, int threshold_ns);
int GetSyncWindowThreshold(uint16_t master_index);
阈值默认 1000ns。
GetMaxSyncDifference()
int GetMaxSyncDifference(uint16_t master_index);
获取所有 DC 从站中的最大时间偏差(纳秒),失败返回 -1。
IsAllSlavesInSync()
BOOL IsAllSlavesInSync(uint16_t master_index);
检查所有 DC 从站是否都在同步窗口内(偏差 ≤ SyncWindowThreshold)。
GetSlaveSyncWindowStatus()
BOOL GetSlaveSyncWindowStatus(uint16_t master_index, uint16_t slave_index,
int* diff_ns, int* max_diff_ns, int* min_diff_ns,
BOOL* in_sync, uint32_t* out_of_sync_count);
获取从站的 DC 同步窗口详细状态:当前偏差、历史最大/最小偏差、是否在同步窗口内、累计失同步次数。
ResetAllSyncWindowStats()
void ResetSlaveSyncWindowStats(uint16_t master_index, uint16_t slave_index);
重置单从站同步窗口统计。遍历所有从站调用此函数可实现全局重置。
DC 漂移补偿
EnableDriftCompensation()
void EnableDriftCompensation(uint16_t master_index, BOOL enable,
int32_t threshold_ns, int32_t gain);
启用或禁用 DC 漂移补偿。漂移补偿在主站侧持续修正系统时钟与 DC 参考时钟之间的偏差,防止长时间运行后同步精度下降。
参数:
threshold_ns— 触发补偿的偏差阈值(纳秒),偏差低于此值时不做修正,推荐 1000gain— 补偿增益(控制修正速率,越大修正越快但可能引入振荡),推荐 512
/* 推荐参数 */
dll.EnableDriftCompensation(master, TRUE, 1000, 512);
/* 自定义: 500ns 阈值, 较低增益 (更平滑) */
dll.EnableDriftCompensation(master, TRUE, 500, 256);
/* 禁用 */
dll.EnableDriftCompensation(master, FALSE, 0, 0);
对于长时间运行的系统(>24小时),建议启用漂移补偿。默认参数适合大多数场景。
主站当前 DC 时间查询
主站每个 PDO 周期会通过 FRMW (Feed-Read-Multiple-Write) 从参考时钟从站取回 64 位 DC 系统时间。SDK 将该时间戳暴露给应用层, 用于:
- 日志时间对齐 — 应用层日志可用 DC 时间打戳, 与从站侧事件 (EMCY / Diagnosis History) 时间轴严格对齐
- 跨站事件关联 — 多从站同时上报事件时, 基于 DC 时间可判断绝对先后
- 漂移诊断 — 与本机墙上时钟或外部 NTP 做差值, 观察时钟漂移趋势
DC 时间单位为纳秒, 起算点为 2000-01-01 00:00:00 UTC (ETG 规范定义)。与 UNIX 时间戳有 30 年偏移, 换算时注意。
GetMasterDCTime()
uint64_t GetMasterDCTime(uint16_t master_index);
uint16_t GetReferenceClockSlave(uint16_t master_index);
GetMasterDCTime() 返回主站当前的 64 位 DC 系统时间(纳秒),0 表示 DC 尚未激活或无参考时钟。GetReferenceClockSlave() 返回参考时钟从站索引(1-based),由 SDK 在 configdc 阶段自动选为链路上第一个支持 DC 的从站。
示例:
uint16_t ref = dll.GetReferenceClockSlave(master);
if (ref == 0) {
printf("网络无 DC 从站\n");
} else {
uint64_t now = dll.GetMasterDCTime(master);
printf("参考时钟: 从站 %u, DC 时间 = %llu ns\n",
ref, (unsigned long long)now);
}
每个 PDO 周期由 FRMW 报文更新一次,分辨率 = LoopCycle。主站返回的是最近一次回读值,不会自己推算增量。实际事件时间戳请优先使用从站本地的 Latch 寄存器。
完整示例
125μs 高性能(WDK 驱动)
#define DYNAMIC_LOAD
#include "ethercat.h"
#include <stdio.h>
static void on_dc_lost(uint16_t mi, uint16_t si, int diff) {
printf("从站 %d DC 同步丢失: 偏差 %dns\n", si, diff);
}
int main(void) {
dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");
uint16_t master = dll.Initialize();
dll.SetNetwork(master, "\\Device\\NPF_{GUID}", "");
/* 1. 配置周期 + DC */
dll.SetMasterLoopCycleTime(master, 125000);
int dc_count = dll.ConfigureDCAll(master, 125000, 0);
dll.AutoCalculateDCShift(master);
printf("配置了 %d 个 DC 从站\n", dc_count);
/* 2. 同步窗口阈值 + 监听 */
dll.SetSyncWindowThreshold(master, 500);
dll.SetDCSyncLostCallback(on_dc_lost);
/* 3. 启动到 OP */
dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000);
dll.Start(master);
/* 4. 检查同步状态 */
printf("所有从站同步: %s\n",
dll.IsAllSlavesInSync(master) ? "是" : "否");
printf("最大同步偏差: %d ns\n",
dll.GetMaxSyncDifference(master));
getchar();
dll.Stop(master);
dll.Dispose(master);
UNLOAD_DLL(&dll);
return 0;
}
持续测量与漂移补偿
/* 长时间运行:启用持续传播延迟测量(温度漂移补偿) */
dll.EnableContinuousMeasurement(master, TRUE, 60);
/* 启用漂移补偿 */
dll.EnableDriftCompensation(master, TRUE, 1000, 512);
/* 同步窗口监控 */
if (!dll.IsAllSlavesInSync(master)) {
int max_diff = dll.GetMaxSyncDifference(master);
printf("同步偏差过大: %d ns\n", max_diff);
}