Share this

Easy-to-use motion control card (Part 5): IO configuration and homing motion

2026-04-06 02:58:48 · · #1

Today, Zheng Motion Assistant will share with you how to use C++ to write a controller for zero-return motion and configure the corresponding I/O for the ECI3808 motion control card.

ECI3808 Hardware Introduction

1. Function Introduction

The ECI3808 series control cards support up to 12 axes of linear interpolation, arbitrary circular interpolation, spatial circular interpolation, helical interpolation, electronic cams, electronic gears, synchronous following, virtual axes, and robot commands; they also employ optimized network communication protocols to achieve real-time motion control.

The ECI3808 series motion control card supports Ethernet and RS232 communication interfaces to connect to a computer, receive commands from the computer, and can connect to various expansion modules via CAN bus to expand the number of input/output points or motion axes.

Applications for the ECI3808 series motion control card can be developed using software such as VC, VB, VS, C++, and C#. The program requires the dynamic library zmotion.dll to run. During debugging, the ZDevelop software can be connected to the controller simultaneously for convenient debugging and observation.

2. Hardware Interface

General purpose input circuit

General purpose input circuit

AD/DA Interface Description

Local Pulse Axis Description

3. Controller Basic Information

II. Motion Control Development using C++

1. Create a new MFC project and add function libraries.

(1) In the VS2015 menu, go to "File" → "New" → "Project" to start the Project Creation Wizard.

(2) Select “Visual C++” as the development language and “MFC Application” as the program type.

(3) Click Next.

(4) Select "Dialog-based" as the type, then click Next or Finish.

(5) Locate the CD-ROM data provided by the manufacturer. The path is as follows (64-bit library as an example).

A. Locate the "8.PC Functions" folder in the CD-ROM provided by the manufacturer and click to enter.

B. Select the "Function Library 2.1" folder.

C. Select the "Windows Platform" folder.

D. Select the appropriate function library as needed; here, we choose the 64-bit library.

E. Unzip the C++ compressed file, which contains the corresponding C++ function library.

F. The specific path to the function library is as follows.

(6) Copy the C++ library files and related header files provided by the vendor into the newly created project.

(7) Add static libraries and related header files to the project.

A. First, right-click the project file, then select: "Add" → "Existing Item".

B. In the pop-up window, add the static library and related header files in sequence.

(8) Declare the header files used and define the controller connection handle.

The project is now complete and ready for MFC project development.

2. Review the PC function manual and familiarize yourself with the relevant function interfaces.

(1) The PC function manual is also included in the CD-ROM materials. The specific path is as follows: "CD-ROM materials\8.PC functions\Function library 2.1\ZMotion function library programming manual V2.1.pdf"

(2) Link controller, obtain link handle.

ZAux_OpenEth() Interface Description:

(3) Configure the function interface corresponding to the IO signal point as follows.

For detailed information on the interface, please refer to the PC function manual.

The following is the zero-return motion call interface and a detailed explanation of the zero-return mode. Adding 10 means that after encountering the limit switch, it will reverse and stop without encountering the limit switch. For example, 13 = mode 3 + limit switch reverse search 10, which is used when the origin is in the middle.

3. MFC development of controller hardware peripheral read/write routines.

(1) The routine interface is as follows.

(2) In the event handling function of the link button, the interface function ZAux_OpenEth() of the link controller is called to link with the controller. After the link is successfully linked, timer 1 is started to monitor the status of the controller.

// Network port connection controller void CSingle_move_Dlg::OnOpen(){ char buffer[256]; int32 iresult; // If already connected, disconnect first if(NULL != g_handle) { ZAux_Close(g_handle); g_handle = NULL; } // Select and get the IP address from the IP drop-down box GetDlgItemText(IDC_IPLIST,buffer,255); buffer[255] = '\0'; // Start the connection controller iresult = ZAux_OpenEth(buffer, &g_handle); if(ERR_SUCCESS != iresult) { g_handle = NULL; MessageBox(_T("Connection failed")); SetWindowText("Not connected"); return; } // Start timer 1 if connection is successful SetWindowText("Connected"); SetTimer( 1, 100, NULL ); }

(3) Monitor the controller status through a timer.

