Windows10 利用QT搭建SOEM开发环境

devtools/2024/9/18 23:13:56/ 标签: qt, mfc, 倍福, EtherCAT

文章目录

  • 一. SOEM库简介
  • 二. 安装WinPcap
  • 三. SOEM(1.4)库安装
    • (1) 编译32位库
    • (2) 编译64位库
  • 四. 运行SOEM示例代码
  • 五. WIN10下利用QT构建SOEM开发环境

一. SOEM库简介

SOEM(Scalable Open EtherCAT Master 或 Simple Open EtherCAT Master)是一个开源的、用于EtherCAT通信协议的软件库。EtherCAT(Ethernet for Control Automation Technology)是一种实时以太网通信协议,广泛应用于自动化和机器人技术中,以其高速和低延迟特性而受到青睐。SOEM库允许开发者在他们的应用程序中实现EtherCAT主站功能,从而控制和驱动EtherCAT从站设备。

以下是SOEM库的一些关键特点和优势:

  • 开源和免费:SOEM是开源的,使用LGPLv2.1授权,可以自由使用、修改和分发。
  • 跨平台支持:SOEM支持多种操作系统,包括Linux、FreeRTOS、VxWorks、QNX等,提供跨平台的灵活性。
  • 实时性能:SOEM直接与硬件交互,确保了低延迟和高数据吞吐量,满足实时性要求。
  • 易于集成:SOEM使用标准的设备驱动模型,简化了在现有系统中添加EtherCAT功能的过程。
  • 文档完善:提供详细的API文档和示例代码,帮助开发者快速上手。
  • 社区支持:作为一个开源项目,SOEM拥有活跃的社区支持,不断有更新和问题解决方案。

SOEM库适用于工业自动化、实验室研究、开源硬件项目和教育用途等多种场景。它为用户应用程序提供了发送和接收EtherCAT帧的方法,支持读写过程数据、保持本地IO数据与全局IO映射同步、检测和管理系统错误等功能。

开发者可以通过研究SOEM的源码来深入理解EtherCAT主站与从站之间的交互方式,这不仅有助于学习EtherCAT协议,还能在此基础上进行定制和优化,以满足特定的应用需求。SOEM项目在GitHub上维护,提供了完整的示例应用和配置文件,方便开发者获取和使用。

二. 安装WinPcap

WinPcap库

  1. 下载并安装WinPcap运行库:官网:http://www.winpcap.org/install/default.htm
    在这里插入图片描述
  2. 运行下载好的exe文件,点击下一步
    在这里插入图片描述
  3. 点击同意
    在这里插入图片描述
  4. 点击安装
    在这里插入图片描述
  5. 点击完成
    在这里插入图片描述

三. SOEM(1.4)库安装

(1) 编译32位库

  1. 官网下载SOEM源文件
    在这里插入图片描述

  2. 运行VS2019的命令行
    在这里插入图片描述

  3. 进入下载好的SOEM源文件
    在这里插入图片描述

  4. 在源文件目录下创建build文件夹,并进入

    mkdir build
    cd build
    

    在这里插入图片描述

  5. 运行以下命令,编译源文件

    cmake .. -G "NMake Makefiles"
    nmake
    

    在这里插入图片描述

  6. 运行以下命令生成调用库

    namke install
    

    在这里插入图片描述

(2) 编译64位库

  1. 官网下载SOEM源文件
    在这里插入图片描述

  2. 运行VS2019的命令行
    在这里插入图片描述

  3. 进入下载好的SOEM源文件
    在这里插入图片描述

  4. 在源文件目录下创建build文件夹,并进入

    mkdir build
    
  5. 运行以下命令,编译源文件

    cmake .. -G "Visual Studio 16 2019" -S . -B build
    

    在这里插入图片描述

  6. 进入build文件夹,用vs2019打开soem.sln项目

    namke install
    

    在这里插入图片描述

  7. 点击生成,点击配置管理器
    在这里插入图片描述

  8. 选择要生成的内容
    在这里插入图片描述

  9. 点击生成解决方案
    在这里插入图片描述

  10. 没有报错则完成,可以在debug文件夹中找到生成的库文件
    在这里插入图片描述
    在这里插入图片描述

