2. 状态机初始化流程:ec_init()、ec_config()、ec_config_map() 等 API 的调用顺序与作用
好,咱们直接进入正题。EtherCAT 主站的状态机初始化,说白了就是让主站和从站「握手」的过程。很多新手一上来就调 ec_send_processdata(),结果发现从站没反应——嗯,八成是初始化没走对。
我个人习惯把初始化分成三个阶段:打开网络、扫描拓扑、映射数据。这三个阶段对应三个核心 API,顺序不能乱,少一步都不行。
2.1 ec_init():打开网络接口
这是第一步,也是很多人容易忽略的一步。它的作用很简单——绑定一个网卡,让 SOEM 知道用哪个物理端口去发 EtherCAT 报文。
if (ec_init("eth0") == 0) {
printf("初始化失败,请检查网卡名称\n");
return -1;
}
这里有个坑:网卡名称在不同系统上不一样。Linux 下可能是 eth0、enp3s0,Windows 下可能是 \Device\NPF_{UUID}。我曾经在 Ubuntu 18.04 上折腾了半天,最后发现是网卡名写成了 enp3s0 但实际是 enp2s0——这种低级错误,排查起来最费时间。
2.2 ec_config():扫描并配置从站
这一步才是真正的「握手」。ec_config() 会遍历总线上的所有从站,读取它们的 EEPROM(即 ESI 文件中的信息),然后自动分配站地址。
int slave_count = ec_config(FALSE, &io_map);
if (slave_count <= 0) {
printf("未发现任何从站,请检查接线\n");
return -1;
}
printf("发现 %d 个从站\n", slave_count);
第一个参数 FALSE 表示不启用 DC(分布式时钟)。如果你需要同步运动控制,这里要传 TRUE。第二个参数 io_map 是一个指针,用来接收映射后的内存地址——这个后面会用到。
我记得有一次在现场调试,客户说「明明接了 5 个从站,怎么只读到 3 个?」后来发现是其中一个从站的终端电阻没拨对,导致总线信号反射,后面的从站根本收不到报文。所以,如果从站数量不对,先检查物理层,别急着怀疑代码。
2.3 ec_config_map():映射过程数据
这一步很多人觉得可有可无,其实不然。ec_config_map() 的作用是把从站的 PDO(过程数据对象)映射到主站的内存区域。说白了,就是告诉主站:「从站 A 的输入数据放在内存的 0x1000 位置,输出数据放在 0x2000 位置」。
int map_size = ec_config_map(&io_map);
if (map_size <= 0) {
printf("映射失败,请检查 PDO 配置\n");
return -1;
}
printf("映射完成,总数据大小: %d 字节\n", map_size);
这里要注意:ec_config_map() 必须在 ec_config() 之后调用。如果你先调了映射再扫描,那映射表里啥都没有——因为从站还没被发现呢。
我见过一个案例:有人把 ec_config_map() 的参数传成了 NULL,结果程序跑起来后,所有从站的数据都读不到。为什么?因为映射没成功,主站根本不知道从站的数据该往哪里放。所以,一定要检查返回值,别想当然。
2.4 完整的初始化流程
把上面三步串起来,就是一个标准的初始化流程。我一般会这样写:
// 第一步:打开网卡
if (ec_init("eth0") == 0) {
printf("网卡打开失败\n");
return -1;
}
// 第二步:扫描从站
int slave_count = ec_config(FALSE, &io_map);
if (slave_count <= 0) {
printf("未发现从站\n");
ec_close();
return -1;
}
// 第三步:映射过程数据
int map_size = ec_config_map(&io_map);
if (map_size <= 0) {
printf("映射失败\n");
ec_close();
return -1;
}
// 第四步:切换到 Operational 状态
ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE);
你可能会问:为什么最后还要调 ec_statecheck()?因为 ec_config() 只把从站带到 Pre-Op 状态,而我们要跑应用数据,必须进入 Operational 状态。这一步是显式地让所有从站进入运行态。
ec_readstate() 查看它的当前状态和错误码。错误码 0x0011 通常表示 PDO 映射不匹配——检查一下你的 ESI 文件和实际硬件是否一致。
2.5 状态机流程图
下面这张图是我手绘的初始化流程,你看一眼就能记住调用顺序:
2.6 常见错误与恢复
初始化过程中,最容易出问题的就是 ec_config() 这一步。我整理了一个表格,方便你对照排查:
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| ec_init() 返回 0 | 网卡名称错误 / 权限不足 | 检查 ifconfig,用 sudo 运行 |
| ec_config() 返回 0 | 物理连接断开 / 终端电阻未拨 | 检查网线、从站供电、终端电阻 |
| ec_config_map() 返回 0 | PDO 映射不匹配 / ESI 文件错误 | 重新生成 ESI,检查从站手册 |
| 从站卡在 Init 状态 | EEPROM 损坏 / 供电不足 | 更换从站或检查电源 |
好了,这一章的内容就到这里。记住这个流程,后面讲过程数据通信的时候,你会感谢自己把初始化搞扎实了。
公众号:蓝海资料掘金营,微信 deep3321