从顶层模型生成可重入代码
默认情况下,对于顶层模型,代码生成器生成不可重入的代码。入口函数具有 void-void 接口。代码通过共享对驻留在共享内存中的全局数据结构体的访问来与其他代码通信。
如果应用程序可以获益于代码重用,且代码的每次使用或每个实例需要保留其自己的独有数据,则可将模型配置为支持使用代码生成器生成可重入代码。要生成可重入代码,请将模型配置参数 Code interface packaging 设置为可重用函数。如果您正在使用 Embedded Coder® 并生成 C++ 代码,您也可以将参数设置为 C++ 类。
当代码接口打包设置为可重用函数时,代码生成器:
将模型数据(例如模块 I/O、DWork 向量和参数)打包到实时模型数据结构体 (
rtModel
) 中。按引用将实时模型数据结构体作为输入参量传递给生成的模型入口函数。
将根级输入和输出参量作为单个参量传递给生成的模型入口函数。
为模型数据结构体静态分配内存。
将实时模型数据结构体导出到生成的头文件
中。model
.h
通过设置以下模型配置参数,应用其他诊断和代码生成控制:
要选择当模型不符合多实例代码要求时代码生成器显示的诊断消息的严重性级别,请将参数 Multi-instance code error diagnostic 设置为无、警告或错误。除非您需要更改当模型违反生成多实例代码的要求时显示的诊断的严重性级别。否则将参数设置为错误。
要控制生成的代码如何将根级模型输入和输出传递给可重用执行(单步)函数(需要 Embedded Coder),请将参数 Pass root-level I/O as (Embedded Coder) 设置为单个参量、结构体引用或模型数据结构体的一部分。
当您将 Code interface packaging 设置为可重用函数时,代码生成器将模型数据(如模块 I/O、Dwork 和参数)打包到实时模型数据结构体中,并将模型结构传递给生成的模型入口函数。如果您将 Pass root-level I/O as (Embedded Coder) 设置为模型数据结构体的一部分,代码生成器还会将根级模型输入和输出打包到实时模型数据结构体中。
要通过从实时模型数据结构体中忽略错误状态字段来减少内存使用量(需要 Embedded Coder),请选择模型配置参数删除实时模型数据结构体中的错误状态字段。
要在生成的文件
中包含使用model
.cmalloc
为模型实例数据动态分配内存的函数(需要 Embedded Coder),请选择模型配置参数使用动态内存分配进行模型初始化。如果不选择此参数,生成的代码将为模型数据结构体静态分配内存。
生成可重入的多实例代码
此示例说明如何配置模型以生成可重入的多实例代码。多个程序可以同时使用可重入代码。当您为实现可重入性而配置模型时,执行(单步)入口函数使用根级输入和输出参量而不是全局数据结构体。检查配置设置后,生成并查看生成的代码。
打开模型
打开模型 Reusable
。该模型包含两个根 Inport 模块和一个根 Outport 模块。
model='Reusable';
open_system(model);
检查相关模型配置参数设置
1.打开 Embedded Coder。
2.打开“模型配置参数”对话框。
3.模型配置参数系统目标文件设置为 ert.tlc
。虽然对于系统目标文件设置为 grt.tlc
的模型可生成可重入代码,但基于 ERT 和 ERT 的系统目标文件可以更好地控制代码如何通过根级 I/O。
4.打开代码生成 > 接口窗格,并查看相关模型配置参数设置。
代码接口打包设置为
Reusable function
。此参数设置指示代码生成器产生可重用的多实例代码。Reusable function
的设置显示参数多实例代码错误诊断。该参数设置为Error
,表示如果模型违反生成多实例代码的要求,代码生成器将中止。根级 I/O 传递方式设置为
Part of model data structure
。此设置将根级别模型输入和输出打包到实时模型数据结构体 (rtModel
) 中,该结构体是一个经过优化的数据结构体,可代替SimStruct
作为模型的顶级数据结构体。删除实时模型数据结构体中的错误状态字段处于选中状态。此参数设置通过省略生成的实时模型数据结构体中的错误状态字段来减少内存使用量。
生成和查看代码
slbuild(model);
### Starting build procedure for: Reusable ### Successful completion of build procedure for: Reusable Build Summary Top model targets built: Model Action Rebuild Reason ========================================================================================== Reusable Code generated and compiled. Code generation information file does not exist. 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 9.9477s
查看生成的代码
ert_main.c
是模型的示例主程序(执行框架)。此代码通过调用入口函数Reusable_step
来控制模型代码执行。使用此文件作为对执行框架进行编码的起始点。Reusable.c
包含实现模型算法的代码的入口函数。此文件包含速率调度代码。Reusable.h
声明模型数据结构体和对接模型入口函数和数据结构体的公共接口。rtwtypes.h
定义生成的代码所需的数据类型、结构体和宏。
代码接口
打开并查看代码接口报告。使用该报告中的信息编写用于您的执行框架的接口代码。
1.通过添加指令 #include Reusable.h
来包含生成的头文件。
2.将输入数据写入模型的 Inport 模块的生成代码。
3.调用生成的入口函数。
4.从为模型 Outport 模块生成的代码中读取数据。
输入端口:
<Root>/In1
的数据类型为real_T
,维度为 1<Root>/In2
的数据类型为real_T
,维度为 1
入口函数:
初始化入口函数,
void Reusable_initialize(RT_MODEL *const rtM)
。在启动时,调用一次此函数。输出和更新(单步)入口函数,
void Reusable_step(RT_MODEL *const rtM)
。以模型中最快的速率定期调用此函数。对于此模型,每秒调用一次该函数。要实现实时执行,请将此函数附加到计时器。
输出端口:
<Root>/Out1
的数据类型为real_T
,维度为 1
检查单步函数
Examine the |Reusable_step| function code in |Reusable.c|.
cfile = fullfile('Reusable_ert_rtw','Reusable.c'); coder.example.extractLines(cfile,'/* Model step function', '/* Model initialize function ', 1, 0);
/* Model step function */ void Reusable_step(RT_MODEL *const rtM) { D_Work *rtDWork = rtM->dwork; ExternalInputs *rtU = (ExternalInputs *) rtM->inputs; ExternalOutputs *rtY = (ExternalOutputs *) rtM->outputs; /* Outport: '<Root>/Out1' incorporates: * UnitDelay: '<Root>/Delay' */ rtY->Out1 = rtDWork->Delay_DSTATE; /* Gain: '<Root>/Gain' incorporates: * Sum: '<Root>/Sum' * UnitDelay: '<Root>/Delay' */ rtDWork->Delay_DSTATE = (rtU->In1 + rtU->In2) * rtP.k1; }
代码生成器将模型数据作为实时模型数据结构体的一部分传递给 Reusable_step
函数。尝试模型配置参数代码接口打包和根级 I/O 传递方式的不同设置,并重新生成代码。观察函数原型是如何变化的。
关闭模型和报告
关闭模型和代码生成报告。
bdclose(model)
在实例之间共享数据
当您的代码多次调用一个可重入模型入口函数时,每次调用都表示该模型的一个实例。默认情况下,代码生成器生成的代码假定每个实例分别读写模型中信号、模块状态和参数的单独副本。
要在各实例之间共享一段参数数据(例如,共享可重用的 PID 控制算法的设定值),请使用参数对象,如
Simulink.Parameter
。然后,将参数配置为使用Auto
之外的存储类,或在代码映射编辑器中,将参数数据的对应类别的默认存储类默认(默认设置)设置为模型默认。参数对象在代码中显示为函数直接访问的全局符号,如全局变量。有关详细信息,请参阅C Data Code Interface Configuration for Model Interface Elements。要在各实例之间共享一段非参数数据(例如,共享故障指示或累加器),请使用数据存储。您可以将数据存储配置为在代码中显示为函数直接访问的全局符号,例如全局变量。使用
Simulink.Signal
对象创建全局数据存储,或使用 Data Store Memory 模块并选择模块参数跨模型实例共享。有关详细信息,请参阅通过创建数据存储对全局数据建模和 Data Store Memory。