主要内容

金宝appSimulink功能块和代码生成

为什么要从Simulink函数块和函数调用器中金宝app生成代码?

金宝appSimulink函数块提供了一种机制,用于为表示共享资源的组件建模生成C或c++代码。在Simulink Function块中将逻辑定义为资源,该块将函数接口(名称和金宝app参数)与逻辑的实现分离。函数调用器(函数调用器块、MATLAB函数块和statflow®然后可以在模型层次结构的不同级别重用功能逻辑。

金宝appSimulink函数块提供了可重用子系统的替代方案。例如,使用Simulink函数块而不是子系统块的一个考虑是,Simulink函数块金宝app在函数调用者之间共享状态。代码生成器生成一个函数。如果Simul金宝appink Function块包含有状态的块,如延迟或内存,则状态在函数调用者之间持久存在。函数调用的顺序是一个重要的考虑因素。

代码生成器从子系统生成的可重用函数不共享状态。作为优化,代码生成器为子系统的多个实例生成一个函数。如果该子系统包含具有状态的块,则代码生成器生成一个函数,但将不同的状态变量传递给每个实例。实例不共享状态。

Simulink功能块和调用金宝app器的其他用途包括:

  • 嵌套函数调用。

  • 从另一个建模组件调用一个建模组件中定义的函数。

  • 生成全局可访问或作用域范围的函数。

  • 为客户机和服务器应用程序生成代码。

实现选项

选择如何实现Simulink金宝app®函数和函数调用者基于代码生成需求。注意事项包括:

  • 如何在模型中表示函数和函数调用者

  • 职能范围

  • 是否从模型中导出函数(需要嵌入式编码器)®

  • 函数代码接口定制(需要嵌入式编码器)

  • 代码生成的需求

  • 代码生成的局限性

选择建模模式

这个表显示了一个将输入值乘以2的函数的C代码,以及一个可以在Simulink模型中表示该函数的Simulink函数块。金宝app

函数定义 建模元素

codegen-folder/子系统.c

#include "ex_slfunc_comp_sf_private.h" #include "ex_slfunc_comp_sf_private.h" #include "ex_slfunc_comp_sf_private.h" #include "ex_slfunc_comp_sf_private.h" #include "ex_slfunc_comp_sf_private.h"void timestwo_sf(real_T rtu_x, real_T *rty_y) {*rty_y = 2.0 * rtu_x;}

金宝app仿真软件功能块

Si金宝appmulink函数调用者调用用Simulink函数块定义的函数。在模型或图表层次结构的任何地方,你都可以通过使用以下建模元素之一调用用Simulink function块定义的函数:金宝app

函数调用 建模元素

codegen-folder/模型.c

void ex_slfunc_comp_sf_step(void) {real_T rtb_FunctionCaller1;timestwo_sf (ex_slfunc_comp_sf_U。三机一体,&rtb_FunctionCaller1);ex_slfunc_comp_sf_Y。着干活= rtb_FunctionCaller1;. . .

函数调用程序块

codegen-folder/模型.c

void ex_slfunc_comp_gf_step(void) {real_T rtb_y1_l;timestwo_gf (ex_slfunc_comp_gf_U。In4 &rtb_y1_l);ex_slfunc_comp_gf_Y。Out4 = rtb_y1_l;. . .

Stateflow图表过渡

codegen-folder/模型.c

void ex_slfunc_comp_mf_step(void) {real_T rtb_y;timestwo_mf (ex_slfunc_comp_mf_U。In3 &rtb_y);ex_slfunc_comp_mf_Y。Out3 = rtb_y;. . .

MATLAB功能块

有关建模选择的更多信息,请参见金宝app动态仿真模块功能概述

指定函数的范围

用Simulink function块定义的函数可以是全局的,也可以金宝app是作用域的。

  • Global——代码生成器将全局函数的代码放在与模型代码文件分离的源文件和头文件中(例如,函数.c函数.h) .单独的文件使得函数代码可以在函数调用者之间共享。

  • 作用域——代码生成器将作用域函数的代码放置在模型代码文件中(模型.c模型.h).要在模型上下文中调用作用域函数,函数调用者必须位于与模型层次结构中的函数相同的级别,或者比模型层次结构低一个或多个级别。

    要创建一个可从生成的模型代码中的任何地方访问的函数库,将每个函数设置为一个有作用域的Simulink函数块。金宝app将每个作用域函数放置在模型的根级的虚拟子系统中。

有关更多信息,请参见和作用域和全局的Simulink函数块金宝app概述

是否生成导出函数代码

尽管您可以在单个顶级模型设计中使用Simu金宝applink Function块,但当您将函数代码生成为独立的原子组件时,它更易于重用。您可以通过在导出函数模型的上下文中设计函数来实现这一点。

信息,请参阅生成组件源代码导出到外部代码库导出功能模型概述

指定功能代码接口自定义

使用Embedded Coder,通过定制Simulink function和function Caller块生成的函数代码接口,简化生成代码与外部代码的集成。金宝app您可以自定义以下功能接口:

  • 全局Simul金宝appink函数块

  • 具有作用域的S金宝appimulink函数块位于模型的根级别

有关更多信息,请参见配置Simulink函数和函数调用程序块的入口点函数接口金宝app

未调用的Simul金宝appink函数块

如果您在基于费率的模型中使金宝app用Simulink Function块,并且不调用该函数,代码生成器将Simulink Function块视为常量,而不生成函数代码。例如,这可能发生在模型开发期间,此时您已经准备好定义函数,但还没有准备好标识调用者。

为了在基于速率的模型中识别这些块,在模拟过程中显示样本时间颜色。默认情况下,Constant块显示为洋红色。因为代码生成器在模拟过程中考虑未调用的Simulink函数块常量,所以它们显示为洋红色。金宝app

需求

  • 在模型层次结构中,函数名是唯一的。如果代码生成器发现多个同名函数,就会发出错误。更改其中一个函数的名称并删除slprj文件夹中。

  • 函数的签名(例如,参数和参数数据类型)必须与函数调用者匹配。

    • 如果代码生成器首先找到函数,而函数调用者的签名不匹配,则代码生成器将发出错误。更改函数调用者的签名以匹配Simulink函数块的签名或删除金宝appslprj文件夹中。

    • 如果代码生成器首先发现函数调用者,而函数的签名不匹配,则代码生成器发出警告消息。更改函数或函数调用者的签名,使签名匹配。

  • 在Simu金宝applink函数块定义中,不要使用存储类为参数导入和参数输出块定义输入和输出信号。

  • 不要指定参数导入和参数输出块作为测试点。

  • 如果将参数导入和参数输出块的输入和输出信号的数据类型指定为金宝app仿真软件。IntEnumType金宝app仿真软件。AliasType,或金宝app仿真软件。公共汽车,设置DataScope财产进口出口

  • 函数接口和函数调用者必须在数据类型、复杂性、维度和参数数量上达成一致。

限制

  • 要从包含有作用域的Simulink函数的模型中生成代码,该模型必须是一个导出函数模型。金宝app代码生成器不支持基于费率的模型,其中包含限定范围的Sim金宝appulink函数。金宝app

  • 可以使用Simulink F金宝appunction块在引用模型中定义作用域函数。但是,您不能为使用原子子系统中的Function Caller块来调用该函数的导出函数模型生成代码。

  • 您可以调用代码生成器C++生成的函数,该代码生成器由SIMULINK函数块生成,其中的代码由StaseFLUM图生成。由于当前C++生成函数金宝app的范围限制,必须调用函数从函数调用方块生成的代码。

  • 金宝appSimulink函数和函数调用者不尊重MaxStackSize参数。

  • c++类接口的代码生成只支持有作用域的Simulink函数。金宝app金宝app

生成和调用可重用的函数代码

此示例演示如何使用Simulink函数和函数调用程序块生成可重用的函金宝app数代码。代码生成器生成符合代码要求的全局函数,以便现有外部代码可以调用该函数和局部函数。代码生成器还生成对全局和局部函数的调用。对全局函数的调用表明全局函数被重用(共享)。

全局函数的代码要求如下:

  • 函数名以前缀开头func_

  • 输入参数的名称是这种形式的xn,在那里n是唯一的整数值。

  • 输出参数的名称是这种形式的yn,在那里n是唯一的整数值。

  • 输入和输出参数均为整数(int),并通过引用传递。目标硬件的本地整数大小是32位。

您可以创建一个函数来调用生成的可重用函数代码。然后,构建并配置一个模型以匹配代码需求。

本例中使用的一些特性,如数据类型别名和替换,需要Embedded Coder软件。

检查调用可重用函数的外部代码

在代码生成根文件夹中创建文件call_times2.hcall_times2.c.如果你愿意,你可以从matlabroot \ \工具箱\是帮助\例子

call_times2.h

typedef int my_int;

call_times2.c

#include "call_times2.h" void call_times2(void) {int times2result;func_times2 (x1, y1);printf('乘以2的值:',y1);}

这个C代码调用可重用函数func_times2.函数乘以一个整数输入值x1并返回结果为日元

创建模型

打开示例模型ex_slfunc_comp,可在文件夹中找到matlabroot \ \工具箱\是帮助\例子.该模型包括两个Simulink功能模块,金宝appfunc_times2func_times3,以及对每个函数的调用。如模型中所示,用于的Simulink函数块的可见性金宝appfunc_times2被设置为全球. 该可见性设置使功能代码可供其他代码访问,包括要与生成的代码集成的外部代码。能见度func_times3被设置为作用域

如果您使用GRT系统目标文件或ERT系统目标文件配置模型文件的包装格式设置为模块化,代码生成器为模型生成函数代码。

有关更多信息,请参见为Simulink函数和函数调用者生成代金宝app码

配置生成的代码以重用自定义数据类型

该示例假设生成的代码在目标硬件上运行,本地整数大小为32位。外部代码用数据类型表示整数my_int的别名int.配置要使用的代码生成器my_int代替代码生成器默认使用的数据类型,即int32_T

  1. 创建一个模型。金宝appAliasTypeobject to represent the custom data typemy_int

    my_int =仿金宝app真软件。AliasTypemy_int= AliasType with properties: Description: '' DataScope: 'Auto' HeaderFile: '' BaseType: 'double'
  2. 设置别名类型属性。输入描述,设置范围为进口,指定包含类型定义的头文件,并将别名类型与Simulink基类型关联金宝appint32

    my_int。Description='自定义32位int表示';my_int.DataScope =“进口”;my_int.HeaderFile =“call_times2.h”;my_int.BaseType =“int32”;my_int AliasType带有属性:描述:'自定义32位int表示' DataScope: 'Imported' HeaderFile: 'call_times2.h' BaseType: 'int32'
  3. 配置代码生成器以替换类型的实例int32_Tmy_int.在“配置参数”对话框中打开代码生成数据类型替换窗格。

    • 选择替换生成代码中的数据类型名称

    • 数据类型名称表,输入my_int的替换名称int32

配置可重用的全局函数

对于调用全局函数的外部代码,配置相应的Simulink function块,使其具有全局可见性和与外部调用者所期望的匹配的接口。金宝app

  1. 打开表示times2函数。

  2. 通过设置“触发端口阻塞”参数,配置函数的名称和可见性。例如,代码要求指定函数名以前缀开头func_

    • 函数名func_times2

    • 功能可见性全球

  3. 通过设置参数导入和参数输出块参数来配置函数的输入和输出参数。例如,代码要求指定参数名称为该形式xnyn.这些要求还指定了参数的类型my_int

    • 主要选项卡,设置参数名称x1(输入)和日元(输出)。

    • 信号的属性选项卡,设置数据类型int32.使用前面指定的数据类型替换,int32在生成的代码中显示为

  4. 配置Simulink功能块代金宝app码接口。在模型的顶层,右键单击表示全局函数的块func_times2.从上下文菜单中选择C / c++代码配置C/ c++函数接口

    • C / c++函数名func_times2

    • C / c++返回参数无效

    • C / c++标识符的名字为参数x1x1

    • C / c++标识符的名字为参数日元日元

    如果对话框列出了输出参数日元在输入参数x1,通过拖动行来重新排列参数x1排在前面的日元

配置本地函数

配置一个Simulink金宝app Function块,它表示具有作用域可见性的本地函数。根据代码需求,您可能还必须配置函数名、输入和输出参数名称和类型,以及函数接口。

  1. 打开表示times3函数。

  2. 通过设置“触发端口阻塞”参数,配置函数的名称和可见性。例如,代码要求指定函数名以前缀开头func_

    • 函数名func_times3

    • 功能可见性作用域

  3. 通过设置参数导入和参数输出块参数来配置函数的输入和输出参数。例如,代码要求指定参数名称为该形式xnyn.这些要求还指定了参数的类型my_int

    • 主要选项卡,设置参数名称x1(输入)和日元(输出)。

    • 信号的属性选项卡,设置数据类型int32.使用前面指定的数据类型替换,int32在生成的代码中显示为my_int

  4. 配置Simulink功能块代金宝app码接口。在模型的顶层,右键单击作用域函数func_times3.从菜单中选择C / c++代码配置C/ c++函数接口.在这种情况下,代码生成器控制函数和参数的命名。函数名组合了根模型的名称和为Simulink function块的触发器端口指定的函数名。金宝app在本例中,名称为ex_slfunc_comp_func_times3

    你可以设置C / c++返回参数为参数输出块指定的参数名或无效.对于本例,将其设置为无效

    对于参数,代码生成器前置rtu_(输入)或rty_(输出)到为参数导入块指定的参数名。

    如果对话框列出了输出参数日元在输入参数x1,通过拖动行来重新排列参数x1排在前面的日元

配置函数调用者

对于每个函数调用者,配置函数调用者块参数:

  • 函数原型日元= func_times2 (x1)

  • 输入参数规格int32 (1)

  • 输出参数规格int32 (1)

生成和检查代码

为模型生成代码。

  • 全局函数代码

    全局可重用函数的源代码func_times2在子系统文件的构建文件夹中,func_times2.c

    #include "func_times2.h" /* include "ex_slfunc_comp_private.h" void func_times2(my_int x1, my_int *y1) {*y1 = x1 << 1;}
  • 局部函数码

    代码生成器放置局部(作用域)函数的定义func_times3在文件中构建文件夹在文件中ex_slfunc_comp.c

    Void ex_slfunc_comp_func_times3(my_int rtu_x1, my_int *rty_y1) {rty_y1 = 3 * rtu_x1;}
  • 对生成函数的调用

    模型执行(步骤)函数,在模型文件中ex_slfunc_comp.c,调用两个Simulink函数:金宝appglobal函数func_times2和当地的函数ex_slfunc_comp_func_times3. 名字ex_slfunc_comp_func_times3通过组合模型的名称和函数的名称来反映局部函数的范围。

    void ex_slfunc_comp_step(void) {my_int rtb_FunctionCaller2;func_times2 (ex_slfunc_comp_U。三机一体,&rtb_FunctionCaller2);ex_slfunc_comp_Y。着干活= rtb_FunctionCaller2;ex_slfunc_comp_func_times3 (ex_slfunc_comp_U。In2 &rtb_FunctionCaller2);ex_slfunc_comp_Y。Out2 = rtb_functionCaller2;. . .
  • 局部函数的入口点声明

    模型头文件ex_slfunc_comp.h包括走读生声明函数ex_slfunc_comp_func_times3.该语句声明了函数入口点。

    Extern void ex_slfunc_comp_func_times3(my_int rtu_x1, my_int *rty_y1);
  • 包含全局函数的语句

    模型头文件ex_slfunc_comp.h列表包含全局函数的语句func_times2

    #include "func_times2_private.h" #include "func_times2.h"
  • 全局函数的本地宏和数据

    子系统头文件func_times2_private.h定义宏,包括为全局函数声明数据和函数的头文件,func_times2

    #ifndef RTW_HEADER_func_times2_private_h_ #define RTW_HEADER_func_times2_private_h_ #ifndef ex_slfunc_comp_common_incles_ #define ex_slfunc_comp_common_incles_ #include "rtwtypes.h" #endif #endif .
  • 全局函数的入口点声明

    共享头文件func_times2.h,在共享实用程序文件夹中slprj /月31/ _sharedutils,列出共享类型包含的rtwtypes.h.该文件还包括走读生全局函数的声明,func_times2.该语句声明了函数入口点。

    #ifndef RTW_HEADER_func_times2_ #define RTW_HEADER_func_times2_ #include "rtwtypes.h" extern void func_times2(my_int rtu_x1, my_int *rty_y1);# endif

为Simulink函数和函数调用者生成代金宝app码

这个例子展示了如何为Simulink Function和Function Caller块生成金宝appC代码,并显示相关的生成代码。

打开示例模型rtwdemo_export_functions.模型使用statflow软件,但是本示例只检查从引用模型生成的代码。

为函数定义生成代码

  1. 要查看子系统的内容,双击rtwdemo_functions.Simu金宝applink函数块是f3子系统定义为y = f3 (u)

  2. 生成的代码。

代码生成器创建rtwdemo_functions.c.该文件包含函数定义和函数初始化代码。

  • 函数初始化代码f3:

    void f3_Init(void) {rtDWork. log ();Delay_DSTATE = 1;}
  • 代码功能f3:

    void f3(real_T rtu_u, real_T *rty_y) {rtY. txt;TicToc10 = rtDWork.Delay_DSTATE;rtDWork。Delay_DSTATE = (int8_T) (int32_T)——(int32_T) rtY.TicToc10;adder_h (rtB。减、rtU。U2, rtu_u rtB.FunctionCaller);* rty_y = rtB.FunctionCaller;} void adder_h(real_T rtu_u1, real_T rtu_u2, real_T rtu_u3, real_T *rty_y) {*rty_y = (rtu_u1 + rtu_u2) + rtu_u3;}

  • 共享头文件f3.h包含函数的入口点声明f3

    #include "rtwtypes.h" extern void f3(real_T rtu_u, real_T *rty_y);

为函数调用者生成代码

  1. rtwdemo_export_functions模型中,双击rtwdemo_caller查看调用方子系统的内容。

  2. 生成的代码。

代码生成器创建文件rtwdemo_caller.hrtwdemo_caller.c在文件夹rtwdemo\u呼叫者\u ert\u rtw

rtwdemo_caller.h包括共享头文件,f3.h,其中包含函数入口点声明。

rtwdemo_caller.c调用函数f3

void rtwdemo_caller_t_10tic(const real_T *rtu_u, real_T *rty_y) {f3(*rtu_u, rty_y);}

相关的话题