void CFuncWrapperDlg::OnTimer(UINT_PTR nIDEvent){ // TODO: Add message handler code here and/or call default values ​​if(NULL == g_handle) { MessageBox(_T("Link disconnected")); return ; } if(1 == nIDEvent) { CString string; float position[4] = {0}; int status[4] = {0}; int nAxisStatus[4] = {0}; for (int i = 0;i< 4; i++) { ZAux_Direct_GetDpos( g_handle,i,&position[i]); //Get the current axis position ZAux_Direct_GetIfIdle(g_handle,i,&status[i]); //Determine the current axis status ZAux_Direct_GetAxisStatus(g_handle, i, &nAxisStatus[i]); } if (status[0] == -1) { if (nAxisStatus[0] == 0 || (nAxisStatus[0] & 0x000040) == 64) { string.Format("X Stop%.2f axis status normal", position[0]); GetDlgItem(IDC_STATE_X)->SetWindowText(string); } if ((nAxisStatus[0] & 0x000010) == 16) { string.Format("X Stop%.2f axis positive hard limit alarm", position[0]); GetDlgItem(IDC_STATE_X)->SetWindowText(string); } if ((nAxisStatus[0] & 0x000020) == 32) { string.Format("X Stop%.2f axis reverse hard limit alarm", position[0]); GetDlgItem(IDC_STATE_X)->SetWindowText(string); } } else { if (nAxisStatus[0] == 0 || (nAxisStatus[0] & 0x000040) == 64) { string.Format("X running. %.2f axis status normal", position[0]); GetDlgItem(IDC_STATE_X)->SetWindowText(string); } if ((nAxisStatus[0] & 0x000010) == 16) { string.Format("X running. %.2f axis positive hard limit alarm", position[0]); GetDlgItem(IDC_STATE_X)->SetWindowText(string); } if ((nAxisStatus[0] & 0x000020) == 32) { string.Format("X running. %.2f axis reverse hard limit alarm", position[0]); GetDlgItem(IDC_STATE_X)->SetWindowText(string); } } if (status[1] == -1) { if (nAxisStatus[1] == 0 || (nAxisStatus[1] & 0x000040) == 64) { string.Format("Y Stop%.2f Axis Status Normal", position[1]); GetDlgItem(IDC_STATE_Y)->SetWindowText(string); } if ((nAxisStatus[1] & 0x000010) == 16) { string.Format("Y Stop%.2f Axis Positive Hard Limit Alarm", position[1]); GetDlgItem(IDC_STATE_Y)->SetWindowText(string); } if ((nAxisStatus[1] & 0x000020) == 32) { string.Format("Y Stop%.2f Axis Reverse Hard Limit Alarm", position[1]); GetDlgItem(IDC_STATE_Y)->SetWindowText(string); } } else { if (nAxisStatus[1] == 0 || (nAxisStatus[1] & 0x000040) == 64) { string.Format("Y running. %.2f axis status normal", position[1]); GetDlgItem(IDC_STATE_Y)->SetWindowText(string); } if ((nAxisStatus[1] & 0x000010) == 16) { string.Format("Y running. %.2f axis positive hard limit alarm", position[1]); GetDlgItem(IDC_STATE_Y)->SetWindowText(string); } if ((nAxisStatus[1] & 0x000020) == 32) { string.Format("Y running. %.2f axis reverse hard limit alarm", position[1]); GetDlgItem(IDC_STATE_Y)->SetWindowText(string); } } if (status[2] == -1) { if (nAxisStatus[2] == 0 || (nAxisStatus[2] & 0x000040) == 64) { string.Format("Z Stop%.2f Axis Status Normal", position[2]); GetDlgItem(IDC_STATE_Z)->SetWindowText(string); } if ((nAxisStatus[2] & 0x000010) == 16) { string.Format("Z Stop%.2f Axis Positive Hard Limit Alarm", position[2]); GetDlgItem(IDC_STATE_Z)->SetWindowText(string); } if ((nAxisStatus[2] & 0x000020) == 32) { string.Format("Z Stop%.2f Axis Reverse Hard Limit Alarm", position[2]); GetDlgItem(IDC_STATE_Z)->SetWindowText(string); } } else { if (nAxisStatus[2] == 0 || (nAxisStatus[2] & 0x000040) == 64) { string.Format("Z is running.2f axis status is normal", position[2]); GetDlgItem(IDC_STATE_Z)->SetWindowText(string); } if ((nAxisStatus[2] & 0x000010) == 16) { string.Format("Z is running.2f axis positive hard limit alarm", position[2]); GetDlgItem(IDC_STATE_Z)->SetWindowText(string); } if ((nAxisStatus[2] & 0x000020) == 32) { string.Format("Z is running.2f axis reverse hard limit alarm", position[2]); GetDlgItem(IDC_STATE_Z)->SetWindowText(string); } } if (status[3] == -1) { if (nAxisStatus[3] == 0 || (nAxisStatus[3] & 0x000040) == 64) { string.Format("R Stop%.2f Axis Status Normal", position[3]); GetDlgItem(IDC_STATE_R)->SetWindowText(string); } if ((nAxisStatus[3] & 0x000010) == 16) { string.Format("R Stop%.2f Axis Positive Hard Limit Alarm", position[3]); GetDlgItem(IDC_STATE_R)->SetWindowText(string); } if ((nAxisStatus[3] & 0x000020) == 32) { string.Format("R Stop%.2f Axis Reverse Hard Limit Alarm", position[3]); GetDlgItem(IDC_STATE_R)->SetWindowText(string); } } else { if (nAxisStatus[3] == 0 || (nAxisStatus[3] & 0x000040) == 64) { string.Format("R is running.2f axis status is normal", position[3]); GetDlgItem(IDC_STATE_R)->SetWindowText(string); } if ((nAxisStatus[3] & 0x000010) == 16) { string.Format("R is running.2f axis positive hard limit alarm", position[3]); GetDlgItem(IDC_STATE_R)->SetWindowText(string); } if ((nAxisStatus[3] & 0x000020) == 32) { string.Format("R is running.2f axis reverse hard limit alarm", position[3]); GetDlgItem(IDC_STATE_R)->SetWindowText(string); } } } CDialog::OnTimer(nIDEvent);}

(4) Use the event handling function of the return-to-zero button to initialize the parameters before the return-to-zero movement and call the corresponding return-to-zero mode to perform the return-to-zero movement.

void CSingle_homeDlg::OnHome() // Zeroing motion { // TODO: Add your control notification handler code here UpdateData(true);//Refresh parameters int status = 0; ZAux_Direct_GetIfIdle(g_handle, m_nAxis,&status); // Check the current axis status if (status == 0) // Already in motion { return; } // Set axis type 7 - Pulse axis type + encoder Z signal can be set to 1 if zeroing is not required ZAux_Direct_SetAtype(g_handle, m_nAxis, 7); // Set pulse mode and logical direction (pulse + direction) ZAux_Direct_SetInvertStep(g_handle, m_nAxis, 0); // Set pulse equivalent 1 to indicate the number of pulses per 1MM, the unit of measurement is MM ZAux_Direct_SetUnits(g_handle, m_nAxis, m_units); // Set speed, acceleration/deceleration ZAux_Direct_SetLspeed(g_handle, m_nAxis, m_lspeed); ZAux_Direct_SetSpeed(g_handle, m_nAxis, m_speed); ZAux_Direct_SetAccel(g_handle, m_nAxis, m_acc); ZAux_Direct_SetDecel(g_handle, m_nAxis, m_dec); ZAux_Direct_SetCreep(g_handle, m_nAxis, m_creep); // Set the origin input signal for the corresponding axis ZAux_Direct_SetDatumIn(g_handle, m_nAxis, m_datumin); // ZMC series assumes the origin signal (normally closed) is encountered when OFF. If it is a normally open sensor, the input port needs to be reversed. ECI series does not need to be reversed. ZAux_Direct_SetInvertIn(g_handle, m_datumin, 1); // Set the origin input signal for the corresponding axis ZAux_Direct_SetFwdIn(g_handle, m_nAxis, m_FwdIn); // ZMC series assumes the origin signal (normally closed) is encountered when OFF. If it is a normally open sensor, the input port needs to be reversed. ECI series does not need to be reversed. ZAux_Direct_SetInvertIn(g_handle, m_FwdIn, 1); // Set the origin input signal for the corresponding axis ZAux_Direct_SetRevIn(g_handle, m_nAxis, m_RevIn); // ZMC series assumes the origin signal (normally closed) is encountered when OFF. If it is a normally open sensor, the input port needs to be reversed. ECI series does not need to be reversed. ZAux_Direct_SetInvertIn(g_handle, m_RevIn, 1); // Return to zero if( m_datummode < 4) { ZAux_Direct_Single_Datum(g_handle, m_nAxis, m_datummode + 1); //Modes 1-4 } else { ZAux_Direct_Single_Datum(g_handle, m_nAxis, m_datummode + 4 ); //Modes 8, 9 } UpdateData(false); }

(5) Stop the current motion by using the event handler function of the stop motion button.

void CSingle_homeDlg::OnStop() //Stop movement{ // TODO: Add your control notification handler code here if(NULL == g_handle) { MessageBox(_T("Connection disconnected")); return ; } ZAux_Direct_Single_Cancel(g_handle,m_nAxis,2); //}

(6) The coordinates of the current axis are cleared by using the event handling function of the coordinate clearing button.

void CSingle_homeDlg::OnZero() // Clear coordinates to zero { if(NULL == g_handle) { MessageBox(_T("Connection disconnected")); return ; } // TODO: Add your control notification handler code here for (int i=0;i<4;i++) { ZAux_Direct_SetDpos(g_handle,i,0); // Set zero point }}

Full code download address

III. Debugging and Monitoring

Compile and run the routines, and simultaneously monitor the controller status by connecting to the controller through the ZDevelop software.

1. Connect the ZDevelop software and click "View" → "Oscilloscope" to open the oscilloscope and monitor the axis movement.

2. ZDevelop software debugging video.

This concludes our sharing of the fifth installment of ZhengMotion Technology's easy-to-use motion control card: IO configuration and homing motion. For more exciting content, please follow the "ZhengMotion Assistant" WeChat official account. For related development environment and example code, please contact ZhengMotion Technology's sales engineer: 400-089-8936.

This article is original content from Zheng Motion Technology. We welcome everyone to reprint it for mutual learning and to jointly improve China's intelligent manufacturing level. Copyright belongs to Zheng Motion Technology. Please indicate the source if you reprint this article.


Read next

CATDOLL Maruko 109CM TPE (Soft Silicone Head)

Height: 109cm Weight: 15.6kg Shoulder Width: 26cm Bust/Waist/Hip: 52/50/57cm Oral Depth: 3-5cm Vaginal Depth: 3-13cm An...

Articles 2026-02-22