四. 运行SOEM示例代码

  1. 编译好的SOEM文件夹中有例程(simple_ng)
    在这里插入图片描述

  2. cmd中运行simple_ng,可以看到电脑带的所有的网卡信息
    在这里插入图片描述

  3. 选择已经接入EtherCAT从站的网口,复制网口信息(\Device\NPF_{51D73200-BC7C-4562-8918-04FA9C959372}),cmd中运行如下代码

    simple_ng \Device\NPF_{51D73200-BC7C-4562-8918-04FA9C959372}
    

    在这里插入图片描述

  4. 通过-map指令,可以查看从站的I/O配置

    slaveinfo \Device\NPF_{A837AD34-3738-42FF-8E0B-F5B0BE69ABD6} -map
    

    在这里插入图片描述

五. WIN10下利用QT构建SOEM开发环境

  1. 在QT中创建一个新c++项目,CMakeList.txt文件如下

    cmake_minimum_required(VERSION 3.5)project(SOEMTest LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)set(SOEM_DIR "C:\\Users\\10001540\\Downloads\\SOEM-master")
    include_directories(${SOEM_DIR}\\install\\include\\soem\\ ${SOEM_DIR}\\oshw\\win32\\wpcap\\Include\\)
    link_directories(C:\\Users\\10001540\\Downloads\\SOEM-master\\build\\Debug\\ ${SOEM_DIR}\\oshw\\win32\\wpcap\\Lib\\x64\\)add_executable(SOEMTest main.cpp)target_link_libraries(SOEMTest PUBLIC soem.lib Packet.lib wpcap.lib Ws2_32.lib Winmm.lib)install(TARGETS SOEMTestLIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})message(STATUS "The system is: ${CMAKE_SYSTEM_NAME}")
    
  2. main函数中,代码如下:

    #include <iostream>
    #include "ethercat.h"using namespace std;char IOmap[4096];
    ec_ODlistt ODlist;
    ec_OElistt OElist;
    boolean printSDO = FALSE;
    boolean printMAP = FALSE;
    char usdo[128];
    char hstr[1024];char* dtype2string(uint16 dtype)
    {switch(dtype){case ECT_BOOLEAN:sprintf(hstr, "BOOLEAN");break;case ECT_INTEGER8:sprintf(hstr, "INTEGER8");break;case ECT_INTEGER16:sprintf(hstr, "INTEGER16");break;case ECT_INTEGER32:sprintf(hstr, "INTEGER32");break;case ECT_INTEGER24:sprintf(hstr, "INTEGER24");break;case ECT_INTEGER64:sprintf(hstr, "INTEGER64");break;case ECT_UNSIGNED8:sprintf(hstr, "UNSIGNED8");break;case ECT_UNSIGNED16:sprintf(hstr, "UNSIGNED16");break;case ECT_UNSIGNED32:sprintf(hstr, "UNSIGNED32");break;case ECT_UNSIGNED24:sprintf(hstr, "UNSIGNED24");break;case ECT_UNSIGNED64:sprintf(hstr, "UNSIGNED64");break;case ECT_REAL32:sprintf(hstr, "REAL32");break;case ECT_REAL64:sprintf(hstr, "REAL64");break;case ECT_BIT1:sprintf(hstr, "BIT1");break;case ECT_BIT2:sprintf(hstr, "BIT2");break;case ECT_BIT3:sprintf(hstr, "BIT3");break;case ECT_BIT4:sprintf(hstr, "BIT4");break;case ECT_BIT5:sprintf(hstr, "BIT5");break;case ECT_BIT6:sprintf(hstr, "BIT6");break;case ECT_BIT7:sprintf(hstr, "BIT7");break;case ECT_BIT8:sprintf(hstr, "BIT8");break;case ECT_VISIBLE_STRING:sprintf(hstr, "VISIBLE_STRING");break;case ECT_OCTET_STRING:sprintf(hstr, "OCTET_STRING");break;default:sprintf(hstr, "Type 0x%4.4X", dtype);}return hstr;
    }char* SDO2string(uint16 slave, uint16 index, uint8 subidx, uint16 dtype)
    {int l = sizeof(usdo) - 1, i;uint8 *u8;int8 *i8;uint16 *u16;int16 *i16;uint32 *u32;int32 *i32;uint64 *u64;int64 *i64;float *sr;double *dr;char es[32];memset(&usdo, 0, 128);ec_SDOread(slave, index, subidx, FALSE, &l, &usdo, EC_TIMEOUTRXM);if (EcatError){return ec_elist2string();}else{switch(dtype){case ECT_BOOLEAN:u8 = (uint8*) &usdo[0];if (*u8) sprintf(hstr, "TRUE");else sprintf(hstr, "FALSE");break;case ECT_INTEGER8:i8 = (int8*) &usdo[0];sprintf(hstr, "0x%2.2x %d", *i8, *i8);break;case ECT_INTEGER16:i16 = (int16*) &usdo[0];sprintf(hstr, "0x%4.4x %d", *i16, *i16);break;case ECT_INTEGER32:case ECT_INTEGER24:i32 = (int32*) &usdo[0];sprintf(hstr, "0x%8.8x %d", *i32, *i32);break;case ECT_INTEGER64:i64 = (int64*) &usdo[0];//sprintf(hstr, "0x%16.16"PRIx64" %"PRId64, *i64, *i64);break;case ECT_UNSIGNED8:u8 = (uint8*) &usdo[0];sprintf(hstr, "0x%2.2x %u", *u8, *u8);break;case ECT_UNSIGNED16:u16 = (uint16*) &usdo[0];sprintf(hstr, "0x%4.4x %u", *u16, *u16);break;case ECT_UNSIGNED32:case ECT_UNSIGNED24:u32 = (uint32*) &usdo[0];sprintf(hstr, "0x%8.8x %u", *u32, *u32);break;case ECT_UNSIGNED64:u64 = (uint64*) &usdo[0];//sprintf(hstr, "0x%16.16"PRIx64" %"PRIu64, *u64, *u64);break;case ECT_REAL32:sr = (float*) &usdo[0];sprintf(hstr, "%f", *sr);break;case ECT_REAL64:dr = (double*) &usdo[0];sprintf(hstr, "%f", *dr);break;case ECT_BIT1:case ECT_BIT2:case ECT_BIT3:case ECT_BIT4:case ECT_BIT5:case ECT_BIT6:case ECT_BIT7:case ECT_BIT8:u8 = (uint8*) &usdo[0];sprintf(hstr, "0x%x", *u8);break;case ECT_VISIBLE_STRING:strcpy(hstr, usdo);break;case ECT_OCTET_STRING:hstr[0] = 0x00;for (i = 0 ; i < l ; i++){sprintf(es, "0x%2.2x ", usdo[i]);strcat( hstr, es);}break;default:sprintf(hstr, "Unknown type");}return hstr;}
    }/** Read PDO assign structure */
    int si_PDOassign(uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset)
    {uint16 idxloop, nidx, subidxloop, rdat, idx, subidx;uint8 subcnt;int wkc, bsize = 0, rdl;int32 rdat2;uint8 bitlen, obj_subidx;uint16 obj_idx;int abs_offset, abs_bit;rdl = sizeof(rdat); rdat = 0;/* read PDO assign subindex 0 ( = number of PDO's) */wkc = ec_SDOread(slave, PDOassign, 0x00, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);rdat = etohs(rdat);/* positive result from slave ? */if ((wkc > 0) && (rdat > 0)){/* number of available sub indexes */nidx = rdat;bsize = 0;/* read all PDO's */for (idxloop = 1; idxloop <= nidx; idxloop++){rdl = sizeof(rdat); rdat = 0;/* read PDO assign */wkc = ec_SDOread(slave, PDOassign, (uint8)idxloop, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);/* result is index of PDO */idx = etohl(rdat);if (idx > 0){rdl = sizeof(subcnt); subcnt = 0;/* read number of subindexes of PDO */wkc = ec_SDOread(slave,idx, 0x00, FALSE, &rdl, &subcnt, EC_TIMEOUTRXM);subidx = subcnt;/* for each subindex */for (subidxloop = 1; subidxloop <= subidx; subidxloop++){rdl = sizeof(rdat2); rdat2 = 0;/* read SDO that is mapped in PDO */wkc = ec_SDOread(slave, idx, (uint8)subidxloop, FALSE, &rdl, &rdat2, EC_TIMEOUTRXM);rdat2 = etohl(rdat2);/* extract bitlength of SDO */bitlen = LO_BYTE(rdat2);bsize += bitlen;obj_idx = (uint16)(rdat2 >> 16);obj_subidx = (uint8)((rdat2 >> 8) & 0x000000ff);abs_offset = mapoffset + (bitoffset / 8);abs_bit = bitoffset % 8;ODlist.Slave = slave;ODlist.Index[0] = obj_idx;OElist.Entries = 0;wkc = 0;/* read object entry from dictionary if not a filler (0x0000:0x00) */if(obj_idx || obj_subidx)wkc = ec_readOEsingle(0, obj_subidx, &ODlist, &OElist);printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);if((wkc > 0) && OElist.Entries){printf(" %-12s %s\n", dtype2string(OElist.DataType[obj_subidx]), OElist.Name[obj_subidx]);}elseprintf("\n");bitoffset += bitlen;};};};};/* return total found bitlength (PDO) */return bsize;
    }int si_map_sdo(int slave)
    {int wkc, rdl;int retVal = 0;uint8 nSM, iSM, tSM;int Tsize, outputs_bo, inputs_bo;uint8 SMt_bug_add;printf("PDO mapping according to CoE :\n");SMt_bug_add = 0;outputs_bo = 0;inputs_bo = 0;rdl = sizeof(nSM); nSM = 0;/* read SyncManager Communication Type object count */wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, 0x00, FALSE, &rdl, &nSM, EC_TIMEOUTRXM);/* positive result from slave ? */if ((wkc > 0) && (nSM > 2)){/* make nSM equal to number of defined SM */nSM--;/* limit to maximum number of SM defined, if true the slave can't be configured */if (nSM > EC_MAXSM)nSM = EC_MAXSM;/* iterate for every SM type defined */for (iSM = 2 ; iSM <= nSM ; iSM++){rdl = sizeof(tSM); tSM = 0;/* read SyncManager Communication Type */wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, iSM + 1, FALSE, &rdl, &tSM, EC_TIMEOUTRXM);if (wkc > 0){if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave!{SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4printf("Activated SM type workaround, possible incorrect mapping.\n");}if(tSM)tSM += SMt_bug_add; // only add if SMt > 0if (tSM == 3) // outputs{/* read the assign RXPDO */printf("  SM%1d outputs\n     addr b   index: sub bitl data_type    name\n", iSM);Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].outputs - (uint8 *)&IOmap[0]), outputs_bo );outputs_bo += Tsize;}if (tSM == 4) // inputs{/* read the assign TXPDO */printf("  SM%1d inputs\n     addr b   index: sub bitl data_type    name\n", iSM);Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].inputs - (uint8 *)&IOmap[0]), inputs_bo );inputs_bo += Tsize;}}}}/* found some I/O bits ? */if ((outputs_bo > 0) || (inputs_bo > 0))retVal = 1;return retVal;
    }int si_siiPDO(uint16 slave, uint8 t, int mapoffset, int bitoffset)
    {uint16 a , w, c, e, er, Size;uint8 eectl;uint16 obj_idx;uint8 obj_subidx;uint8 obj_name;uint8 obj_datatype;uint8 bitlen;int totalsize;ec_eepromPDOt eepPDO;ec_eepromPDOt *PDO;int abs_offset, abs_bit;char str_name[EC_MAXNAME + 1];eectl = ec_slave[slave].eep_pdi;Size = 0;totalsize = 0;PDO = &eepPDO;PDO->nPDO = 0;PDO->Length = 0;PDO->Index[1] = 0;for (c = 0 ; c < EC_MAXSM ; c++) PDO->SMbitsize[c] = 0;if (t > 1)t = 1;PDO->Startpos = ec_siifind(slave, ECT_SII_PDO + t);if (PDO->Startpos > 0){a = PDO->Startpos;w = ec_siigetbyte(slave, a++);w += (ec_siigetbyte(slave, a++) << 8);PDO->Length = w;c = 1;/* traverse through all PDOs */do{PDO->nPDO++;PDO->Index[PDO->nPDO] = ec_siigetbyte(slave, a++);PDO->Index[PDO->nPDO] += (ec_siigetbyte(slave, a++) << 8);PDO->BitSize[PDO->nPDO] = 0;c++;/* number of entries in PDO */e = ec_siigetbyte(slave, a++);PDO->SyncM[PDO->nPDO] = ec_siigetbyte(slave, a++);a++;obj_name = ec_siigetbyte(slave, a++);a += 2;c += 2;if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) /* active and in range SM? */{str_name[0] = 0;if(obj_name)ec_siistring(str_name, slave, obj_name);if (t)printf("  SM%1d RXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name);elseprintf("  SM%1d TXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name);printf("     addr b   index: sub bitl data_type    name\n");/* read all entries defined in PDO */for (er = 1; er <= e; er++){c += 4;obj_idx = ec_siigetbyte(slave, a++);obj_idx += (ec_siigetbyte(slave, a++) << 8);obj_subidx = ec_siigetbyte(slave, a++);obj_name = ec_siigetbyte(slave, a++);obj_datatype = ec_siigetbyte(slave, a++);bitlen = ec_siigetbyte(slave, a++);abs_offset = mapoffset + (bitoffset / 8);abs_bit = bitoffset % 8;PDO->BitSize[PDO->nPDO] += bitlen;a += 2;str_name[0] = 0;if(obj_name)ec_siistring(str_name, slave, obj_name);printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);printf(" %-12s %s\n", dtype2string(obj_datatype), str_name);bitoffset += bitlen;totalsize += bitlen;}PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO];Size += PDO->BitSize[PDO->nPDO];c++;}else /* PDO deactivated because SM is 0xff or > EC_MAXSM */{c += 4 * e;a += 8 * e;c++;}if (PDO->nPDO >= (EC_MAXEEPDO - 1)) c = PDO->Length; /* limit number of PDO entries in buffer */}while (c < PDO->Length);}if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */return totalsize;
    }int si_map_sii(int slave)
    {int retVal = 0;int Tsize, outputs_bo, inputs_bo;printf("PDO mapping according to SII :\n");outputs_bo = 0;inputs_bo = 0;/* read the assign RXPDOs */Tsize = si_siiPDO(slave, 1, (int)(ec_slave[slave].outputs - (uint8*)&IOmap), outputs_bo );outputs_bo += Tsize;/* read the assign TXPDOs */Tsize = si_siiPDO(slave, 0, (int)(ec_slave[slave].inputs - (uint8*)&IOmap), inputs_bo );inputs_bo += Tsize;/* found some I/O bits ? */if ((outputs_bo > 0) || (inputs_bo > 0))retVal = 1;return retVal;
    }void si_sdo(int cnt)
    {int i, j;ODlist.Entries = 0;memset(&ODlist, 0, sizeof(ODlist));if( ec_readODlist(cnt, &ODlist)){printf(" CoE Object Description found, %d entries.\n",ODlist.Entries);for( i = 0 ; i < ODlist.Entries ; i++){ec_readODdescription(i, &ODlist);while(EcatError) printf("%s", ec_elist2string());printf(" Index: %4.4x Datatype: %4.4x Objectcode: %2.2x Name: %s\n",ODlist.Index[i], ODlist.DataType[i], ODlist.ObjectCode[i], ODlist.Name[i]);memset(&OElist, 0, sizeof(OElist));ec_readOE(i, &ODlist, &OElist);while(EcatError) printf("%s", ec_elist2string());for( j = 0 ; j < ODlist.MaxSub[i]+1 ; j++){if ((OElist.DataType[j] > 0) && (OElist.BitLength[j] > 0)){printf("  Sub: %2.2x Datatype: %4.4x Bitlength: %4.4x Obj.access: %4.4x Name: %s\n",j, OElist.DataType[j], OElist.BitLength[j], OElist.ObjAccess[j], OElist.Name[j]);if ((OElist.ObjAccess[j] & 0x0007)){printf("          Value :%s\n", SDO2string(cnt, ODlist.Index[i], j, OElist.DataType[j]));}}}}}else{while(EcatError) printf("%s", ec_elist2string());}
    }void slaveinfo(char *ifname)
    {int cnt, i, j, nSM;uint16 ssigen;int expectedWKC;ecx_contextt* contex;printf("Starting slaveinfo\n");if(ec_init(ifname)) // 初始化SOEM库,绑定soket到网口{printf("ec_init on %s succeeded.\n",ifname);if(ec_config(FALSE, &IOmap) > 0) // 枚举所有从站的信息,并配置从站,保存到IOmap中{ec_configdc();while(EcatError){cout<< ec_elist2string() << endl;}printf("%d slaves found and configured.\n",ec_slavecount);expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;printf("Calculated workcounter %d\n", expectedWKC);ec_statecheck(0, EC_STATE_SAFE_OP,  EC_TIMEOUTSTATE * 3);if (ec_slave[0].state != EC_STATE_SAFE_OP ){printf("Not all slaves reached safe operational state.\n");ec_readstate();for(i = 1; i<=ec_slavecount ; i++){if(ec_slave[i].state != EC_STATE_SAFE_OP){printf("Slave %d State=%2x StatusCode=%4x : %s\n",i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode));}}}ec_readstate();for( cnt = 1 ; cnt <= ec_slavecount ; cnt++){printf("\nSlave:%d\n Name:%s\n Output size: %dbits\n Input size: %dbits\n State: %d\n Delay: %d[ns]\n Has DC: %d\n",cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits,ec_slave[cnt].state, ec_slave[cnt].pdelay, ec_slave[cnt].hasdc);if (ec_slave[cnt].hasdc) printf(" DCParentport:%d\n", ec_slave[cnt].parentport);printf(" Activeports:%d.%d.%d.%d\n", (ec_slave[cnt].activeports & 0x01) > 0 ,(ec_slave[cnt].activeports & 0x02) > 0 ,(ec_slave[cnt].activeports & 0x04) > 0 ,(ec_slave[cnt].activeports & 0x08) > 0 );printf(" Configured address: %4.4x\n", ec_slave[cnt].configadr);printf(" Man: %8.8x ID: %8.8x Rev: %8.8x\n", (int)ec_slave[cnt].eep_man, (int)ec_slave[cnt].eep_id, (int)ec_slave[cnt].eep_rev);for(nSM = 0 ; nSM < EC_MAXSM ; nSM++){if(ec_slave[cnt].SM[nSM].StartAddr > 0)printf(" SM%1d A:%4.4x L:%4d F:%8.8x Type:%d\n",nSM, ec_slave[cnt].SM[nSM].StartAddr, ec_slave[cnt].SM[nSM].SMlength,(int)ec_slave[cnt].SM[nSM].SMflags, ec_slave[cnt].SMtype[nSM]);}for(j = 0 ; j < ec_slave[cnt].FMMUunused ; j++){printf(" FMMU%1d Ls:%8.8x Ll:%4d Lsb:%d Leb:%d Ps:%4.4x Psb:%d Ty:%2.2x Act:%2.2x\n", j,(int)ec_slave[cnt].FMMU[j].LogStart, ec_slave[cnt].FMMU[j].LogLength, ec_slave[cnt].FMMU[j].LogStartbit,ec_slave[cnt].FMMU[j].LogEndbit, ec_slave[cnt].FMMU[j].PhysStart, ec_slave[cnt].FMMU[j].PhysStartBit,ec_slave[cnt].FMMU[j].FMMUtype, ec_slave[cnt].FMMU[j].FMMUactive);}printf(" FMMUfunc 0:%d 1:%d 2:%d 3:%d\n",ec_slave[cnt].FMMU0func, ec_slave[cnt].FMMU1func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU3func);printf(" MBX length wr: %d rd: %d MBX protocols : %2.2x\n", ec_slave[cnt].mbx_l, ec_slave[cnt].mbx_rl, ec_slave[cnt].mbx_proto);ssigen = ec_siifind(cnt, ECT_SII_GENERAL);/* SII general section */if (ssigen){ec_slave[cnt].CoEdetails = ec_siigetbyte(cnt, ssigen + 0x07);ec_slave[cnt].FoEdetails = ec_siigetbyte(cnt, ssigen + 0x08);ec_slave[cnt].EoEdetails = ec_siigetbyte(cnt, ssigen + 0x09);ec_slave[cnt].SoEdetails = ec_siigetbyte(cnt, ssigen + 0x0a);if((ec_siigetbyte(cnt, ssigen + 0x0d) & 0x02) > 0){ec_slave[cnt].blockLRW = 1;ec_slave[0].blockLRW++;}ec_slave[cnt].Ebuscurrent = ec_siigetbyte(cnt, ssigen + 0x0e);ec_slave[cnt].Ebuscurrent += ec_siigetbyte(cnt, ssigen + 0x0f) << 8;ec_slave[0].Ebuscurrent += ec_slave[cnt].Ebuscurrent;}printf(" CoE details: %2.2x FoE details: %2.2x EoE details: %2.2x SoE details: %2.2x\n",ec_slave[cnt].CoEdetails, ec_slave[cnt].FoEdetails, ec_slave[cnt].EoEdetails, ec_slave[cnt].SoEdetails);printf(" Ebus current: %d[mA]\n only LRD/LWR:%d\n",ec_slave[cnt].Ebuscurrent, ec_slave[cnt].blockLRW);if ((ec_slave[cnt].mbx_proto & ECT_MBXPROT_COE) && printSDO){si_sdo(cnt);}if (ec_slave[cnt].mbx_proto & ECT_MBXPROT_COE)si_map_sdo(cnt);elsesi_map_sii(cnt);}}}else{}
    }int main()
    {char* ifbuf = "\\Device\\NPF_{A837AD34-3738-42FF-8E0B-F5B0BE69ABD6}"; // 网口设备号printf("SOEM (Simple Open EtherCAT Master)\nSlaveinfo\n");slaveinfo(ifbuf);return 0;
    }
    

    在这里插入图片描述


