AN2101


AN2101 如何在GUTTA解释系统中添加自定义指令
   PDF格式完整版本下载

概述

在GUTTA PLC系统中添加自定义指令,是进行PLC开发的最常见任务。添加自定义指令存在两部分工作。一部分是对上位机软件配置进行修改:首先应该让用户能够在GUTTA编程软件中操作自定义指令。这就需要修改指令文件规范ManagerFun.xml。这个文件的详细信息请参考《UM4003 指令描述文件规范》。二部分是对下位机固件进行修改:在解释型PLC系统中,添加自定义指令需要用C语言编写指令功能的具体实现,然后在指令分发系统中添加功能的调用。

具体步骤

这里我们以一个简单的例子,一步一步介绍解释系统中添加自定义指令的过程。假设我们需要添加指令的CPU类型为CPU-EC20。需要添加的指令为数值比较指令。指令有两个输入操作数,都是整型数值。指令有三个输出操作数,都是位变量。这三个位变量分别在两个输入操作数为大于、等于、小于的时候置位。

第一步:确定指令格式,绘制图形

在进行任何修改前,首先要明确我们添加指令是什么。由于GUTTA支持指令表和梯形图两种模式的编程,故需要定义好两种模式下指令的格式和形状。根据前面提出的指令功能,画出指令草图如下:

指令表指令格式

梯形图指令格式

由于不使用组合指令,对应的指令表指令和梯形图指令是一对一的关系。同时这两种操作数都是5个,并且他们也是一对一的。需要注意的是,在指令表形式时,指令名是“COMW”;在梯形图形式时,指令名是“COM_W”;两种名字并不一致。

第二步:修改ManagerFun.xml文件

找到ManagerFun.xml文件、打开并编辑

在软件的安装文件夹中,有一个名为GuttaLad的子文件夹。在GuttaLad子文件夹中,又存在若干子文件夹,其中每一个子文件夹代表一种CPU配置。每个CPU配置下面分别有ManagerEnu和ManagerChs这两个子文件夹。这两个文件夹中的文件内容基本一致。只不过对应的语言选项不同。ManagerEnu对应的语言选项为英文,ManagerChs对应的语言选项为中文。我们先修改英文模式下的文件(中文模式下的文件修改基本相同)。

添加<FunOrg><Unit>节点

参考《UM4003 指令描述文件规范》,写出COMW中间指令描述代码如下:

 <FunOrg>
   <Unit Name="COMW" Comment="" Parent="" Type="Output" Node="1">
     <Operand>
       <FunOperand Name="IN1" Capacity="Wcvp:" Const="Uint" />
       <FunOperand Name="IN2" Capacity="Wcvp:" Const="Uint" />
       <FunOperand Name="GT" Capacity="Tv:" Const="Bit" />
       <FunOperand Name="EQ" Capacity="Tv:" Const="Bit" />
       <FunOperand Name="LT" Capacity="Tv:" Const="Bit" />
     </Operand>
   </Unit>
 </FunOrg>
添加<FunStl><Unit>节点

参考《UM4003 指令描述文件规范》,写出COMW指令表指令描述代码如下:

 <FunStl>
   <Unit Name="COMW" Comment="" Parent="Additional" Slot="156">
     <Operand>
       <FunOperand Name="IN1" Capacity="Wcvp:" Const="Uint" />
       <FunOperand Name="IN2" Capacity="Wcvp:" Const="Uint" />
       <FunOperand Name="GT" Capacity="Tv:" Const="Bit" />
       <FunOperand Name="EQ" Capacity="Tv:" Const="Bit" />
       <FunOperand Name="LT" Capacity="Tv:" Const="Bit" />
     </Operand>
   </Unit>
 </FunStl>
添加<FunLad><Unit>节点

参考《UM4003 指令描述文件规范》,写出COMW梯形图指令描述代码如下:

 <FunLad>
   <Unit Name="COMW" Comment="" Parent="Additional" Look="Block" Keyword="COM_W">
     <PowerIn>
       <FunPower Name="EN" />
     </PowerIn>
     <OperandIn>
       <FunOperand Name="IN1" Capacity="Wcvp:" Const="Uint" />
       <FunOperand Name="IN2" Capacity="Wcvp:" Const="Uint" />
     </OperandIn>
     <OperandOut>
       <FunOperand Name="GT" Capacity="Tv:" Const="Bit" />
       <FunOperand Name="EQ" Capacity="Tv:" Const="Bit" />
       <FunOperand Name="LT" Capacity="Tv:" Const="Bit" />
     </OperandOut>
   </Unit>
 </FunLad>
添加<ConvertStl><Unit>节点

参考《UM4003 指令描述文件规范》,写出COMW指令表指令到中间指令的规则如下:

 <ConvertStl>
   <Unit>
     <Left>
       <Item Name="COMW" Key="12345" />
     </Left>
     <Right>
       <Item Name="COMW" Key="12345" />
     </Right>
   </Unit>
 </ConvertStl>

