外观
EtherCAT LVGL 示例
2025-10-29
本文将介绍如何基于 睿擎工业开发平台 实现在 MIPI 接口的显示屏上进行 EtherCAT 应用开发学习,以开发板作为主机,与伺服控制器进行通信,通过显示屏进行伺服电机的位置控制,需要开发者对 EtherCAT 基础知识有一定的了解。
EtherCAT 控制电机示例
本示例通过 LVGL + EtherCAT 示例,完成对 EtherCAT 伺服控制器和远程 IO 的初始化配置,使伺服电机控制器工作在 CSP 模式。在 EtherCAT 主站过程数据同步回调函数中,实现对电机的位置控制,并循环输出电平给远程 IO 设备,让 IO 设备输出流水灯的效果。在显示屏上还可以观察到电机此时的期望位置、当前位置,通过控制显示屏的运行开关以及位置滑块,就可以控制电机到达指定位置。
硬件准备
- 睿擎工业开发平台支持 7 寸显示屏一套
- 睿擎工业开发平台支持板卡 1 块(推荐
睿擎派 RC3506) - EtherCAT 伺服驱动器一套(推荐
力川 LC10E-400W) - EtherCAT 远程 IO 一套(可选,16DI 16DO)
- 串口调试器、jlink 调试各一套
硬件连接
警告
必须在断电状态下进行连接操作
1.电机连接
用网线将伺服控制器 IN 口与开发板 ETH0 网口连接,并将远程 IO 模块的 IN 口连接到伺服控制器的 OUT 口。伺服电机的电源线和编码器线分别接入电源口和 CN3 连接口。如图所示:

2.显示屏连接
开发板的 mipi 接口和显示屏的接口连接好,开发板 MIPI 接口位置如图所示:

注意接口防呆设计,确保方向正确,轻轻锁紧连接器扣具。

创建工程点击展开
依次点击 “文件” -> “新建” -> "RT-Thread RuiChing App 项目"。

在弹出新建向导中选择 开发版 、BSP: 、示例 、 调试器/下载器。选择好之后点击 “完成”。

点击 “完成” 后,等待工程创建完成。

创建完成。

构建工程点击展开
单击工程使工程进入 Active-Debug 模式。

点击工具栏上的构建按钮进行工程编译。

构建成功后,会显示构建成功的信息。

固件下载点击展开
固化设备树

固化 APP

核心示例代码
- LVGL 线程启动和 EtherCAT 初始化
applications/ethercat_domain.c
int main(void)
{
rt_kprintf("Hello, RT-Thread app\n");
lvgl_thread_init();
ethercat_domain_init();
return 0;
}- EtherCAT lc_csp_mode 函数
ethercat_domain.c
static int lc_csp_mode(const char *ifname)
{
int slave_counts;
uint16_t state;
rt_err_t err;
ecat_service_init();
if (ifname)
{
csp_master.nic0 = ifname;
}
err = ecat_master_init(&csp_master);
if (err)
{
rt_kprintf("ethercat master init failed, err:%d\n", err);
return err;
}
err = ecat_config_init(&csp_master, RT_FALSE);
if (err)
{
rt_kprintf("ethercat master init failed, err:%d\n", err);
return err;
}
slave_counts = ecat_slavecount(&csp_master);
rt_kprintf("Found slaves count:%d\n", slave_counts);
err = ecat_write_state(&csp_master, 0, EC_STATE_PRE_OP);
if (err)
{
rt_kprintf("ecat_write_state PRE_OP failed\n");
return err;
}
state = EC_STATE_PRE_OP;
err = ecat_check_state(&csp_master, 0, &state, 2000000 * 3);
if (err != RT_EOK)
{
rt_kprintf("Not all slaves reached PRE_OP state.\n");
return err;
}
ecat_config_dc(&csp_master);
lc_pdo_config(&csp_master);
err = ecat_config_map_group(
&csp_master, (void *)(csp_master.process_data), 0);
if (err != RT_EOK)
{
rt_kprintf("ecat_config_map_group failed\n");
return err;
}
err = ecat_write_state(&csp_master, 0, EC_STATE_SAFE_OP);
if (err != RT_EOK)
{
rt_kprintf("ecat_write_state PRE_OP failed\n");
return err;
}
state = EC_STATE_SAFE_OP;
err = ecat_check_state(&csp_master, 0, &state, 20000000 * 3);
if (err != RT_EOK)
{
rt_kprintf("Not all slaves reached SAFE_OP state.%d\n", err);
return err;
}
err = ecat_write_state(&csp_master, 0, EC_STATE_OPERATIONAL);
if (err != RT_EOK)
{
rt_kprintf("ecat_write_state PRE_OP failed\n");
return err;
}
struct rpdo_csp *rmap = (struct rpdo_csp *)(csp_master.process_data);
struct tpdo_csp *tmap =
(struct tpdo_csp *)(csp_master.process_data + sizeof(struct rpdo_csp));
rmap->control_word = 0x8;
/* swith mode */
int _chk = 400;
do
{
servo_switch_op(rmap, tmap);
ecat_send_processdata_group(&csp_master, 0);
ecat_receive_processdata_group(&csp_master, 0, 2000000 * 3);
state = EC_STATE_OPERATIONAL;
} while (
_chk-- && (ecat_check_state(&csp_master, 0, &state, 2000) != RT_EOK));
struct ecat_timer t;
ecat_timer_start(&t, 1000);
while (1)
{
servo_switch_op(rmap, tmap);
if (servo_run == 0)
{
rmap->control_word = 0x2;
/* get the current position */
motor_current_pos = PULSE_TO_ANGLE(tmap->cur_pos);
rmap->dest_pos = tmap->cur_pos;
goto stop;
}
ecat_send_processdata_group(&csp_master, 0);
ecat_receive_processdata_group(&csp_master, 0, 2000 * 10);
if (rmap->control_word == 7)
{
rmap->mode_byte = 0x8;
rmap->dest_pos = tmap->cur_pos;
}
if (rmap->control_word == 0xf)
{
if (motor_target_pos_last != motor_target_pos)
{
/* get the current position */
motor_current_pos = PULSE_TO_ANGLE(tmap->cur_pos);
if (abs(motor_current_pos - motor_target_pos) <= 0)
{
rmap->dest_pos = tmap->cur_pos;
if (abs(tmap->cur_pos - rmap->dest_pos) <= 10)
{
motor_target_pos_last = motor_target_pos;
}
goto stop;
}
if (servo_dir)
{
rmap->dest_pos -= motor_step;
}
else
{
rmap->dest_pos += motor_step;
}
}
}
while (ecat_timer_is_expired(&t) == RT_FALSE);
ecat_timer_start(&t, 1000);
stop:
ecat_send_processdata_group(&csp_master, 0);
ecat_receive_processdata_group(&csp_master, 0, 2000 * 10);
rt_thread_delay(1);
}
return 0;
}运行程序
连接开发板,在 RuiChing Studio IDE 中启动调试,结果如下:
- 电机现象
移动显示幕的滑块到某一位置后,点击 Run/Stop 按钮即可运行电机,可以观察到电机通过设定的方向旋转到指定位置,电机停止只需再次点击 Run/Stop 按钮,且点击 Direct/Reverse 按钮可以改变电机旋转方向。不关闭 Run/Stop 按钮电机可一直滑动滑块,松开后电机会再次移动指定位置。其中位置表盘也可以显示当前位置和期望位置。
EtherCAT 示例运行后,远程 IO 模块输出端会呈现流水灯的方式控制,驱动器风扇会开启,面板显示 88rn 字符。
- 显示屏现象