http://www.ppmy.cn/devtools/53570.html

相关文章

钡铼BL102应用智能电网配电柜PLC转MQTT无线接云服务

在当今智能电网的发展浪潮中&#xff0c;配电系统的智能化升级是提升电网效率与稳定性的重要环节。随着物联网技术的飞速发展&#xff0c;实现配电柜的远程监控与管理成为了可能&#xff0c;而这一转变的关键在于如何有效地将传统配电柜中的PLC数据接入到云端进行分析与处理。 …

skywalking9.4 链路追踪

下载&#xff0c;很慢很慢很慢&#xff01;&#xff01;&#xff01;&#xff01; jdk 使用jdk17 skywalking-apm 9.4 java-agent 9.0 idea 本地开发配置 第1行配置按实际来&#xff1b; 第2行自定义&#xff0c;一般和微服务名称相同&#xff1b; 第3行ip写安装的机器ip,端…

基于C#开发web网页管理系统模板流程-总集篇

第一篇 基于C#开发web网页管理系统模板流程-登录界面和主界面_c#的网页编程-CSDN博客 第二篇 基于C#开发web网页管理系统模板流程-主界面管理员录入和编辑功能完善_c#网页设计-CSDN博客 第三篇 基于C#开发web网页管理系统模板流程-主界面管理员入库和出库功能完善_c#web程序设计…

