3. EtherCAT主站状态机初始化与从站状态转换
状态机转换的核心对象与顺序
EtherCAT 从站上电后处于 INIT 状态,主站必须按 INIT → PREOP → SAFEOP → OP 的顺序逐级请求,每级都通过写 AL Control(0x0120)寄存器发起,再轮询 AL Status(0x0130)确认从站真正进入目标状态。跳级或逆序请求会被从站拒绝,并在 AL Status Code 中给出错误码。
本案例针对单个从站,用主站依次发起三次状态请求,记录每次从请求发出到状态位匹配的耗时,并读取 AL Status Code 判断是否出错。关键寄存器与状态编码如下:
| 对象 | 地址/取值 | 含义 |
|---|---|---|
| AL Control | 0x0120 | 主站写入目标状态请求 |
| AL Status | 0x0130 | 从站当前状态 + 错误标志 |
| AL Status Code | 0x0134 | 转换失败时的错误码 |
| INIT | 0x01 | 初始状态,无过程数据通信 |
| PREOP | 0x02 | 可访问邮箱,可读写 SDO |
| SAFEOP | 0x04 | 过程数据输入有效,输出保持安全值 |
| OP | 0x08 | 过程数据输入输出全部有效 |
主站初始化流程实现
下面用一段可运行的伪代码结构展示主站如何依次请求状态并记录耗时。实际工程中,寄存器读写通过主站库(如 SOEM 的 ec_readstate/ec_writestate 或 IgH EtherCAT Master 的 ecrt_master_slave_config 接口)完成,这里用 readReg/writeReg 抽象表示。
// 目标状态序列
const uint8_t STATE_SEQ[3] = {0x02, 0x04, 0x08}; // PREOP, SAFEOP, OP
const char* STATE_NAME[3] = {"PREOP", "SAFEOP", "OP"};
// 单次状态转换:请求 + 轮询确认 + 耗时记录
int transitionTo(uint16_t slave, uint8_t target, double* elapsed_ms) {
struct timespec t0, t1;
clock_gettime(CLOCK_MONOTONIC, &t0);
writeReg(slave, 0x0120, target); // 写 AL Control
uint16_t status;
do {
status = readReg(slave, 0x0130); // 读 AL Status
if (status & 0x0010) { // 错误标志位
uint16_t code = readReg(slave, 0x0134);
printf(" 错误: AL Status Code = 0x%04X\n", code);
return -1;
}
usleep(1000); // 1ms 轮询间隔
} while ((status & 0x000F) != target); // 状态位匹配
clock_gettime(CLOCK_MONOTONIC, &t1);
*elapsed_ms = (t1.tv_sec - t0.tv_sec) * 1000.0
+ (t1.tv_nsec - t0.tv_nsec) / 1e6;
return 0;
}
// 主初始化流程
void initSlave(uint16_t slave) {
double total = 0.0;
for (int i = 0; i < 3; i++) {
double ms = 0.0;
printf("请求 %s ... ", STATE_NAME[i]);
if (transitionTo(slave, STATE_SEQ[i], &ms) == 0) {
printf("成功, 耗时 %.2f ms\n", ms);
total += ms;
} else {
printf("失败\n");
return;
}
}
printf("总耗时: %.2f ms\n", total);
}
运行与结果判读
在从站正常上电、邮箱配置正确的前提下,典型观察结果是:INIT→PREOP 耗时通常在几毫秒到几十毫秒(取决于邮箱初始化),PREOP→SAFEOP 和 SAFEOP→OP 通常更快,因为过程数据通道已建立。若某一步耗时异常长或返回错误码,可按以下方向排查:
- 0x0011:检查是否跳过了中间状态,必须严格按 INIT→PREOP→SAFEOP→OP 顺序。
- 0x0016:邮箱通信未就绪,检查 EEPROM 中邮箱配置是否与主站一致。
- 0x0024:过程数据看门狗超时,检查 SAFEOP→OP 时 PDO 映射和看门狗时间设置。
耗时记录建议使用单调时钟(CLOCK_MONOTONIC),避免系统时间调整影响测量。轮询间隔不宜过短,1ms 是常见折中值,既能快速响应又不会占满总线。
验证清单
| 检查项 | 通过条件 |
|---|---|
| 状态顺序 | 三次请求依次为 0x02、0x04、0x08,无跳级 |
| 状态确认 | 每次轮询到 AL Status 低 4 位等于目标值 |
| 错误标志 | 转换过程中 AL Status 的 bit4 始终为 0 |
| 耗时记录 | t1、t2、t3 均有数值,且 t_total = t1+t2+t3 |
| 错误码 | 若失败,AL Status Code 非 0x0000 且可对应到具体原因 |