这个段代码的含义比较简单,就是说指令表指令“COMW”和中间指令“COMW”可以在需要时互相转化,转化时参数一一对应(因为“12345”=“12345”)。

添加<ConvertLad><Unit>节点

参考《UM4003 指令描述文件规范》,写出COMW梯形图指令到中间指令的规则如下:

 <ConvertLad>
   <Unit>
     <Left>
       <Item Name="COMW" Key="12345" />
     </Left>
     <Right>
       <Item Name="COMW" Key="12345" />
     </Right>
   </Unit>
 </ConvertLad>

这个段代码的含义比较简单,就是说梯形图指令“COMW”和中间指令“COMW”可以在需要时互相转化,转化时参数一一对应(因为“12345”=“12345”)。

注意到梯形图指令操作数分为标识操作数(本指令没有用到)、输入操作数、输出操作数。在进行一一对应时,梯形图指令按照先标识操作数,后输入操作数,最后输出操作数的顺序匹配。

将上面5段代码添加到ManagerFun节点的最后面:

保存文件后,便完成了ManagerFun.xml文件的修改。

第三步:验证ManagerFun.xml文件

为了验证以上修改的正确,需要运行GUTTA Ladder Editor软件。

若两种转换都能够正确执行,说明ManagerFun.xml文件修改准确无误。由于前面只修改了英文模式下的指令系统,对于中文模式下的指令系统,也要做出相应的修改。这里不再重复讲述。

第四步:修改PLC固件

修改plc_type.h文件
#endif // FUN_USE_TABLE

#ifdef FUN_USE_TIMERS
                   #define FUN_INS_TON         149
                   #define FUN_INS_TONR        150
                   #define FUN_INS_TOF         151
#endif // FUN_USE_TIMERS

#ifdef FUN_USE_ADDITIONAL
                   #define FUN_INS_PID         152
                   #define FUN_INS_EXCH        153
                   #define FUN_INS_ERB         154
                   #define FUN_INS_EWB         155
                   #define FUN_INS_COMW        156
#endif // FUN_USE_ADDITIONAL
///////////////////////////////////////////////////////////////////////////////

// Other:
///////////////////////////////////////////////////////////////////////////////
#define FUN_INT_SIZE        PLC_TYPE_PROGRAM_BLOCK_PAGE_INT_SIZE

在指令表指令中,添加一个FUN_INS_COMW的宏定义(表格中黑体部分)。此宏的值等于指令表指令的固件代码。

修改swap_logic.h文件
   #define LgcParByte(x, par)      (*(uint8_t*)(&(par).itCachePar[x]))
   #define LgcParWord(x, par)      (*(uint16_t*)(&(par).itCachePar[x]))
   #define LgcParDword(x, par)     (*(uint32_t*)(&(par).itCachePar[x]))

   #define LGC_INS_DISPATCH()  case FUN_INS_COMW: \
                                       LgcExcuteIns_COMW(); \
                                       break;

   void LgcExcuteIns_COMW();

   #define LgcIsIntIndex(x)        ((x & 0x08) == 0)
   #define LgcIsSbrIndex(x)        ((x & 0x08) != 0)

修改宏LGC_INS_DISPATCH()的定义、并且在后面添加函数LgcExcuteIns_COMW()的声明(表格中黑体部分)。修改这个宏的结果是解释系统在遇到固件代码号为FUN_INS_COMW的指令时,调用完成指令功能的LgcExcuteIns_COMW()函数。

修改swap_logic.c文件
   void LgcMainScanPrepare(void) {
       }

#ifdef FUN_INS_COMW
   void LgcExcuteIns_COMW(void) {
       if (_BT(theRes.itState.itStackData, 0)) {
           // If great
           if (_ADDR_VAL_UINT16(0) > _ADDR_VAL_UINT16(1))
               _ADDR_VAL_BIT_BST(2);
           else
               _ADDR_VAL_BIT_BSF(2);
           // If equal
           if (_ADDR_VAL_UINT16(0) == _ADDR_VAL_UINT16(1))
               _ADDR_VAL_BIT_BST(3);
           else
               _ADDR_VAL_BIT_BSF(3);
           // If less
           if (_ADDR_VAL_UINT16(0) < _ADDR_VAL_UINT16(1))
               _ADDR_VAL_BIT_BST(4);
           else
               _ADDR_VAL_BIT_BSF(4);
           }
   }
#endif //FUN_INS_COMW

在文件的最后加入函数LgcExcuteIns_COMW()的定义。完成该指令的功能。这里这个指令通过比较两个输入操作数的大小关系,来设置输出参数的值(见该指令的设计要求)。

引用参数时可以使用下列宏:

更多的细节请参考sfw_logic.h头文件。

第五步:编译、烧写PLC固件后调试

上面的工作完成后,最后一步便是编译、烧写固件。使用的工具根据CPU类型的不同而不同。只有在调试通过后,添加指令的工作就算正式完成了。