EtherCAT Code Assistent

 
zurück

Code-Assistent zur Generierung eines Framework-Codes

Um die Handhabung der EtherCAT-Masterbibliothek zu vereinfachen, hilft Ihnen der Code-Assistent bei der Generierung eines Framework-Codes für die EtherCAT-Kommunikation auf Basis von C++. Mit dem Code-Assistenten wird ein Vorlagencode generiert, der Header-Dateien und Codestrukturen enthält. Es sind zwei Schritte erforderlich: das Erstellen einer Header-Datei für jedes ausgewählte Gerät und anschließend das Erstellen des Vorlagencodes. Der Code-Assistent bietet daher verschiedene Programmierstufen, vom Anfänger bis zum Experten. Die Struktur des Anwendungscodes ist somit vorgegeben und sofort einsatzbereit. Dadurch wird die Handhabung der EtherCAT-Masterbibliothek deutlich vereinfacht.

Erstellung der Header-Dateien

Zuerst müssen wir alle Header-Dateien aus der nativen Parameterdatei ECATDEVICExxx.par erstellen. Dazu müssen wir jedes Gerät anhand von VendorID, ProductCode und Revision auswählen. Der Name der Header-Datei besteht aus einem erforderlichen Präfix (DevConfig_...), dem Gerätenamen (z. B. LXM32M) und einem Zeitstempel (z. B. 2001091624).

Sample: DevConfig_EL7041_2001081526

//*****************************************************************
//*** Automated generated header ***
//*** Name:        [EL7041-1000] ***
//*** VendorID:    [0x00000002] ***
//*** ProductCode: [0x1b813052] ***
//*** Revision:    [0x001303e8] ***
//*****************************************************************
 
#pragma once
 
//*** Required header files ***
#include <windows.h>
#include "c:\sha\globdef64.h"
#include "c:\sha\Sha64Debug.h"
#include "c:\eth\Sha64EthCore.h"
#include "c:\eth\Eth64CoreDef.h"
#include "c:\eth\Eth64Macros.h"
#include "c:\ect\Sha64EcatCore.h"
#include "c:\ect\Ecat64CoreDef.h"
#include "c:\ect\Ecat64Macros.h"
#include "c:\ect\Ecat64Control.h"
#include "c:\ect\Ecat64SilentDef.h"
 
//*** Structures need to have 1 byte alignment ***
#pragma pack(push, old_alignment)
#pragma pack(1)
 
//*** TX mapping structure [Device Output] ***
typedef struct _TX_MAP_EL7041_2001081709
{
      UCHAR  Data0[1];  //Item: Value
      UCHAR  Data1[1];  //Item: Value
      UCHAR  Data2[2];  //Item: Value, Type: Unsigned 16Bit
      UCHAR  Data3[2];  //Item: Value, Type: Unsigned 16Bit
      UCHAR  Data4[2];  //Item: Value
} TX_MAP_EL7041_2001081709, *PTX_MAP_EL7041_2001081709;
 
//*** RX mapping structure [Device Input]  ***
typedef struct _RX_MAP_EL7041_2001081709
{
      UCHAR  Data0[1];  //Item: Value
      UCHAR  Data1[1];  //Item: Value
      UCHAR  Data2[2];  //Item: Value, Type: Unsigned 16Bit
      UCHAR  Data3[1];  //Item: Value
      UCHAR  Data4[1];  //Item: Value
      UCHAR  Data5[2];  //Item: Value, Type: Signed 16Bit
} RX_MAP_EL7041_2001081709, *PRX_MAP_EL7041_2001081709;
 
