AN2102


AN2102 如何在GUTTA编译系统中添加自定义指令
   PDF格式完整版本下载

概述

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

具体步骤

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

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

在进行任何修改前,首先要明确我们添加指令是什么。由于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的固件每次都需要重新编译然后再下载。故修改PLC固件,其实就是修改编译所需要的文件。这些文件位于PLC配置文件夹下的CompileFiles子文件夹中:

打开CompileFiles文件夹:

这个目录下面有1个子文件夹和5个文件。WinAVR文件夹用于存放编译器。plc_res.h、plc_type.h、swap_logic.h、swap_auto.h这4个文件都是编译时必需的头文件。swap_system.a是一个动态连接库,里面包含了除用户PLC逻辑代码以外的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文件
   #ifdef FUN_INS_EXCH
       void LgcExcuteIns_EXCH(void);
   #endif //FUN_INS_EXCH
   #ifdef FUN_INS_ERB
       void LgcExcuteIns_ERB(void);
   #endif //FUN_INS_ERB
   #ifdef FUN_INS_EWB
       void LgcExcuteIns_EWB(void);
   #endif //FUN_INS_EWB
   #ifdef FUN_INS_COMW
       void LgcExcuteIns_COMW(void);
   #endif //FUN_INS_EWB
/////////////////////////////////////////////////////// swap:

添加函数LgcExcuteIns_COMW()的声明(表格中黑体部分)。

创建swap_logic_dic_comw.c文件

#include "swap_auto.h"

#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头文件。

将这个文件保存在CompileFiles文件夹中,文件名为swap_logic_dic_comw.c。

编译swap_logic_dic_comw.c文件

在DOS窗口中,进入CompileFiles文件夹,运行编译命令:

...\CompileFiles>WinAVR\bin\avr-gcc.exe -c -mmcu=atmega64 -I. -DF_CPU=11059200UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -std=gnu99 -Wundef swap_logic_dic_comw.c -o swap_logic_dic_comw.o

这个命令根据swap_logic_dic_comw.c文件生成对应的目标文件swap_logic_dic_comw.o。

修改CompileInfor.xml文件
<CompileInfor>
 <Instruction>
   <Item Id="0" Name="LgcExcuteIns_ALD" />
   <Item Id="1" Name="LgcExcuteIns_OLD" />
   <Item Id="2" Name="LgcExcuteIns_LPS" />
   ...
   
<Item Id="153" Name="LgcExcuteIns_EXCH" />
   <Item Id="154" Name="LgcExcuteIns_ERB" />
   <Item Id="155" Name="LgcExcuteIns_EWB" />
   <Item Id="156" Name="LgcExcuteIns_COMW" />
 </Instruction>
 <Command Directory="\CompileFiles\"
          DirectoryExcute="\CompileFiles\WinAVR\bin\"
          OperateFile="\CompileFiles\swap_auto"
          OperateFileSrc="\CompileFiles\swap_auto.c"
          OperateFileObj="\CompileFiles\swap_auto.o"
          OperateFileHex="\CompileFiles\swap_auto.hex">
   <Enter>
     <Step Value="#avr-gcc.exe -c -mmcu=atmega64 -I. -DF_CPU=11059200UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -std=gnu99 -Wundef swap_auto.c -o swap_auto.o" />
     <Step Value="#avr-gcc.exe -mmcu=atmega64 -I. -DF_CPU=11059200UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -std=gnu99 -Wundef -L. swap_system.a swap_auto.o swap_logic_dic_comw.o --output swap_auto.elf" />
     <Step Value="#avr-objcopy.exe -O ihex -R .eeprom swap_auto.elf swap_auto.hex" />
   </Enter>
   <Leave>
   </Leave>
 </Command>
</CompileInfor>

在CompileInfor.xml文件中,加入COMW指令名LgcExcuteIns_COMW(表格中黑体部分);并且在连接命令中加入swap_logic_dic_comw.o目标文件(表格中黑体部分)。

第五步:调试

在GUTTA Ladder Editor软件中新建一个CPU-EC20 (Compile)项目,输入下面的PLC程序。编译下载到AVR试验板后,进入调试模式。通过改变MW10、MW12的值观察Q0.0、Q0.1、Q0.2的值的变化是否正确。