生成非虚拟子系统模块功能代码
关于非虚拟子系统代码生成
默认情况下,在为非虚拟子系统生成代码时,代码生成器将与非虚拟子系统关联的内部数据与父模型的内部数据放在相同的数据结构中。这会使跟踪和测试代码变得困难,特别是对于不可重用的子系统。此外,在包含非虚拟子系统的大型模型中,数据结构可能变得很大,并且可能难以编译。
要为非虚拟子系统(包括原子子系统和有条件执行的子系统)生成模块化功能代码,请使用子系统块参数具有单独数据的函数。此块参数指示代码生成器为独立于父模型数据结构的非虚拟子系统函数生成块I/O和DWork数据结构。因此,为子系统生成的代码:
更容易追踪。
更容易测试。
减少模型的全局数据结构的大小。
要使用具有单独数据的函数参数,
使用基于ert的系统目标文件配置模型。
将子系统配置为原子执行或有条件执行。
设置子系统块参数函数包装来
那种一次性的功能
。
要配置子系统以生成模块化功能代码,请调用子系统参数对话框,并进行一系列选择以显示和启用具有单独数据的函数选择。看到配置生成模块功能代码的子系统和非虚拟子系统的模块化功能代码获取详细信息。有关适用的限制,请参见非虚拟子系统模块功能代码限制。
有关为原子子系统生成代码的更多信息,请参见以下部分子系统功能的控制生成(金宝appSimulink Coder)和为单个子系统生成代码和可执行文件(金宝app仿真软件编码器)。
配置生成模块功能代码的子系统
验证包含子系统的模型是否使用基于ert的系统目标文件。
选择您想要生成模块化功能代码的子系统,并打开子系统参数对话框。原子子系统的对话框如下所示。(在有条件执行的子系统的对话框中,对话框选项作为原子单位处理为灰色,可以跳过步骤3。)
如果block参数作为原子单位处理可用于选择但未被选中,则子系统既不是原子执行的,也不是有条件执行的。选择参数作为原子单位处理,这使得函数包装的参数。代码生成选项卡。选择代码生成选项卡。
为函数包装参数,选择
那种一次性的功能
。选择完成后,具有单独数据的函数参数显示。在为非虚拟子系统生成代码之前具有单独数据的函数参数选中后,考虑清除参数生成函数代码,并保存生成的函数
。c
和。h
单独目录中的文件,以便以后进行比较。选择具有单独数据的函数参数。出现了其他参数。
如果需要控制生成的子系统函数和子系统文件的命名,可以修改子系统参数函数名选项和文件名选项。
保存您的子系统参数更改,并通过单击退出对话框好吧。
为子系统生成代码,并检查生成的文件,包括函数
。c
和。h
根据您的子系统参数规范命名的文件。
有关为非虚拟子系统生成代码的更多信息,请参见子系统功能的控制生成(金宝app仿真软件编码器)。有关生成的子系统功能代码的示例,请参见非虚拟子系统的模块化功能代码。
非虚拟子系统的模块化功能代码
控件生成非虚拟子系统功能代码具有单独数据的函数参数被清除并选中,并比较结果。
开放示例模型
rtwdemo_atomic
。然后,打开嵌入式编码器将系统目标文件更改为ert.tlc
。该模型展示了如何保持虚拟子系统的边界。当选择子系统块参数时作为原子单位处理,代码生成器为子系统生成的代码作为原子单元执行。将代码生成器配置为原子时,您可以通过设置函数包装的参数。代码生成选项卡。你可以指定将子系统转换为以下类型的实现之一:
内联
:调用站点的内联子系统代码。函数
:空/空
函数与模型全局数据结构中的I/O和内部数据。可重用的功能
:可重入函数,数据作为函数参数传入。汽车
:代码生成器根据上下文优化实现。
双击SS1子系统并检查其内容。
然后,关闭子系统窗口。
右键单击SS1子系统,从上下文菜单中选择块参数(子系统),并检查设置。金宝app动态仿真模块®当使用子系统参数使子系统原子化时,代码生成器可以避免“人为”的代数循环最小化代数循环的次数。
创建的变体
rtwdemo_atomic
显示了函数代码没有数据分离。在“子系统参数”对话框中,
在主要选项卡上,选择作为原子单位处理。
在代码生成标签:
集函数包装来
那种一次性的功能
。集函数名选项来
用户指定的
。集函数名来
myfun
。集文件名选项来
使用函数名
。这个设置是可选的,但是通过将原子子系统函数代码生成到文件中,简化了后面的代码比较任务myfun.c
和myfun.h
。
做不选择具有单独数据的函数参数。
点击应用要应用更改,请单击好吧退出对话框。
用唯一的文件名保存模型变体(例如,
rtwdemo_atomic1
)到可写位置。
创建的变体
rtwdemo_atomic
显示了函数代码与数据分离。开放模式
rtwdemo_atomic
。打开嵌入式编码器将系统目标文件更改为
ert.tlc
。在模型画布中,右键单击SS1子系统并选择块参数(子系统)。在“子系统参数”对话框中,
在主要选项卡上,选择作为原子单位处理。
在代码生成标签:
集函数包装来
那种一次性的功能
。集函数名选项来
用户指定的
。集函数名来
myfun
。集文件名选项来
使用函数名
。选择具有单独数据的函数。
点击应用要应用更改,请单击好吧退出对话框。
用唯一的文件名保存模型变体(例如,
rtwdemo_atomic2
)到可写位置。
为每个模型生成代码(例如,
rtwdemo_atomic1
和rtwdemo_atomic2
).比较
/模型
。c。h
和myfun.c
/。h
为两个模型生成的文件。有关代码比较的讨论,请参见H非虚拟子系统功能数据分离的文件差异和非虚拟子系统功能数据分离的C文件差异。在本例中,的生成变体没有显著差异
ert_main.c
,
,模型
_private.h
,或模型
_types.hrtwtypes.h
。
H非虚拟子系统功能数据分离的文件差异
选择具有单独数据的函数控件中放置子系统数据的类型定义
myfun.h
文件rtwdemo_atomic2
:/*阻塞系统'
/SS1' */ typedef struct {real_T Integrator;/* ' /Integrator' */} rtB_myfun;/*块状态(自动存储)系统' /SS1' */ typedef struct {real_T Integrator_DSTATE;/* ' /Integrator' */} rtDW_myfun; 为
rtwdemo_atomic1
,子系统数据的类型定义属于模型,出现在rtwdemo_atomic1.h
:/*阻塞信号(自动存储)*/ typedef struct{…real_T积分器;/* '
/Integrator' */} BlockIO_rtwdemo_atomic1;/*块状态(自动存储)系统' ' */ typedef struct {real_T Integrator_DSTATE;/* ' /Integrator' */} D_Work_rtwdemo_atomic1; 选择具有单独数据的函数类中生成以下外部声明
myfun.h
文件rtwdemo_atomic2
:/*外部声明'system '
/SS1 " */ Extern rtB_myfun rtwdemo_atomic2_myfunB;rtwdemo_atomic2_myfunDW;外部void myfun_initialize(void); 生成的代码
rtwdemo_atomic1
包含子系统的模型级外部声明BlockIO
和D_Work
数据,在rtwdemo_atomic1.h
:/*阻塞信号(自动存储)*/ extern BlockIO_rtwdemo_atomic1 rtwdemo_atomic1_B;/*块状态(自动存储)*/ extern D_Work_rtwdemo_atomic1 rtwdemo_atomic1_DWork;
非虚拟子系统功能数据分离的C文件差异
选择具有单独数据的函数导致一个单独的子系统初始化函数,
myfun_initialize
,将在myfun.c
文件rtwdemo_atomic2
:void myfun_initialize(void) {{((real_T*)&rtwdemo_atomic2_myfunB.Integrator)[0] = 0.0;} rtwdemo_atomic2_myfunDW。Integrator_DSTATE = 0.0;}
中的子系统初始化函数
myfun.c
是由模型初始化函数调用rtwdemo_atomic2.c
:/*模型初始化函数*/ void rtwdemo_atomic2_initialize(void){…/*初始化子系统数据*/ myfun_initialize();}
相比之下,对于
rtwdemo_atomic1
中的模型初始化函数初始化子系统数据rtwdemo_atomic1.c
:/*模型初始化函数*/ void rtwdemo_atomic1_initialize(void){…/*阻塞I/O */{…((real_T*)&rtwdemo_atomic1_B.Integrator)[0] = 0.0;} /* states (dwork) */ rtwdemo_atomic1_DWork。Integrator_DSTATE = 0.0;…}
选择具有单独数据的函数类中生成以下声明
myfun.c
文件rtwdemo_atomic2
:/*为系统'
/SS1'声明变量*/ rtB_myfun rtwdemo_atomic2_myfunB;rtDW_myfun rtwdemo_atomic2_myfunDW; 生成的代码
rtwdemo_atomic1
包含子系统的模型级声明BlockIO
和D_Work
数据,在rtwdemo_atomic1.c
:/*阻塞信号(自动存储)*/ BlockIO_rtwdemo_atomic1 rtwdemo_atomic1_B;/*块状态(自动存储)*/ D_Work_rtwdemo_atomic1 rtwdemo_atomic1_DWork;
选择具有单独数据的函数生成标识符命名,以反映数据项的子系统方向。在子系统函数中对子系统数据的引用,例如
myfun
和myfun_update
,都在模型中
函数。例如,将此代码与模型
_stepmyfun
为rtwdemo_atomic2
/* DiscreteIntegrator: '
/Integrator' */ rtwdemo_atomic2_myfunB。Integrator = rtwdemo_atomic2_myfunDW.Integrator_DSTATE; 相应的代码从
myfun
为rtwdemo_atomic1
。/* DiscreteIntegrator: '
/Integrator' */ rtwdemo_atomic1_B. /Integrator = rtwdemo_atomic1_DWork.Integrator_DSTATE;
生成代码中的分区函数
这个例子展示了如何将模型中的子系统与函数名和文件关联起来。
学习如何:
在生成的代码中指定函数和文件名。
确定生成的代码中集成所需要的部分。
为原子子系统生成代码。
识别执行生成的函数所需的数据。
有关示例模型和本系列中的其他示例的信息,请参见从嵌入式系统的控制算法生成C代码。
原子子系统和虚拟子系统
中的示例模型从嵌入式系统的控制算法生成C代码和在生成代码中配置数据接口使用虚拟子系统。虚拟子系统可视地组织块,但不影响模型功能。原子子系统将模型中包含的块作为一个单元进行评估。对于原子子系统,您可以指定额外的功能分区信息。在模型中,原子子系统以粗体边框显示。
模型体系结构中的视图变更
打开示例模型rtwdemo_PCG_Eval_P3。
将模型的副本保存到可写文件夹中。
这个例子展示了如何用函数调用子系统。函数调用子系统:
是原子子系统
使您能够控制子系统的执行顺序
执行时函数调用信号触发器
通过控制子系统的执行顺序,您可以将模型与具有特定执行顺序的现有系统相匹配。
该图标识了函数调用子系统(1)PI_ctrl_1
,PI_ctrl_2
,Pos_Command_Arbitration
。
这个版本的模型包含了新的子系统Execution_Order_Control
(2),其中包含一个对调度程序的调用功能建模的Stateflow®图表。子系统通过函数调用信号(3)控制函数调用子系统的执行顺序。稍后在本例中,您将研究更改执行顺序如何改变模拟结果。
这个版本的模型在PI控制器的输出端包含了新的信号转换模块(4)。有了这些额外的块,代码生成器就可以为PI控制器生成单个可重入函数。
生成代码中的控制函数位置和文件位置
在从嵌入式系统的控制算法生成C代码和在生成代码中配置数据接口,代码生成器创建一个模型
_step
函数,其中包含控制算法代码。但是,许多应用程序需要对函数的文件位置进行更高级别的控制。通过修改原子子系统的参数,您可以在单个模型中指定多个功能。
的子系统参数PI_ctrl_1
。
作为原子单位处理
启用其他子菜单。对于原子子系统,将自动选择和禁用该参数。
样品时间
指定执行的示例时间。不可用于函数调用子系统。
功能打包选项
汽车
——决定子系统在生成的代码中如何出现。此值为默认值。内联
——将子系统代码与模型代码的其余部分内嵌。函数
——作为一个函数为子系统生成代码。可重用的功能
——从子系统生成可重用(可重入)的函数。该函数通过形式参数传递所有输入和输出数据。该函数不直接访问全局变量。
函数名选项
选择
函数
或可重用的功能
为函数包装启用函数名选项。汽车
——确定函数。使用子系统名称
——基于子系统名称的函数。用户指定的
——应用指定的文件名。
文件名选项
选择
函数
或可重用的功能
为函数包装启用文件名选项。汽车
——将函数定义放在为父系统生成的模块中,或者,如果模型根是父系统,则放在model.c
。使用子系统名称
——生成一个单独的文件。文件的名称是子系统或库块的名称。使用函数名
——生成一个单独的文件。文件的名称是您指定的名称函数名选项。用户指定的
——应用指定的唯一文件名。
具有单独数据的函数
设置时启用函数包装来
函数
。选择后,代码生成器将从父模型的数据中分离出子系统的内部数据(例如,信号)。子系统拥有这些独立的数据。
生成可重入代码
嵌入式编码器®支持金宝app可重入代码。可重入代码是多个程序可以同时使用的可重用编程例程。可重入代码用于操作系统和其他使用多线程处理并发事件的系统软件中。可重入代码不维护状态数据,因此函数中没有持久变量。调用程序维护状态变量,并且必须将状态数据传递给函数。多个用户或进程可以共享一个可重入函数的副本。
要生成可重入代码,您必须首先通过配置子系统参数将子系统指定为可重用的函数包装。
在某些情况下,模型的配置阻止了代码的可重用。该表列出了常见问题。
原因解决方案
子系统输出馈送全局信号在数据子系统和全局信号之间添加信号转换块。
生成函数接收数据通过指针选择配置参数>(形式参数)模型引用>按值传递固定大小的标量根输入进行代码生成。
子系统使用全局信号数据在子系统的内部算法中使用一个端口来传递全局数据。
使用掩码将参数值传递到库子系统
要在可重用库块或子系统的作用域之外定义算法参数数据(例如增益或系数),可以应用面具到块或子系统并创建一个掩码参数。然后,您可以为块或子系统的每个实例指定不同的参数值。每个掩码参数在生成的代码中作为可重入函数的形式参数出现。
在这个版本的模型中,子系统PI_ctrl_1
和PI_ctrl_2
是被掩盖的。在每个掩码中,P
和我
增益由数据对象设置,例如I_Gain_2
和P_Gain_2
。
为原子子系统生成代码
在从嵌入式系统的控制算法生成C代码和在生成代码中配置数据接口,则在模型的根级生成代码。或者,您可以构建一个特定的子系统。
要启动子系统构建,请使用上下文菜单。您可以从以下选项中进行选择:
构建这个子系统:将子系统视为单独的模式,并创建完整的C源文件和头文件集。这个选项不支持函数调用子系统。金宝app
生成功能:为子系统生成C代码并创建S-Function包装器。然后可以在原始模型中模拟代码。这个选项不支持函数调用子系统。金宝app
导出功能:生成C代码,而不使用构建这个子系统选择。使用此选项构建使用触发器的子系统,例如函数调用子系统。
或者,选择子系统并在C代码选项卡上,单击构建。
检查生成的代码
此示例比较了为完整系统构建生成的文件与为导出函数生成的文件。您还将研究掩码数据在代码中的显示方式。
运行这三个选项的构建脚本。然后,通过单击超链接检查生成的文件。
rtwdemo_PCG_Eval_P3.c
完整的构建:是的、阶跃函数
PI_ctrl_1:不
Pos_Command_Arbitration:不
PI_ctrl_1.c
完整版本:没有
PI_ctrl_1:是的、触发功能
Pos_Command_Arbitration:不
Pos_Command_Arbitration.c
完整版本:没有
PI_ctrl_1:不
Pos_Command_Arbitration:是的、Init和Function
PI_Ctrl_Reusable.c
ert_main.c
eval_data.c
(1)eval_data.c
在完整和导出功能构建中具有不同的内容。完整构建包括模型使用的所有参数。导出函数只包含子系统使用的变量。
生成代码中的屏蔽数据
在文件中rtwdemo_PCG_Eval_P3.c
,可重入函数的调用点使用数据对象P_Gain
,I_Gain
,P_Gain_2
,I_Gain_2
作为参数。
执行顺序对仿真结果的影响
默认情况下,Simuli金宝appnk®按以下顺序执行子系统:
PI_ctrl_1
PI_ctrl_2
Pos_Command_Arbitration
对于本例,您可以指定两种可选的执行顺序之一。然后,您可以使用测试工具来观察执行顺序对模拟结果的影响。子系统Execution_Order_Control
具有两个控制执行顺序的配置。要选择配置,请使用子系统上下文菜单。
改变执行顺序并观察结果。
仿真结果(随时间变化的油门位置)根据执行顺序略有不同。当节流请求发生变化时,您可以最清楚地看到差异。
关于本系列的下一个示例,请参见从模型和生成的代码中调用外部C代码。
非虚拟子系统模块功能代码限制
非虚拟子系统块参数具有单独数据的函数具有以下限制:
该参数可用于配置了基于ert的系统目标文件的模型。
应用该参数的非虚拟子系统不能有多个采样次数或连续采样次数;也就是说,子系统必须是具有离散采样时间的单速率。
非虚拟子系统不能包含连续状态。
非虚拟子系统不能输出函数调用信号。
非虚拟子系统不能包含非内联s函数。
为非虚拟子系统生成的文件将引用模型范围的头文件,例如
和模型
。h
。模型
_private.h参数不兼容经典调用接口参数。同时选择两个参数会产生错误。
参数不兼容
可重用的功能
模型配置参数设置代码接口封装。同时选择两个参数会产生错误。
当您为一个子系统选择参数时,包含该子系统的模型不能包含数据存储内存块与跨模型实例共享选中。看到数据存储内存。