//*** SDO download requests ***
__inline BOOLEAN __SdoControl_EL7041_2001081709(PSTATION_INFO pStation)
{
      ULONG SdoData = 0;
 
      SdoData = 0x00000000;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c12, 0x00, 1, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      SdoData = 0x00001600;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c12, 0x01, 2, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      SdoData = 0x00001602;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c12, 0x02, 2, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      SdoData = 0x00001604;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c12, 0x03, 2, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      SdoData = 0x00000003;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c12, 0x00, 1, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      SdoData = 0x00000000;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c13, 0x00, 1, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      SdoData = 0x00001a00;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c13, 0x01, 2, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      SdoData = 0x00001a03;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c13, 0x02, 2, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      SdoData = 0x00000002;
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadReq (pStation, 0x1c13, 0x00, 1, (PUCHAR)&SdoData))
      if (ERROR_SUCCESS == Ecat64SdoInitDownloadResp(pStation)) {
 
      //*** Disable SDO automation ***
      pStation->SdoNum = 0;
      return TRUE; }}}}}}}}}
 
      //*** Something failed ***
      return FALSE;
}
 
//Set back old alignment
#pragma pack(pop, old_alignment)

Build Template Code

Als Nächstes muss der Vorlagencode erstellt werden. Der Code-Assistent unterstützt Sie bei der Erstellung verschiedener Codevorlagen:

Beginner:       Kurzer Code mit High-Level-Schnittstelle. Keine Unterstützung für verteilte Taktung.
Beginner DC: Kurzer Code mit High-Level-Schnittstelle. Unterstützung für verteilte Taktung.
Expert:            Standardcode mit Low-Level-Schnittstelle. Keine Unterstützung für verteilte Taktung.
Expert DC:      Standardcode mit Low-Level-Schnittstelle. Unterstützung für verteilte Taktung.
Expert Silent: Standardcode mit Low-Level-Schnittstelle. Unterstützung für verteilte Taktung und Silent-Modus.

Die Codevorlage wird automatisch mithilfe einer vordefinierten Vorlagencodedatei (*.tpl) und den generierten Headerdateien erstellt. Der Vorlagencode enthält drei gerätespezifische Einfügungen:

• Header-Datei-Includes
• Mapping-Strukturen
• SdoControls

Diese Informationen werden in den Vorlagencode eingefügt und machen ihn ausführbar.

Sample: Expert DC Code

//***************************************
//  Automated generated code template ***
//  EtherCAT Code Type : [Expert DC]  ***
//***************************************
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include "c:\sha\globdef64.h"
#include "c:\sha\sha64debug.h"
#include "c:\eth\Sha64EthCore.h"
#include "c:\eth\Eth64CoreDef.h"
#include "c:\eth\Eth64Macros.h"
#include "c:\ect\Sha64EcatCore.h"
#include "c:\ect\Ecat64CoreDef.h"
#include "c:\ect\Ecat64Macros.h"
#include "c:\ect\Ecat64Control.h"
#include "c:\ect\Ecat64SilentDef.h"
//Configuration Header Includes
#include "DevConfig_EK1100_2001091626.h"
#include "DevConfig_EL1008_2001091626.h"
#include "DevConfig_EL2004_2001091626.h"
#include "DevConfig_EL7041_2001081526.h"
#include "DevConfig_LXM32M_2001091624.h"
#pragma comment( lib, "c:\\sha\\sha64dll.lib" )
#pragma comment( lib, "c:\\eth\\sha64ethcore.lib" )
#pragma comment( lib, "c:\\ect\\sha64ecatcore.lib" )
#pragma warning(disable:4996)
#pragma warning(disable:4748)
#define REALTIME_PERIOD    2000           //Realtime sampling period [usec]
#define SYNC_CYCLES           1
//************************************
//#define SEQ_DEBUG                1
//************************************
//Declare global elements
PETH_STACK     __pUserStack = NULL;     //Ethernet Stack (outside Realtime Task)
PETH_STACK     __pSystemStack = NULL;   //Ethernet Stack (inside Realtime Task)
PSTATION_INFO  __pUserList = NULL;      //Station List (outside Realtime Task)
PSTATION_INFO  __pSystemList = NULL;    //Station List (inside Realtime Task)
USHORT         __StationNum = 0;        //Number of Stations
FP_ECAT_ENTER  __fpEcatEnter = NULL;    //Function pointer to Wrapper EcatEnter
FP_ECAT_EXIT   __fpEcatExit = NULL;     //Function pointer to Wrapper EcatExit
ULONG          __EcatState = 0;         //Initial Wrapper State
ULONG          __UpdateCnt = 0;         //Station Update Counter
ULONG          __LoopCnt = 0;           //Realtime Cycle Counter
ULONG          __ReadyCnt = 0;          //Ready state counter
STATE_OBJECT   __StateObject = { 0 };   //Cyclic state object
BOOLEAN        __bLogicReady = FALSE;   //Logic Ready Flag
//***************************
#ifdef SEQ_DEBUG
      SEQ_INIT_ELEMENTS(); //Init sequencing elements
