Main Content

使用代码继承工具在生成的代码中导入对外部代码的调用

代码继承工具和代码生成

您可以使用 Simulink® 代码继承工具为现有代码或自定义代码生成完全内联的 C MEX S-Function。S-Function 针对设备驱动程序和查找表等嵌入式组件进行了优化,可以调用现有的 C 或 C++ 函数。

注意

代码继承工具可与 C++ 函数对接,但不能与 C++ 对象对接。要解决此问题,使该工具能够与 C++ 对象对接,请参阅Legacy Code Tool Limitations

可以使用该工具:

  • 编译生成的 S-Function 以进行仿真。

  • 生成封装的 S-Function 模块,此模块被配置为调用现有的外部代码。

如果要在打算为其生成代码的模型中包含这些类型的 S-Function,请使用该工具生成 TLC 模块文件。TLC 模块文件指定为模型生成的代码如何调用现有的 C 或 C++ 函数。

如果 S-Function 依赖的是其他文件夹中的文件,而不是包含 S-Function 动态加载的可执行文件的文件夹中的文件,请使用该工具为 S-Function 生成 sFunction_makecfg.mrtwmakecfg.m 文件。生成这样的文件可在编译包含 S-Function 的模型时保持这些依存关系。例如,对于某些应用程序(如自定义目标),您可能希望在目标特定的位置找到文件。编译过程将在与 S-Function 动态加载可执行文件相同的文件夹中查找 sFunction_makecfg.mrtwmakecfg.m,并调用此文件中的函数。

有关详细信息,请参阅Integrate C Functions Using Legacy Code Tool

生成内联 S-Function 文件以进行代码生成

要为使用 S-Function 的模型生成代码,请根据应用程序的代码生成要求执行以下操作之一:

  • 为内联 S-Function 生成一个 .cpp 文件。在从现有 C 函数生成 S-Function 源文件之前,请在代码继承工具数据结构体中将 Options.singleCPPMexFile 字段的值设置为 true。例如:

    def.Options.singleCPPMexFile = true;
    legacy_code('sfcn_cmex_generate', def);

  • 为内联 S-Function 生成源文件和 TLC 模块文件。例如:

    def.Options.singleCPPMexFile = false;
    legacy_code('sfcn_cmex_generate', def);
    legacy_code('sfcn_tlc_generate', def);

有关 singleCPPMexFile 的限制

在下列情况下,不能将 singleCPPMexFile 字段设置为 true

  • Options.language='C++'

  • 您使用以下 Simulink 对象之一并将 IsAlias 属性设置为 true

    • Simulink.Bus

    • Simulink.AliasType

    • Simulink.NumericType

  • 代码继承工具函数设定中包含 void*void**,以表示状态参数的标量工作数据

  • 代码继承工具结构体的 HeaderFiles 字段指定多个头文件

对已有函数应用代码样式设置

要将代码样式的模型配置参数应用于已有函数,请执行以下操作:

  1. 初始化代码继承工具数据结构体。例如:

    def = legacy_code('initialize');
    
  2. 在数据结构体中,将 Options.singleCPPMexFile 字段的值设置为 true。例如:

    def.Options.singleCPPMexFile = true;

要检查设置,请输入:

def.Options.singleCPPMexFile

有关 singleCPPMexFile 的限制

在下列情况下,不能将 singleCPPMexFile 字段设置为 true

  • Options.language='C++'

  • 您使用以下 Simulink 对象之一并将 IsAlias 属性设置为 true

    • Simulink.Bus

    • Simulink.AliasType

    • Simulink.NumericType

  • 代码继承工具函数设定中包含 void*void**,以表示状态参数的标量工作数据

  • 代码继承工具结构体的 HeaderFiles 字段指定多个头文件

解决对不同位置的文件的依存关系

默认情况下,代码继承工具假定 S-Function 所依赖的文件与 S-Function 的动态加载可执行文件位于同一个文件夹中。如果您的 S-Function 所依赖的文件位于其他位置,而您使用的是模板联编文件编译过程,请为 S-Function 生成一个 sFunction_makecfg.mrtwmakecfg.m 文件。例如,如果您的代码继承工具数据结构体将编译资源定义为路径名称,则您可能需要生成此文件。

