错误处理
EtherCAT 通信中的错误处理策略和常见故障排查。
错误类型
| 类型 | 来源 | 处理方式 |
|---|---|---|
| AL Status Code | 从站状态转换失败 | 通过 GetSlaveALStatusCode() 读取,使用 diagnostics_classify_al_error() 分类 |
| SDO Error | CoE 读写失败 | SDOread() 返回 NULL,错误码见 SDO Abort |
| PDO 丢帧 | 通信异常 | 通过 PDOFrameLoss 回调 监控 |
| Emergency | 从站硬件/固件错误 | 通过 Emergency 回调 接收 |
| 状态降级 | 从站异常回退 | 通过 StateChanged 回调 监控 |
错误类型枚举:
typedef enum {
EC_ERROR_FRAME_LOST = 0, /* 帧丢失 */
EC_ERROR_OUT_OF_ORDER = 1, /* 帧顺序错误 */
EC_ERROR_CHECKSUM = 2, /* 校验和错误 */
EC_ERROR_TIMEOUT = 3, /* 超时 */
EC_ERROR_WKC_MISMATCH = 4, /* 工作计数器不匹配 */
EC_ERROR_LINK_LOST = 5 /* 链路丢失 */
} ec_error_type_t;
状态转换错误
检测方式
if (!dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000)) {
printf("状态转换失败\n");
for (uint16_t i = 1; i <= slave_count; i++) {
uint16_t al = dll.GetSlaveALStatusCode(master, i);
uint8_t st = dll.GetSlaveState(master, i);
if (al != 0)
printf("从站 %d: 状态=0x%02X, 错误码=0x%04X\n", i, st, al);
}
}
错误分类
使用 diagnostics_classify_al_error() 快速判断处理策略:
DarraAlErrorClass cat = diagnostics_classify_al_error(al_code);
switch (cat) {
case AL_ERROR_TRANSIENT:
/* 重试状态转换 */
break;
case AL_ERROR_CONFIGURATION:
/* 检查 PDO 映射、SM 配置 */
break;
case AL_ERROR_HARDWARE:
/* 检查从站设备、线缆、电源 */
break;
}
详细分类
完整的 AL 错误分类和常见错误码请参考 主站诊断 - AL 错误分类。
常见 AL Status Code
0x001E无效输入映射 — 检查 PDO 映射配置是否与从站支持的映射一致0x001D无效输出映射 — 检查 PDO 输出映射配置0x0017无效 SM 配置 — 检查 SyncManager 配置(大小、方向)0x001BSM 看门狗超时 — PDO 周期过慢或通信中断0x002D同步错误 — DC 同步配置问题,检查 SYNC0 周期0x0032DC 同步超时 — DC 启动时间配置问题0x0003无效设备设置 — 耦合器无物理模块,或模块配置不匹配
事件驱动的异常处理
推荐通过事件监控异常,而非轮询:
static void on_state_change(uint16_t mi, uint16_t si, int old_s, int new_s) {
if (new_s < old_s) printf("从站 %d 状态降级: %d -> %d\n", si, old_s, new_s);
}
static void on_discovery(uint16_t mi, uint16_t si, BOOL is_found) {
printf("从站 %d %s\n", si, is_found ? "上线" : "离线");
}
static void on_frame_loss(uint16_t mi, uint8_t grp, uint32_t cons, uint32_t total) {
if (cons > 10) printf("组 %d 严重丢帧: 连续 %u 帧\n", grp, cons);
}
static void on_emergency(uint16_t mi, uint16_t si,
uint16_t err, uint16_t reg, uint8_t b1, uint16_t w1, uint16_t w2) {
printf("从站 %d 紧急消息: 0x%04X\n", si, err);
}
dll.RegisterStateChangeSync(on_state_change);
dll.RegisterDiscoverySync(on_discovery);
dll.RegisterPDOFrameLoss(on_frame_loss);
dll.RegisterEmergency(on_emergency);
自动日志
所有事件(PDO 周期回调除外)触发时系统均自动记录日志,无论是否订阅。详见 事件。
常见故障排查
初始化失败
- 管理员权限不足 → 以管理员身份运行
- 网卡名称不匹配 → 检查
GetNetworkInfo()返回的网口列表 - 无从站响应 → 检查网线连接和从站供电
从站无法进入 OP
- PDO 映射不匹配 → 检查
GetSlaveALStatusCode(),常见 0x001E/0x001D - ESI 版本不匹配 → 使用与固件版本对应的 ESI 文件
- DC 同步失败 → 检查 DC 配置,确认 SYNC0 周期合理
- SM 配置错误 → 检查 SyncManager 大小和方向
- 缺少启动参数 → 使用
AddStartupParameter()添加
通信不稳定
- 丢帧率高 → 检查网线质量、交换机端口、EMI 干扰
- 抖动大 → 安装 DarraRT 驱动,隔离 CPU 核心
- 偶尔超时 → 检查系统负载,关闭不必要的后台进程
- DC 同步偏差大 → 使用 DarraRT 驱动降低抖动
日志系统
static void on_log(int category, const char* message) {
const char* level[] = {"ERROR", "WARN", "INFO", "MBX", "PDO", "DEBUG"};
printf("[%s] %s\n", level[category], message);
}
dll.SetLogCallback(on_log);
dll.SetDebugLogging(TRUE);
dll.SetMailboxLogging(TRUE);
dll.SetPDOLogging(TRUE);
日志类别 (category):
| 值 | 名称 | 默认 | 说明 |
|---|---|---|---|
| 0 | ERROR | 始终输出 | 致命错误 / 状态转换失败 / 不可恢复故障 |
| 1 | WARN | 始终输出 | 重试 / 单帧丢失 / 配置问题等可恢复警告 |
| 2 | INFO | 始终输出 | 状态变化 / 启动参数应用 / 主流程消息 |
| 3 | MBX | SetMailboxLogging 控制 | CoE/SoE/FoE 邮箱收发追踪 |
| 4 | PDO | SetPDOLogging 控制 | PDO 周期级别详细日志 (高频) |
| 5 | DEBUG | SetDebugLogging 控制 | 调试与诊断输出 |
PDO 日志开销
启用 PDO 日志后每周期均会调用日志回调 (1ms 周期下约 1000 次/秒), 仅在排障时短时开启, 完成后立即关闭。
日志详情
日志系统详见 日志。
协议错误码参考
CoE SDO Abort 码 (主要):
| 码 | 含义 |
|---|---|
| 0x05030000 | Toggle bit 不一致 |
| 0x05040000 | SDO 协议超时 |
| 0x06010000 | 不支持的访问 |
| 0x06010002 | 对只读对象执行写 |
| 0x06020000 | 对象不存在 |
| 0x06070010 | 数据类型/长度不匹配 |
| 0x06090011 | 子索引不存在 |
| 0x06090030 | 数值超出范围 |
| 0x08000022 | 当前设备状态不允许传输 |
FoE 错误码:
| 码 | 含义 |
|---|---|
| 0x00008001 | 无效操作码 / 未实现 |
| 0x00008002 | 文件未找到 |
| 0x00008003 | 非法文件名 |
| 0x00008005 | 磁盘空间不足 |
| 0x00008006 | 校验失败 |
SoE 错误码 (ETG.1020):
| 码 | 含义 |
|---|---|
| 0x1001 | 无效命令 |
| 0x1009 | IDN 不存在 |
| 0x3002 | 无效数据大小 |
| 0x4001 | 元素属性不可写 |
| 0x6001 | 数据超出范围 |
| 0x7002 | 写入失败 |
异步任务错误码:
| 常量 | 值 | 说明 |
|---|---|---|
| ASYNC_OK | 0 | 操作成功 |
| ASYNC_ERR_PARAM | -1 | 参数非法 |
| ASYNC_ERR_OOM | -2 | 内存分配失败 |
| ASYNC_ERR_OS | -3 | 底层 OS 调用失败 |
| ASYNC_ERR_TIMEOUT | -4 | 等待超时, 可重试 |
| ASYNC_ERR_DETACHED | -5 | 已 detach 的句柄不能再 join |
| ASYNC_ERR_NOT_RUN | -6 | 任务未启动或已 join |