【后端开发】服务开发场景之高可用(冗余设计,服务限流,降级熔断,超时重试,性能测试)

【后端开发】服务开发场景之高可用&#xff08;冗余设计&#xff0c;服务限流&#xff0c;降级熔断&#xff0c;超时重试&#xff0c;性能测试&#xff09; 文章目录 序&#xff1a;如何设计一个高可用的系统&#xff1f;可用性的判断指标是什么&#xff1f;哪些情况会导致系统…

【机器学习】基于RoBERTa模型的句子嵌入实践

1.引言 1.1.RoBERTa模型开发背景 BERT模型自发布以来&#xff0c;就以其卓越的性能和广泛的应用领域&#xff0c;在NLP领域引起了巨大的轰动。BERT通过预训练大量文本数据&#xff0c;学习到了丰富的语言表示&#xff0c;并在多个NLP任务上取得了显著的效果提升。然而&#x…

【源码】校园小情书小程序最新版 校园小程序开发 微信情书小程序 校园小情书小程序源代码

校园小情书微信小程序源码 | 社区小程序前后端开源 | 校园表白墙交友小程序 功能&#xff1a; 表白墙 卖舍友 步数旅行 步数排行榜 情侣脸 漫画脸 个人主页 私信 站内消息 今日话题 评论点赞收藏 服务器环境要求&#xff1a;PHP7.0 MySQL5.7 …

