I want to find...

Search

Shares

Table of Content

Use QEC-M-043T to control the EtherCAT slave Digital I/O modules and monitor internal information

This tutorial will teach you to use QEC-M to control QEC-RxxD (EtherCAT Slave Digital I/O module) products series. This project is a simple demo of the EtherCAT Master and EtherCAT Slave control and monitor.

qecm043tControlQecr00d

Goals:

In this tutorial, we will achieve the following:

  • Understanding the EtherCAT Library
  • Connect between QEC-M and QEC-R
  • Make the UI interface show the digital states and the device data

Hardware and Software needed:


Start this tutorial

If this is your first time running 86Duino sketch files, we suggest you check out how to set up the QEC-M-043T for 86Duino before proceeding.

Step 1. Connect between the QEC-M and QEC-RxxD

  1. Use RJ45 to connect the QEC-M and QEC-RxxD.
  2. Connect between the QEC-R11D0F and QEC-R11DF0 that the Vp (Peripheral power) power.
qecm043tControlQecr00d_img1

Step 2. Copy the given code below into 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]);}    
  }
}

Step 3. Upload your sketch!

Hit the right arrow button (upload) next to the verify button. After the code uploads, you can see the 2-page tabs on the user interface.

  • The Light Status tab is for the LED state display, and it will detect the hardware state to show it on the user interface.
  • The Device Information tab is for the internal monitor information and is configured by software. There is the Voltage, Current, and Temperature in this demo.

Conclusion

This tutorial shows how to use QEC-M-043T to control the EtherCAT slave Digital I/O modules and monitor internal information. You can learn the EtherCAT library and the LVGL library combined to make an application and use a very simple way to show the machine information.

Stay tuned for more projects on QEC!

Feel free to comment if you have any doubts/queries!


The text of the 86Duino reference is a modification of the Arduino reference and is licensed under a Creative Commons Attribution-ShareAlike 3.0 License. Code samples in the reference are released into the public domain.

Leave a Comment

Scroll to Top