“工控有得聊”是机械工业出版社“机工工控”“机工通信”品牌旗下专业资讯和服务平台,致力于帮助读者在电气、通信、自动化领域里,紧跟前沿资讯,掌握核心技术,快速提升专业素养。点击蓝色微信名可快速关注我们。
在工业自动化项目中,你是否曾因EtherCAT从站的模拟量输入(AI)通道不足而头疼?想要灵活扩展,却苦于官方手册语焉不详?
本文将为你揭秘从站设备添加AI变量的完整流程——
要在EtherCAT从站增加模拟量输入AI变量,首先需更新从站设备程序,定义新的AI变量并初始化。然后,在PDO映射配置中添加该变量,以便主站读取。接着,在从站驱动程序中更新数据处理逻辑,包括对AI变量的采集和处理。最后,在主站程序中更新对该AI变量的读取逻辑,实现数据交换。通过这些步骤,可以成功在EtherCAT从站上增加模拟量输入AI变量,并实现与主站的数据通信和控制。
修改XML文件有关模拟量输入AI的部分
模拟量输入AI的EtherCAT数据通信需要8个AI对象,打开XML文件,点击第二个“TxPdo”,可以看到其Name是AI Inputs并且其下拥有7个Entry,在其后增加8个自定义的AI变量。具体添加过程如下。
(1)增加变量对应于输入映射索引0x1a02
增加变量对应于输入映射索引0x1a02的,需要修改DT1A02数据类型以增加8个变量。
①修改DT1A02数据类型
利用XMLNotePad打开要修改的XML文件,之后依次点击节点:
“EtherCATInfo”→“Descriptions”→“Devices”→“Device”→“Profile”→“Dictionary”→“DataTypes”,依次点击子节点“DataType”,直至找到DT1A02所在的位置,在最后的“SubItem”右键“Duplicate”复制8个新的SubItem。之后,修改新建的SubItem的SubIdx,Name和Type等信息。
SubIdx按顺序递增,Name等根据需求定义,BitOffs是上一个SubItem的BitSize和BitOffs的和。因为添加了新的SubItem,所以DT1A02的BitSize要随之更新,它的值是最后一个SubItem的BitSize和BitOffs的和。XML文件中DT1A02的修改如图1所示。 
图1 XML文件中DT1A02的修改
②修改DT1A02对象
在XMLNotePad中点击“Dictionary”的子节点“Objects”,依次点击“Object”,找到0x1a02所在的位置,修改BitSize即可。这个BitSize值与上面DataType中DT1A02的BitSize要保持一致。本例中修改了0x1a02数据对象(输出映射表),增加8个SubItem,XML文件中0x1a02修改如图2所示。
图2 XML文件中0x1a02的修改
(2)修改0x6020数据类型及对象
由于索引0x1a02将输出过程数据映射到0x6020中,需要修改0x6020数据类型和对象。
①修改DT6020数据类型
利用XMLNotePad打开要修改的XML文件,之后依次点击节点:
“EtherCATInfo”→“Descriptions”→“Devices”→“Device”→“Profile”→“Dictionary”→“DataTypes”,依次点击子节点“DataType”,直至找到DT6020所在的位置,新增8个SubItem。之后,修改新建的SubItem的SubIdx,Name和Type等信息。
SubIdx按顺序递增,Name等根据需求定义,BitOffs是上一个SubItem的BitSize和BitOffs的和。同时因为添加了新的SubItem,所以DT6020的BitSize要随之更新,它的值是最后一个SubItem的BitSize和BitOffs的和。XML文件中DT6020的修改如图3所示。