#endif
//***************************
__inline PVOID __GetMapDataByName(char* szName, int Index, BOOLEAN bInput)
{
      int cnt = 0;
      //Loop through station list
      for (USHORT i=0; i<__StationNum;i++)
            if (strstr(__pUserList[i].szName, szName))
                  if (cnt++ == Index)
                  {
                        //Get station pointer and return index
                        if (bInput) { return __pUserList[i].RxTel.s.data; }
                        else        { return __pUserList[i].TxTel.s.data; }
                  }
      //Station not found
      return NULL;
}
void static DoLogic()
{
      //Get mapped data pointers
      //... more devices
      PTX_MAP_EL1008_2001091626 pTxMap_EL1008_0 = (PTX_MAP_EL1008_2001091626)__GetMapDataByName("EL1008", 0, TRUE);    //1. Device
      //PTX_MAP_EL1008_2001091626 pTxMap_EL1008_1 = (PTX_MAP_EL1008_2001091626)__GetMapDataByName("EL1008", 1, TRUE);    //2. Device
      //PTX_MAP_EL1008_2001091626 pTxMap_EL1008_2 = (PTX_MAP_EL1008_2001091626)__GetMapDataByName("EL1008", 2, TRUE);    //3. Device
      //... more devices
      PRX_MAP_EL2004_2001091626 pRxMap_EL2004_0 = (PRX_MAP_EL2004_2001091626)__GetMapDataByName("EL2004", 0, FALSE);   //1. Device
      //PRX_MAP_EL2004_2001091626 pRxMap_EL2004_1 = (PRX_MAP_EL2004_2001091626)__GetMapDataByName("EL2004", 1, FALSE);   //2. Device
      //PRX_MAP_EL2004_2001091626 pRxMap_EL2004_2 = (PRX_MAP_EL2004_2001091626)__GetMapDataByName("EL2004", 2, FALSE);   //3. Device
      //... more devices
      PTX_MAP_EL7041_2001081709 pTxMap_EL7041_0 = (PTX_MAP_EL7041_2001081709)__GetMapDataByName("EL7041", 0, TRUE);    //1. Device
      PRX_MAP_EL7041_2001081709 pRxMap_EL7041_0 = (PRX_MAP_EL7041_2001081709)__GetMapDataByName("EL7041", 0, FALSE);   //1. Device
      //PTX_MAP_EL7041_2001081709 pTxMap_EL7041_1 = (PTX_MAP_EL7041_2001081709)__GetMapDataByName("EL7041", 1, TRUE);    //2. Device
      //PRX_MAP_EL7041_2001081709 pRxMap_EL7041_1 = (PRX_MAP_EL7041_2001081709)__GetMapDataByName("EL7041", 1, FALSE);   //2. Device
      //PTX_MAP_EL7041_2001081709 pTxMap_EL7041_2 = (PTX_MAP_EL7041_2001081709)__GetMapDataByName("EL7041", 2, TRUE);    //3. Device
      //PRX_MAP_EL7041_2001081709 pRxMap_EL7041_2 = (PRX_MAP_EL7041_2001081709)__GetMapDataByName("EL7041", 2, FALSE);   //3. Device
      //... more devices
      PTX_MAP_LXM32M_2001091624 pTxMap_LXM32M_0 = (PTX_MAP_LXM32M_2001091624)__GetMapDataByName("LXM32M", 0, TRUE);    //1. Device
      PRX_MAP_LXM32M_2001091624 pRxMap_LXM32M_0 = (PRX_MAP_LXM32M_2001091624)__GetMapDataByName("LXM32M", 0, FALSE);   //1. Device
      //PTX_MAP_LXM32M_2001091624 pTxMap_LXM32M_1 = (PTX_MAP_LXM32M_2001091624)__GetMapDataByName("LXM32M", 1, TRUE);    //2. Device
      //PRX_MAP_LXM32M_2001091624 pRxMap_LXM32M_1 = (PRX_MAP_LXM32M_2001091624)__GetMapDataByName("LXM32M", 1, FALSE);   //2. Device
      //PTX_MAP_LXM32M_2001091624 pTxMap_LXM32M_2 = (PTX_MAP_LXM32M_2001091624)__GetMapDataByName("LXM32M", 2, TRUE);    //3. Device
      //PRX_MAP_LXM32M_2001091624 pRxMap_LXM32M_2 = (PRX_MAP_LXM32M_2001091624)__GetMapDataByName("LXM32M", 2, FALSE);   //3. Device
      //... more devices
      //ToDo: Payload logic
      //...
//****************************
#ifdef SEQ_DEBUG
      SYSTEM_SEQ_CAPTURE("SEQ", __LINE__, 0, TRUE);
#endif
//****************************
}
void static AppTask(PVOID)
{
      //Call enter wrapper function
      __EcatState = __fpEcatEnter(
                                         __pSystemStack,
                                         __pSystemList,
                                         (USHORT)__StationNum,
                                         &__StateObject);
      //Check operation state and increase ready count
      if (__EcatState == ECAT_STATE_READY) { __ReadyCnt--; }
      else                                 { __ReadyCnt = SYNC_CYCLES; }
      //Check ready count
      if (__ReadyCnt == 1)
      {
            //**********************************
            if (__bLogicReady) { DoLogic(); }
            //**********************************
            //Update counter
            __UpdateCnt++;
      }
      //Call exit function
      __fpEcatExit();
     
      //Increase loop count
      __LoopCnt++;
}
__inline ULONG __SdoControl(void)
{
      //Loop through station list
      for (USHORT i=0; i<__StationNum;i++)
      {
             PSTATION_INFO pStation = (PSTATION_INFO)&__pUserList[i];
            //Do Device SDO control
            if (strstr(pStation->szName, "EL7041"))
if (__SdoControl_EL7041_2001081709(pStation) == FALSE)
return (-1);
            if (strstr(pStation->szName, "LXM32M"))
if (__SdoControl_LXM32M_2001091624(pStation) == FALSE)
return (-1);
      }
      //Do default PDO assignment
      return Ecat64PdoAssignment();
}
void main(void)
{
//******************
#ifdef SEQ_DEBUG
      SEQ_ATTACH();                                  //Attach to sequence memory
      SEQ_RESET(TRUE, FALSE, NULL, 0);   //Reset/Init sequence memory
#endif
//******************
      printf("\n*** EtherCAT Code Type: [Expert DC] ***\n\n");
      //Set ethernet mode
      __EcatSetEthernetMode(0, REALTIME_PERIOD, SYNC_CYCLES, TRUE);
      //Required ECAT parameters
      ECAT_PARAMS EcatParams;
      memset(&EcatParams, 0, sizeof(ECAT_PARAMS));
      EcatParams.PhysAddr = DEFAULT_PHYSICAL_ADDRESS;
      EcatParams.LogicalAddr = DEFAULT_LOGICAL_ADDRESS;
      EcatParams.SyncCycles = SYNC_CYCLES;                 //Set cycles for synchronisation interval
      EcatParams.EthParams.dev_num = 0;                    //Set NIC index [0..7]
      EcatParams.EthParams.period = REALTIME_PERIOD; //Set realtime period [µsec]
      EcatParams.EthParams.fpAppTask = AppTask;
      //******************************
      //Create ECAT realtime core
      //******************************
      if (ERROR_SUCCESS == Sha64EcatCreate(&EcatParams))
      {
            Sleep(1000);
            //Init global elements
            __pUserStack      = EcatParams.EthParams.pUserStack;
            __pSystemStack    = EcatParams.EthParams.pSystemStack;
            __pUserList       = EcatParams.pUserList;
            __pSystemList     = EcatParams.pSystemList;
            __StationNum      = EcatParams.StationNum;
            __fpEcatEnter     = EcatParams.fpEcatEnter;
            __fpEcatExit      = EcatParams.fpEcatExit;
            //Display station information
            for (int i=0; i<__StationNum; i++)
                  printf("Station: %i, Name: %6s\n", i, __pUserList[i].szName);
            //******************************
            //Enable Stations
            //******************************
            //Change state to INIT
            if (ERROR_SUCCESS == Ecat64ChangeAllStates(AL_STATE_INIT))
            {
                  UCHAR Data[0x100] = { 0 };
                  //Reset devices
                  Ecat64ResetDevices();
                  Ecat64SendCommand(BWR_CMD, 0x0000,  0x300, 8, Data);
                  //Set fixed station addresses and
                  //Init FMMUs and SYNCMANs
                  if (ERROR_SUCCESS ==
                                    Ecat64InitStationAddresses(EcatParams.PhysAddr))
                  if (ERROR_SUCCESS == Ecat64InitFmmus(EcatParams.LogicalAddr))
                  if (ERROR_SUCCESS == Ecat64InitSyncManagers())
                  {
                        //Change state to PRE OPERATIONAL
                        //Init PDO assignment
                        if (ERROR_SUCCESS == Ecat64ChangeAllStates(AL_STATE_PRE_OP))
                        if (ERROR_SUCCESS == __SdoControl())
                        {
                              //Drift compensation delay [msec]
                              ULONG CompLoops = 1000;
                              //Init DC immediately after cyclic operation started
                              //and get static master drift per msec (nsec unit)
                              if (ERROR_SUCCESS == Ecat64ReadDcLocalTime())
                              if (ERROR_SUCCESS == Ecat64CompDcOffset())
                              if (ERROR_SUCCESS == Ecat64CompDcPropDelay())
                              if (ERROR_SUCCESS == Ecat64CompDcDrift(&CompLoops))
                              if (ERROR_SUCCESS == Ecat64DcControl())
                              {
                                   //Init process telegrams (required for
//AL_STATE_SAFE_OP)
                                   Ecat64InitProcessTelegrams();
                                    //********************************************************
      //Start cyclic operation
      //********************************************************
                                   if (ERROR_SUCCESS ==
            Ecat64CyclicStateControl(&__StateObject, AL_STATE_SAFE_OP)) { Sleep(500);
                                   if (ERROR_SUCCESS ==
            Ecat64CyclicStateControl(&__StateObject, AL_STATE_OP))      { Sleep(100);
                                               //Set Logic Ready Flag
                                               __bLogicReady = TRUE;
                                               //Do a check loop
                                               printf("\nPress any key ...\n");
                                               while (!kbhit())
                                               {
                                                     //Display TX and RX information
                                                     printf("Update Count: %i\r",
                                                           __UpdateCnt);
           
                                                     //Do some delay
                                                     Sleep(100);
                                               }
                                               //Reset Logic Ready Flag
                                               __bLogicReady = FALSE;
                                               Sleep(100);
           
      //********************************************************
      //Stop cyclic operation
      //********************************************************
                                               Ecat64CyclicStateControl(&__StateObject, AL_STATE_INIT);
                                         }
                                   }
                              }
                        }
                  }
            }
            //Destroy ECAT core
            Sha64EcatDestroy(&EcatParams);
      }
     //Check Status
      If (EcatParams.EthParams.pUserStack == NULL)
                  { printf("\n*** Ethernet Stack Failed ***\n"); }
      else if (EcatParams.EthParams.err_cnts.Phy != 0)
                  { printf("\n*** No Link ***\n"); }
      else if (EcatParams.pUserList == NULL)
                  { printf("\n*** No Station List ***\n"); }
      else if (EcatParams.StationNum == 0)
                  { printf("\n*** No Station Found ***\n"); }
      else        { printf("\n*** OK ***\n"); }
      //Wait for key press
      printf("\nPress any key ...\n");
      while (!kbhit()) { Sleep(100); }
//******************
#ifdef SEQ_DEBUG
      SEQ_DETACH(); //Detach from sequence memory
#endif
//******************
}