要生成 sFunction_makecfg.mrtwmakecfg.m 文件,请调用 legacy_code 函数,并将 'sfcn_makecfg_generate''rtwmakecfg_generate' 作为第一个参数,将代码继承工具数据结构体的名称作为第二个参数。例如:

legacy_code('sfcn_makecfg_generate', lct_spec);

如果您使用同一个文件夹中的多个注册文件,并通过调用一次 legacy_code 为每个文件生成一个 S-Function,则指定 'sfcn_makecfg_generate''rtwmakecfg_generate'legacy_code 调用必须对所有注册文件都是通用的。有关详细信息,请参阅Handling Multiple Registration Files

例如,如果将 defs 定义为代码继承工具结构体数组,则可以使用 'sfcn_makecfg_generate' 调用一次 legacy_code

defs = [defs1(:);defs2(:);defs3(:)];
legacy_code('sfcn_makecfg_generate', defs);

有关详细信息,请参阅编译对 S-Function 的支持

部署 S-Function 以进行仿真和代码生成

您可以部署使用代码继承工具生成的 S-Function,以便其他人也能使用它们。要部署 S-Function 进行仿真和代码生成,请共享以下文件:

  • 注册文件

  • 已编译的动态加载可执行文件

  • TLC 模块文件

  • sFunction_makecfg.mrtwmakecfg.m 文件

  • 生成的 S-Function 所依赖的头文件、源文件和包含文件

使用这些部署的文件时:

  • 在 Simulink 模型中使用部署的文件之前,请将包含 S-Function 文件的文件夹添加到 MATLAB® 路径中。

  • 如果代码继承工具数据结构体将所需的文件注册为绝对路径,而文件位置发生改变,请重新生成 sFunction_makecfg.mrtwmakecfg.m 文件。

集成外部 C++ 对象

代码继承工具可与 C++ 函数对接,但不能与 C++ 对象对接。以上一个示例为基础,下面的示例说明如何应对这一限制。

  • 在新文件 adder_cpp.hpp 中修改 adder 的类定义。添加三个新的宏,分别用于动态分配新的 adder 对象,调用 add_one() 方法和释放分配的内存。每个宏通过一个指针指向一个 adder 对象。因为代码继承工具调用的每个函数必须具有一个与 C 语言类似的签名,所以该指针以 void* 的形式进行缓存和传递。因此,您必须在宏中明确转换为 adder*adder 的新类定义:

    #ifndef _ADDER_CPP_
    #define _ADDER_CPP_
    
    class adder {
    private:
    	int int_state;
    public:
    	adder(): int_state(0) {};
    	int add_one(int increment);
    	int get_val() {return int_state;};
    };
    
    // Method wrappers implemented as macros
    #define createAdder(work1) \
        *(work1) = new adder
    
    #define deleteAdder(work1) \
        delete(static_cast<adder*>(*(work1)))
    
    #define adderOutput(work1, u1) \
        (static_cast<adder*> ((work1)))->add_one(u1)
    
    #endif /* _ADDER_CPP_ */
  • 更新 adder_cpp.cpp。采用类修改方式(而不是一个全局实例),生成的每个 S-Function 可以管理其自己的 adder 对象。

    #include "adder_cpp.hpp"
    
    int adder::add_one(int increment)
    {
    	int_state += increment;
        return int_state;
    }
  • 使用以下更改更新 rtwdemo_sfun_adder_cpp.cpp

    • StartFcnSpec 调用的宏负责分配新的 adder 对象并缓存指针。

      def.StartFcnSpec  = 'createAdder(void **work1)';
      
    • OutputFcnSpec 调用的宏负责调用 add_one() 方法并提供 S-Function 特定的 adder 指针对象。

      def.OutputFcnSpec = 'int32 y1 = adderOutput(void *work1, int32 u1)';
    • TerminateFcnSpec 调用的宏负责释放内存。

      def.TerminateFcnSpec = 'deleteAdder(void **work1)';

另请参阅

相关主题