图3 XML文件中DT6020的修改
②修改DT6020对象
在XMLNotePad中点击“Dictionary”的子节点“Objects”,依次点击“Object”,找到0x6020所在的位置,修改BitSize即可。这个BitSize值与上面DataType中DT6020的BitSize要保持一致。同时增加8个SubItem并进行命名。XML文件中0x6020的修改如图4所示。
图4 XML文件中0x6020的修改
修改stM32程序有关模拟量输入AI的部分
(1)在el9800appl.h文件中修改索引0x1a02的本地存储变量等相关信息
① 修改0x1a02的本地存储
修改TOBJ1A02对应的结构体typedef struct OBJ_STRUCT_PACKED_START。
typedefstructOBJ_STRUCT_PACKED_START
{
UINT16 u16SubIndex0;/* SubIndex 0*/
UINT32 aEntries[16];/* Entry buffer*/
} OBJ_STRUCT_PACKED_END
TOBJ1A02
② 初始化0x1a02与XML文件对应
在图8-19中,在XML文件中对DT1A02进行修改,增加了8个SubItem,且其最大的子索引是16。在图8-20中,在XML文件中对0x1a02进行修改,增加了8个SubItem,其DefaultData表示映射索引号。故而在函数PROTO TOBJ1A02 sAITxPDOMap中进行相应修改:首元素变为16,末尾添加8个元素分别是新增的8个SubItem的相应索引号。
PROTO TOBJ1A02 sAITxPDOMap
#ifdef
_EVALBOARD_
= {16, {0x60200101,0x60200201,0x60200302,0x60200502,0x08,0x18020701,0x18020901,0x60201110,0x60201210,0x60201310,0x60201410,0x60201510,0x60201610,0x60201710,0x60201810,0x60201910}}
#endif
③ 修改0x1a02表项描述
修改结构体OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x1A02[]。
OBJCONST TSDOINFOENTRYDESCOBJMEM asEntryDesc0x1A02[] =
{
{DEFTYPE_UNSIGNED8, 0x8, ACCESS_READ },
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
}
(2)在el9800appl.h文件中修改索引0x6020的本地存储变量等相关信息
① 修改0x6020的本地存储
修改TOBJ6020对应的typedef struct OBJ_STRUCT_PACKED_START。
typedefstructOBJ_STRUCT_PACKED_START
{
UINT16 u16SubIndex0;/* SubIndex 0*/
BOOLEAN(bUnderrange);/* (SI1) Analog input under range*/
BOOLEAN(bOverrange);/* (SI2) Analog input over range*/
BIT2(b2Limit1);/* (SI3) Analog input 1st limit*/
BIT2(b2Limit2);/* (SI5) Analog input 2nd limit*/
ALIGN2(SubIndex006)/* 2Bit alignment*/
ALIGN6(SubIndex007)/* 2Bit alignment*/
BOOLEAN(bTxPDOState);/* (SI15) TxPdo state*/
BOOLEAN(bTxPDOToggle);/* (SI16) TxPdo toggle*/
INT16 i16Analoginput;/* (SI17) Analog input value*/
INT16 i16AI1;/* (SI18) Analog input value*/
INT16 i16AI2;/* (SI19) Analog input value*/
INT16 i16AI3;/* (SI20) Analog input value*/
INT16 i16AI4;/* (SI21) Analog input value*/
INT16 i16AI5;/* (SI22) Analog input value*/
INT16 i16AI6;/* (SI23) Analog input value*/
INT16 i16AI7;/* (SI24) Analog input value*/
INT16 i16AI8;/* (SI25) Analog input value*/
} OBJ_STRUCT_PACKED_END
TOBJ6020
② 初始化0x6020与XML文件对应
在图8-21中,在XML文件中对0x6020进行了修改,增加了8个SubItem,且其最大的子索引是25。对应在函数PROTO TOBJ6020 sAIInputs中进行修改:首元素变为最大子索引25,末尾添加8个元素分别是新增的8个SubItem的初始值。
PROTO TOBJ6020 sAIInputs
#ifdef
_EVALBOARD_
= {25,0x00,0x00,0x00,0x00,0,0,0x00,0x00,0x7FFF,0x0001,0x0001,0x0001,0x0001,
0x0001,0x0001,0x0001,0x0001}
#endif
③ 修改0x6020表项描述
修改结构体OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x6020[]。
OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x6020[] = {
{DEFTYPE_UNSIGNED8, 0x8, ACCESS_READ },
{DEFTYPE_BOOLEAN, 0x01, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_BOOLEAN, 0x01, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_BIT2, 0x02, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{0x0000, 0, 0},
{DEFTYPE_BIT2, 0x02, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{0x0000, 0x02, 0},
{0x0000, 0x06, 0},
{0x0000, 0, 0},
{0x0000, 0, 0},
{0x0000, 0, 0},
{0x0000, 0, 0},
{0x0000, 0, 0},
{0x0000, 0, 0},
{0x0000, 0, 0},
{DEFTYPE_BOOLEAN, 0x01, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_BOOLEAN, 0x01, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING},
{DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING}
}
④ 修改0x1a02和0x6020的对象描述
修改TOBJECT OBJMEM ApplicationObjDic[],需要特别注意方框中数据要与子索引最大值相对应。
TOBJECT OBJMEM ApplicationObjDic[] =
{
……
/* Object 0x1A02 */
{NULL,NULL,0x1A02, {DEFTYPE_PDOMAPPING,16| (OBJCODE_REC << 8)}, asEntryDesc0x1A02, aName0x1A02, &sAITxPDOMap, NULL, NULL, 0x0000 },
……
/* Object 0x6020 */
{NULL, NULL, 0x6020, {DEFTYPE_RECORD, 25 | (OBJCODE_REC << 8)}, asEntryDesc0x6020, aName0x6020, &sAIInputs, NULL, NULL, 0x0000 },
……
}
(3)修改el9800appl.c源文件中的有关内容
① 在函数void APPL_Application(void)中给自定义的变量赋值
voidAPPL_Application(void)
{
……
sAIIutputs.i16AI1= sAOOutputs.i16AO01;
sAIIutputs.i16AI2= sAOOutputs.i16AO02;
sAIIutputs.i16AI3= sAOOutputs.i16AO03;
sAIIutputs.i16AI4= sAOOutputs.i16AO04;
sAIIutputs.i16AI5= sAOOutputs.i16AO05;
sAIIutputs.i16AI6= sAOOutputs.i16AO06;
sAIIutputs.i16AI7= sAOOutputs.i16AO07;
sAIIutputs.i16AI8= sAOOutputs.i16AO08;
……
}
② 在函数void APPL_InputMapping(UINT16* pData)中将已添加的变量传给EtherCAT主站
voidAPPL_InputMapping(UINT16* pData)
{
UINT16j =0;
UINT16*pTmpData = (UINT16*)pData;
/* we go through all entries of the TxPDO Assign object to get the assigned TxPDOs */
for(j =0; j < sTxPDOassign.u16SubIndex0; j++)
{
switch (sTxPDOassign.aEntries[j])
{
/* TxPDO 1 */
case 0x1A00:
*pTmpData++ = SWAPWORD(((UINT16 *) &sDIInputs)[1]);
break;
/* TxPDO 3 */
case 0x1A02:
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[1]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[2]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[3]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[4]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[5]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[6]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[7]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[8]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[9]);
*pTmpData++ = SWAPWORD(((UINT16 *) &sAIInputs)[10]);
break;
}
}
}
本文转自《EtherCAT工业以太网应用系统设计》
第8章 EtherCAT从站增加模拟量输入/输出(AI/AO)数据通信的方法
推荐阅读:







