本教程將教您使用QEC-M控制QEC-RxxD(EtherCAT數位I/O從站模組)系列產品。 該項目是 EtherCAT 主站和 EtherCAT 從站控制和監視器的簡單演示。

目標:
在本教程中,我們將實現以下目標:
- 讓使用者了解 EtherCAT 函式庫
- 連接 QEC-M 和 QEC-R
- 創建一個使用者界面,去顯示裝置的狀態和設備的數據
所需的硬體和軟體:
- 86Duino IDE 500+
- QEC-M-043T
- QEC-R11DF0:EtherCAT 從站數位輸入模組
- QEC-R11DF0:EtherCAT 從站數位輸出模組
開始本教程
首先使用 USB 轉 Micro USB 電纜將 QEC-M-043T 連線至個人電腦,並開啟 86Duino IDE 500。如果這是您第一次運行 86Duino sketch,我們建議您在繼續之前查看如何為86Duino設置QEC-M-043T 。
步驟 1. 連接 QEC-M 和 QEC-RxxD
- 使用 RJ45 連接 QEC-M 和 QEC-RxxD。
- 連接由 Vp(外圍電源)供電的 QEC-R11D0F 和 QEC-R11DF0 之間。

步驟 2. 將以下給定代碼複製到 86Duino IDE
#include "EthercatMaster.h"
#include <lvgl86.h>
EthercatMaster master;
DmpQECR11D0FSDriver QECR11D0FS;
DmpQECR11DF0DDriver QECR11DF0D;
uint16_t val = 0x5555;
void lv_demo_widgets(void); /* lvgl User Interface work */
static void tab_create_1(lv_obj_t * parent);
static void tab_create_2(lv_obj_t * parent);
static void color_chg_event_cb(lv_obj_t * sw, lv_event_t e);
static lv_obj_t * tv;
static lv_obj_t * t[2];
static lv_obj_t * led[32];
static lv_obj_t * label_system[8];
static lv_obj_t * gauge[3];
static lv_obj_t * label_gauge[3];
static lv_style_t bigStyle;
static lv_style_t style_box;
static lv_style_t style_ledColor;
static lv_color_t needle_colors = LV_COLOR_RED;
const char tabName[2][50] = {"Light Status", "Device Information"};
const char led_lightName[2][50] = {"QECR11D0FS LED Light", "QECR11DF0S LED Light"};
const char value_systemName[8][50] = {"QECR11D0FS Voltage-s", "QECR11D0FS Current-s", "QECR11D0FS Voltage-p", "QECR11D0FS Current-p",
"QECR11DF0D Voltage-s", "QECR11DF0D Current-s", "QECR11DF0D Voltage-p", "QECR11DF0D Current-p",
};
const char value_systemTempName[3][50] = {"QECR11D0FS Temp.", "QECR11DF0D Temp.", "Master CPU Temp."};
const int ledLocateX[32] = {350, 250, 150, 50, -50, -150, -250, -350,
350, 250, 150, 50, -50, -150, -250, -350,
350, 250, 150, 50, -50, -150, -250, -350,
350, 250, 150, 50, -50, -150, -250, -350,
};
const int ledLocateY[32] = {150, 150, 150, 150, 150, 150, 150, 150,
50, 50, 50, 50, 50, 50, 50, 50,
-50, -50, -50, -50, -50, -50, -50, -50,
-150, -150, -150, -150, -150, -150, -150, -150,
};
long unsigned int ledStyleColor = 0x60ff4e;
unsigned long timeCheck = 0;
bool ledSw[32];
void setup(void) {
Serial.begin(115200); // Serial Port begin
// GUI: LVGL
lv86_init(); // Init LV86
lv_disp_size_t disp_size = lv_disp_get_size_category(NULL);
lv_demo_widgets();
// EtherCAT
master.begin();
QECR11D0FS.begin(0, master);
QECR11DF0D.begin(1, master);
/* Auto FreeRun Mode, Cycle Time 500000 ns. */
master.start(ECAT_AUTO, 500000);
// Timing
timeCheck = millis();
}
void loop() {
lv_task_handler(); /* let the GUI do its work */
escGpioControl(); /* EtherCAT Slave - GPIN/OUT control */
label_system_value(); /* label Value Setting */
ledSystemControl(); /* led control */
}
void lv_demo_widgets(void) {
double light_palette[49] = {
0x01a2b1,
0x44d1b6,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0x01a2b1,
0xff0000,
0xeaeff3,
0xffffff,
0xeeeeee,
0x3b3e42,
0x3b3e42,
0xffffff,
0x3b3e42,
0xd6dde3,
0x3b3e42,
0xaaaaaa,
0xd6dde3,
0xffffff,
0x888888,
0xcccccc,
0xd4d7d9,
0x666666,
0xaaaaaa,
0x464b5b,
0x888888,
-2,
0xc0c0c0,
0xcccfd1,
-1,//sw_knob
0xffffff,
0x888888};
static lv_font_t * theme_fonts[6] = {
&lv_font_montserrat_18,
&lv_font_montserrat_14,
&lv_font_montserrat_36,
&lv_font_montserrat_12,
&lv_font_montserrat_28,
&lv_font_montserrat_18};
// Setting Theme
lv_theme_material86_init(light_palette, theme_fonts);
// Create Tabview paging object
tv = lv_tabview_create(lv_scr_act(), NULL);
lv_obj_set_style_local_pad_left(tv, LV_TABVIEW_PART_TAB_BG, LV_STATE_DEFAULT, LV_HOR_RES / 2);
// Create a switch element in the upper left corner
lv_obj_t * sw = lv_switch_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(sw, color_chg_event_cb);
lv_obj_set_pos(sw, LV_DPX(10), LV_DPX(10));
lv_obj_set_style_local_value_str(sw, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, " ");
lv_obj_set_style_local_value_align(sw, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, LV_ALIGN_OUT_RIGHT_MID);
lv_obj_set_style_local_value_ofs_x(sw, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, LV_DPI/35);
lv_switch_off(sw, LV_ANIM_ON);
// Create Tabpage title
for (int i = 0; i < 2; i++) {
t[i] = lv_tabview_add_tab(tv, tabName[i]);
}
// Create Tabpage content
tab_create_1(t[0]); // Tabpage 1 content
tab_create_2(t[1]); // Tabpage 2 content
}
static void tab_create_1(lv_obj_t * parent) {
// Tabpage 1 content
lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY_TOP);
lv_disp_size_t disp_size = lv_disp_get_size_category(NULL);
lv_coord_t grid_w = lv_page_get_width_grid(parent, disp_size <= LV_DISP_SIZE_SMALL ? 1 : 2, 1);
lv_style_init(&style_ledColor);
lv_style_set_text_font(&bigStyle ,LV_STATE_DEFAULT, &lv_font_montserrat_28);
lv_style_set_bg_color(&style_ledColor, LV_STATE_DEFAULT, lv_color_hex(ledStyleColor));
lv_style_set_shadow_color(&style_ledColor, LV_STATE_DEFAULT, lv_color_hex(ledStyleColor));
lv_style_set_border_color(&style_ledColor, LV_STATE_DEFAULT, lv_color_hex(ledStyleColor));
for (int j = 0; j < 2; j++) {
lv_obj_t * h = lv_cont_create(parent, NULL);
lv_cont_set_layout(h, LV_LAYOUT_PRETTY_MID);
lv_obj_add_style(h, LV_CONT_PART_MAIN, &style_box);
lv_obj_set_drag_parent(h, true);
lv_cont_set_fit2(h, LV_FIT_NONE, LV_FIT_TIGHT);
lv_obj_set_width(h, grid_w);
lv_obj_set_style_local_value_str(h, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, NULL);
lv_obj_t * label = lv_label_create(h, NULL);
lv_label_set_text(label, led_lightName[j]);
lv_obj_align(label, h, LV_ALIGN_IN_TOP_MID, 0, 0);
lv_obj_add_style(label, LV_LABEL_PART_MAIN, &bigStyle);
if (j == 0) {
for (int i = 0; i < 16; i++) {
led[i] = lv_led_create(h, NULL);
lv_obj_align(led[i], h, LV_ALIGN_CENTER, ledLocateX[i], ledLocateY[i]);
lv_obj_add_style(led[i], LV_OBJ_PART_MAIN, &style_ledColor);
lv_obj_set_size(led[i], 50, 50);
lv_led_set_bright(led[i], 64);
}
} else {
for (int i = 16; i < 32; i++) {
led[i] = lv_led_create(h, NULL);
lv_obj_align(led[i], h, LV_ALIGN_CENTER, ledLocateX[i], ledLocateY[i]);
lv_obj_add_style(led[i], LV_OBJ_PART_MAIN, &style_ledColor);
lv_obj_set_size(led[i], 50, 50);
lv_led_set_bright(led[i], 64);
}
}
}
}
static void tab_create_2(lv_obj_t * parent) {
// Tabpage 2 content
lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY_TOP);
lv_disp_size_t disp_size = lv_disp_get_size_category(NULL);
lv_coord_t grid_w = lv_page_get_width_grid(parent, disp_size <= LV_DISP_SIZE_SMALL ? 1 : 2, 1);
lv_style_init(&bigStyle);
lv_style_set_text_font(&bigStyle ,LV_STATE_DEFAULT, &lv_font_montserrat_28);
for (int i = 0; i < 8; i++) {
lv_obj_t * h = lv_cont_create(parent, NULL);
lv_cont_set_layout(h, LV_LAYOUT_PRETTY_MID);
lv_obj_add_style(h, LV_CONT_PART_MAIN, &style_box);
lv_obj_set_drag_parent(h, true);
lv_cont_set_fit2(h, LV_FIT_NONE, LV_FIT_TIGHT);
lv_obj_set_width(h, grid_w);
lv_obj_set_style_local_value_str(h, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, NULL);
lv_obj_t * label = lv_label_create(h, NULL);
lv_label_set_text(label, value_systemName[i]);
lv_obj_align(label, h, LV_ALIGN_IN_TOP_MID, 0, 0);
lv_obj_add_style(label, LV_LABEL_PART_MAIN, &bigStyle);
label_system[i] = lv_label_create(h, NULL);
lv_label_set_text(label_system[i], "Error");
lv_obj_align(label_system[i], h, LV_ALIGN_IN_TOP_MID, 0, 0);
lv_obj_add_style(label_system[i], LV_LABEL_PART_MAIN, &bigStyle);
}
for (int i = 0; i < 3; i++) {
lv_obj_t * h = lv_cont_create(parent, NULL);
lv_cont_set_layout(h, LV_LAYOUT_PRETTY_MID);
lv_obj_add_style(h, LV_CONT_PART_MAIN, &style_box);
lv_obj_set_drag_parent(h, true);
lv_cont_set_fit2(h, LV_FIT_NONE, LV_FIT_TIGHT);
lv_obj_set_width(h, grid_w);
lv_obj_set_style_local_value_str(h, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, NULL);
lv_obj_t * label = lv_label_create(h, NULL);
lv_label_set_text(label, value_systemTempName[i]);
lv_obj_align(label, h, LV_ALIGN_IN_TOP_MID, 0, 0);
lv_obj_add_style(label, LV_LABEL_PART_MAIN, &bigStyle);
gauge[i] = lv_gauge_create(h, NULL);
lv_obj_align(gauge[i], h, LV_ALIGN_CENTER, 0, 0);
lv_gauge_set_value(gauge[i], 0, 10);
lv_gauge_set_needle_count(gauge[i], 1, &needle_colors);
label_gauge[i] = lv_label_create(gauge[i], NULL);
lv_label_set_text(label_gauge[i], "Error");
lv_obj_align(label_gauge[i], gauge[i], LV_ALIGN_IN_BOTTOM_MID, -20, -20);
lv_obj_add_style(label_gauge[i], LV_LABEL_PART_MAIN, &bigStyle);
}
}
static void color_chg_event_cb(lv_obj_t * sw, lv_event_t e) {
// Here is the action of the switch in the upper left corner
}
void escGpioControl(void) {
while ((millis() - timeCheck) > 1000) { // per 1 second
timeCheck = millis();
for (int i = 0; i < 16; i++) {
QECR11D0FS.digitalWrite(i, ((val >> abs(i-15)) & 0x01));
QECR11DF0D.digitalRead(i);
ledSw[i] = ((val >> abs(i-15)) & 0x01);
}
val = ~val;
}
}
void label_system_value(void) {
/*
DmpQECR11D0FSDriver QECR11D0FS;
DmpQECR11DF0DDriver QECR11DF0D;
*/
float textValue[11];
char textValueChar[11][100];
textValue[0] = QECR11D0FS.getSystemPowerVoltage();
textValue[1] = QECR11D0FS.getSystemPowerCurrent();
textValue[2] = QECR11D0FS.getPeripheralPowerVoltage();
textValue[3] = QECR11D0FS.getPeripheralPowerCurrent();
textValue[4] = QECR11DF0D.getSystemPowerVoltage();
textValue[5] = QECR11DF0D.getSystemPowerCurrent();
textValue[6] = QECR11DF0D.getPeripheralPowerVoltage();
textValue[7] = QECR11DF0D.getPeripheralPowerCurrent();
for (int i = 0; i < 8; i++) {
sprintf(textValueChar[i], "%5.2f", textValue[i]);
if (lv_label_get_text(label_system[i]) != textValueChar[i]) lv_label_set_text(label_system[i], textValueChar[i]);
}
float gaugeValue[3];
char gaugeValueChar[3][100];
gaugeValue[0] = QECR11D0FS.getTemperature();
gaugeValue[1] = QECR11DF0D.getTemperature();
gaugeValue[2] = cpuTemperature();
for (int j = 0; j < 3; j++) {
sprintf(gaugeValueChar[j], "%5.2f", gaugeValue[j]);
if (lv_gauge_get_value(gauge[j], 0) != gaugeValue[j]) lv_gauge_set_value(gauge[j], 0, gaugeValue[j]);
if (lv_label_get_text(label_gauge[j]) != gaugeValueChar[j]) lv_label_set_text(label_gauge[j], gaugeValueChar[j]);
}
}
void ledSystemControl(void) {
for (int i = 0; i < 32; i++) {
// setting light status: digital input
if (i >= 16) ledSw[i] = QECR11DF0D.digitalRead(i-16);
// display light status
if (ledSw[i]) {lv_led_on(led[i]);}
if (!ledSw[i]) {lv_led_off(led[i]);}
}
}步驟 3. 上傳您的草稿碼!
點擊驗證按鈕旁邊的右箭頭按鈕(上傳)。 代碼上傳後,您可以在 QEC-M 的人機界面上看到您設計的畫面。
- 燈號畫面用於 LED 狀態顯示,它將檢測硬件狀態以將其顯示在用戶界面上。
- 設備信息畫面用於內部監視器信息,由軟體配置。 此演示中有電壓、電流和溫度。
結論
本教程介紹如何使用 QEC-M-043T 控制 EtherCAT 從站數位 I/O 模組,並監控其內部信息。 您可以學習 EtherCAT 函式庫與 LVGL (輕量型人機介面函式庫) 結合起來製作一個應用程式,並使用一種非常簡單的方式來顯示機台信息。
請繼續關注 QEC 的更多項目!
如果您有任何疑問/疑問,請隨時發表評論!
86Duino 參考的文本是根據 知識共享署名-相同方式分享 3.0 許可證,部分文本是從 Arduino 參考 修改的。 參考中的代碼示例已發佈到公共領域。