LVS ipvsadm命令的使用(二)

目录 上篇&#xff1a;负载均衡集群&#xff08;一&#xff09;-CSDN博客 命令参数概述 调度算法 基本命令 1. 添加虚拟服务器 2. 添加真实服务器 3. 删除虚拟服务器 4. 删除真实服务器 5. 列出当前配置 6. 修改服务器权重 7.保存规则 8. 清除所有配置 进行增加虚拟…

Nginx-Rewrite

1、Rewrite的定义 rewrite功能就是使用nginx提供的全局变量或自己设置的变量&#xff0c;结合正则表达式和标志位实现url重写以及重定向。rewrite只能放在 server { }, location { }, if { }中&#xff0c;并且只能对域名后边的除去传递的参数外的字符串起作用。 例如location…

【Linux】如何创建yum 组(yum groups)

如何创建yum 组(yum groups) 在 yum 中创建组信息需要手动编辑并创建一个组文件&#xff0c;然后使用 createrepo 工具生成组信息。以下是一个详细的步骤指南&#xff1a; 1. 创建组信息文件 首先&#xff0c;创建一个 XML 文件来定义组信息。例如&#xff0c;创建一个名为 …

设计模式之服务定位模式

文章目录 服务定位器模式概要意图主要解决的问题使用场景实现方式关键代码应用实例优点缺点 使用建议注意事项包含的几个主要角色 代码实现 服务定位器模式 服务定位器模式&#xff08;Service Locator Pattern&#xff09;用在我们想使用 JNDI 查询定位各种服务的时候。考虑到…

论文阅读:基于谱分析的全新早停策略

来自JMLR的一篇论文&#xff0c;https://www.jmlr.org/papers/volume24/21-1441/21-1441.pdf 这篇文章试图通过分析模型权重矩阵的频谱来解释模型&#xff0c;并在此基础上提出了一种用于早停的频谱标准。 1&#xff0c;分类难度对权重矩阵谱的影响 1.1 相关研究 在最近针对…

Vue引入做了什么

Vue.js 是一个功能强大且易于使用的 JavaScript 框架&#xff0c;今天的任务就是分析在 Vue 引入的过程中&#xff0c;都做了哪些处理 &#xff01; 流程讲解 首先会调用这几个方法&#xff0c;主要作用是在 Vue 原型上挂载了一系列的方法&#xff0c;让 Vue 实例具备一些核心…

matlab编写微分方程椭圆型方程(一维形式)

文章目录 理论编程实例原代码 理论 椭圆型方程一维格式即常微分方程&#xff0c;边值问题&#xff0c;方程如下所示&#xff1a; 截断误差&#xff1a; 当 h → ∞ h\rightarrow\infty h→∞时&#xff0c;截断误差趋于零&#xff0c;离散方程组成立&#xff0c; 写成矩阵&…

鸿蒙HarmonyOS实战:状态管理和传值

状态管理 State State是一个装饰器&#xff0c;是用来存放数据的&#xff0c;比较好理解 由State的数据来进行状态驱动视图更新 代码很简单 State count: number 0; 需要注意的是State初始化的数据必须赋值 这里我们讨论简单用法&#xff0c;至于复杂的用法可以到项目中介绍…

vue下载本地xls模版静态文件

需求导入的下载模版不想放在服务器放在前端本地下载静态资源最简单的方式直接访问 public 文件夹下的文件 方法一:使用静态文件路径 将文件放在 public 文件夹中: 把你的文件从 src/assets 移动到 public 文件夹。例如:public/template.xls。 在 Vue 组件中使用相对路径: …

Rust 实战丨HTTPie

概述 之前学习过《陈天Rust 编程第一课 - 04&#xff5c;get hands dirty&#xff1a;来写个实用的 CLI 小工具》&#xff0c;学的时候迷迷糊糊。后来在系统学习完 Rust 后&#xff0c;重新回过头来看这个实战小案例&#xff0c;基本上都能掌握&#xff0c;并且有了一些新的理…

理解Es的DSL语法(二):聚合

前一篇已经系统介绍过查询语法&#xff0c;详细可直接看上一篇文章&#xff08;理解DSL语法&#xff08;一&#xff09;&#xff09;&#xff0c;本篇主要介绍DSL中的另一部分&#xff1a;聚合 理解Es中的聚合 虽然Elasticsearch 是一个基于 Lucene 的搜索引擎&#xff0c;但…

Python考前综合练习-第六章[python123题库]

考前综合练习-第六章 1、字典查询 类型&#xff1a;字典‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪…

爬山算法介绍(极简)

一、引言 爬山算法&#xff0c;作为一种启发式搜索算法&#xff0c;是人工智能和运筹学领域中的经典算法之一。它通过模拟人类爬山的直观过程&#xff0c;逐步向评价函数值更优的方向“攀爬”&#xff0c;以期找到局部最优解。尽管这种算法有其局限性&#xff0c;特别是容易陷入…

【后端】websocket学习笔记

文章目录 1. 消息推送常见方式1.1 轮询 VS 长轮询1.2 SSE&#xff08;server-sent event)服务器发送事件 2. websocket介绍2.1 介绍2.2 原理2.3 websoket API2.3.1 客户端【浏览器】API2.3.2 服务端API 3. 代码实现3.1 流程分析3.2 pom依赖3.3 配置类3.4 消息格式3.5 消息类 4.…