为模型入口函数配置生成的 C 函数接口
什么是入口函数?
入口是代码中发生程序控制权(执行)转移的位置。主函数 (main()
) 是进入 C/C++ 程序的入口,在应用程序开始执行时调用。对其他函数的调用(例如从 main
函数调用)是进入函数代码的入口。程序控制权会转移到被调函数。函数代码随后执行,在完成后将控制权交还给 main
或其他主调函数。
为模型生成代码时,代码生成器会定义一组入口函数,您可以调用这些函数来执行生成的代码。您可以从外部代码或生成的主函数的修改版调用生成的函数。
代码生成报告的“代码接口报告”部分会列出代码生成器为模型生成的入口函数。有关详细信息,请参阅 Analyze Generated Data Code Interface Report。
生成的入口函数的类型
代码生成器为下列类型的模型函数生成入口函数。
模型函数的类型 | 模型源函数名称 | 默认的生成函数名称 | 描述 |
---|---|---|---|
导出函数(需要 Embedded Coder®) | ExportedFunction: ,其中 是模型中函数调用 Inport 模块的名称 | 或 (如果指定) | 对于导出函数模型,即为子系统的导出函数。 |
初始化函数 | Initialize |
| 模型的初始化代码。在应用程序代码的开始,调用函数一次。请不要使用此函数重置实时模型数据结构体 ( |
分区函数 | Partition: ,其中 是从模型中的模块显式创建的一个分区并显示在 Simulink® 调度编辑器中(例如 P1),或是“并行执行”对话框中的一个任务名称 | ,其中 基于模型采样周期唯一标识生成的函数 | 对于模型分区,输出并更新代码。模型配置参数单一输出/更新函数处于选中状态(默认值)。 |
分区更新函数 | PartitionUpdate: ,其中 是从模型中的模块显式创建的一个分区并显示在 Simulink® 调度编辑器中(例如 P1),或是“并行执行”对话框中的一个任务名称 | 和 ,其中 基于模型采样周期唯一标识生成的函数 | 对于模型分区,使用分别的函数输出和更新代码。模型配置参数单一输出/更新函数处于未选中状态。 |
周期性多任务函数 | Periodic: ,其中 是一个注释,对应于多任务模型的一个周期性或连续速率的采样时间周期(例如,D1) | ,其中 基于模型采样周期唯一标识生成的函数 | 对于为多任务配置的一个基于速率的模型中的模块,输出和更新代码。代码生成器为每个采样周期生成一个函数。模型配置参数单一输出/更新函数处于选中状态(默认值)。 |
周期性多任务更新函数 | PeriodicUpdate: ,其中 是一个注释,对应于多任务模型的一个周期性或连续速率的采样时间周期(例如,D1) | 和 ,其中 基于模型采样周期唯一标识生成的函数 | 对于为多任务配置的一个基于速率的模型中的模块,分别在单独的函数中输出和更新代码。代码生成器为每个采样周期生成输出和更新函数。模型配置参数单一输出/更新函数处于未选中状态。 |
周期性单任务函数 | Periodic |
| 对于为单任务配置的基于速率的模型中的模块,输出和更新代码。模型配置参数单一输出/更新函数处于选中状态(默认值)。 |
周期性单任务更新函数 | PeriodicUpdate | 和
| 对于为单任务配置的基于速率的模型中的模块,分别在单独的函数中输出和更新代码。模型配置参数单一输出/更新函数处于未选中状态。 |
重置函数 | Reset: ,其中 是模型中重置函数的名称 |
| 如果模型包含 Reset Function 模块,则重置生成的代码。要重置条件或状态,请从应用程序代码中调用函数。 |
Simulink 函数 | Simulink Function: ,其中 是模型中 Simulink Function 模块的名称 | 对于全局 Simulink Function 模块,为 ;对于限定作用域的 Simulink Function 模块,为
| 对于导出函数模型,是 Simulink Function 模块的导出函数。 |
终止函数 | Terminate |
| 用于关闭系统的代码。对于基于 ERT 的模型,您可以通过清除模型配置参数需要终止函数(默认设置)来隐藏此函数的生成。 |
如果您有 Embedded Coder 软件,为了便于集成外部代码和生成的代码并符合代码标准和规范,您可以配置代码生成器如何从模型或子系统生成函数接口。
配置入口函数是否可重用
默认情况下,对于顶层模型,代码生成器生成不可重用或不可重入的代码。入口函数有一个 void-void
接口。代码通过直接访问驻留在共享内存中的全局数据结构体来与其他代码通信。
如果您的应用程序需要可重用的多实例入口函数代码,您可以配置代码生成器使用唯一数据来调用每个函数(实例)。在这种情况下,代码是可重入的。
您可以使用模型配置参数代码接口打包和相关参数来配置入口函数是否可重用。您选择的参数设置取决于系统目标文件的配置选择、编程语言和参量接口等因素。
单实例 C 入口函数的默认配置
默认情况下,对于基于 GRT 和基于 ERT 的系统目标文件,代码生成器生成单实例 C 入口函数。生成的代码:
创建不带参量的执行函数 (
void-void
)。为模型数据结构体静态分配内存(在编译时)。
配置单实例入口函数代码的默认模型配置参数设置为:
生成可重用的多实例 C 入口函数
您可以配置代码生成器,为基于 GRT 或基于 ERT 的系统目标文件生成可重用的 C 入口函数。但是,代码生成器默认生成的各函数接口有所不同。假设模型配置参数语言设置为 C 且代码接口打包设置为可重用函数,代码生成器为每个系统目标文件场景生成以下入口函数代码。
系统目标文件 | 接口 |
---|---|
基于 GRT |
|
基于 ERT |
|
如果您使用的是基于 ERT 的系统目标文件,并希望生成可重用、可重入的多实例 C 入口函数,请考虑:
使用动态内存分配来初始化模型数据结构体。选择使用动态内存分配进行模型初始化。
将模型根级 Inport 模块的值打包到一个结构体中,将根级 Outport 模块的值打包到另一个结构体中,并按引用将这些结构体作为参量传递给执行函数。将根级 I/O 传递方式设置为结构体引用。
将模型根级 Inport 模块和 Outport 模块的值打包到实时模型数据结构体中,并按引用将该结构体作为参量传递给执行函数。将根级 I/O 传递方式设置为模型数据结构体的一部分。
选择配置生成的 C 函数接口的方法
为了便于集成外部代码和生成的代码并符合代码标准和规范,您可以使用代码映射编辑器或代码映射 API 来配置代码生成器如何从模型或子系统生成函数接口。
对于配置了服务接口的模型,您可以配置:
函数名称
表示为 Simulink Function 模块的子组件中的函数和组件模型中的函数的函数参量
内存段
配置 | 更多信息 |
---|---|
模型中函数类别(初始化/终止、执行和共享实用工具)的默认命名规则 | Configure Default Code Generation for Functions |
单个入口函数的名称(覆盖默认命名规则) | 为单个 C 入口函数配置名称 |
基本速率单步入口函数的单步函数接口(函数名称、返回值和参量 C 类型限定符、名称和顺序),以交互方式配置 | 为单个单步函数配置名称和参量 |
Simulink Function 和 Function Caller 模块的函数接口(函数名称、返回值和参量 C 类型限定符、名称和顺序),以交互方式配置 | Configure Entry-Point Function Interfaces for Simulink Function and Function Caller Blocks |
您可以使用软件在环 (SIL) 测试来验证为自定义入口函数生成的代码。使用您的生成代码创建一个 SIL 模块。然后,将该 SIL 模块集成到一个模型中,以验证生成代码提供与原始模型或非虚拟子系统相同的结果。有关详细信息,请参阅 选择 SIL 或 PIL 方法。
为函数类别配置默认代码生成设置
通过为整个模型中的函数类别指定默认配置,减少为 C 代码生成而准备模型的工作量。例如,您可以配置函数命名规则和函数代码在内存段中的位置。应用默认配置可以节省时间并降低在代码中引入错误的风险,尤其是对于具有大量函数的模型。
代码生成器为下列类别的模型函数生成入口函数:
函数类别 | 描述 |
---|---|
初始化/终止 | 用于初始化和关闭系统的函数 |
执行 | 用于启动执行和重置的函数 |
共享实用工具 | 共享工具函数代码 |
通过使用代码映射编辑器 - C 或代码映射 API 函数 setFunctionDefault
,为函数配置默认代码映射。使用这些接口,您可以将函数类别与模型的 Embedded Coder 字典中定义的函数自定义模板相关联。
如果您的应用程序要求您配置内存中入口函数的位置(例如,用于针对特定硬件优化生成代码),您可以将默认内存段应用于模型中的一个函数类别。在代码映射编辑器中,将函数类别映射到定义为使用特定内存段的函数自定义模板。请参阅Create Function Customization Template。
如果函数自定义模板不存在,您可以使用 Embedded Coder 字典创建一个(请参阅Define Service Interfaces, Storage Classes, Memory Sections, and Function Templates for Software Architecture)。
有关如何为函数类别设置默认配置的示例,请参阅Configure Default C Code Generation for Categories of Data Elements and Functions。
为单个 C 入口函数配置名称
为了使您的生成的 C 代码符合代码标准和规范,或更轻松地将该代码与外部代码集成,您可以配置单个入口函数的名称。例如,您可以将为一个模型生成的初始化函数命名为 myInitFunc
。
如果您的模型满足下列至少一个条件,请考虑单独配置函数的名称:
使用多个要求唯一命名的函数。
使用很少的函数。
具有函数类别的默认配置,并且您需要覆盖特定函数的配置。
通过使用代码映射编辑器或代码映射 API 函数 setFunction,为单个单步函数配置函数名称。使用这些接口,您可以将函数与在模型的 Embedded Coder 字典中定义的函数自定义模板相关联,并指定函数名称。
此示例说明如何更改模型 ConfigurationInterface
的 initialize
函数的名称。
打开模型。
openExample('ConfigurationInterface')
打开 Embedded Coder。
在 C 代码选项卡上,选择代码接口 > 个体元素代码映射。
在代码映射编辑器的函数选项卡中,使用以下方法之一更改函数名称:
在函数名称列中,输入函数的名称。
在函数预览列中,点击函数原型超链接以打开配置对话框。在 C 初始化函数名称字段中,输入函数名称。点击应用以验证 C 函数原型字段中的更改,或点击确定以退出对话框并在“函数映射”编辑器的函数预览列中查看函数名称。
在此示例中,将
initialize
函数的名称更改为fcnprotoctrl_init
。保存模型。
生成代码。
验证生成代码中的更改。在代码视图中,查找函数名称
fcnprotoctrl_init
的实例。函数名称出现在生成的文件ConfigurationInterface.h
和ConfigurationInterface.c
中。在
ConfigurationInterface.h
中:extern void fcnprotoctrl_init(void);
在
ConfigurationInterface.c
中:void fcnprotoctrl_init(void) { ... }
为单个单步函数配置名称和参量
为了使您的生成的 C 代码符合代码标准和规范,或更轻松地将代码与外部代码集成,您可以配置为 Simulink 周期函数生成的各个单步函数的名称和参量。您可以自定义单步函数的以下方面:
函数名称
参量名称
参量的顺序
返回值和参量数据限定符
参量的缓冲优化
如果您的模型满足下列至少一个条件,请考虑单独配置单步函数的名称和参量:
是周期性单任务模型,且代码生成器为其生成一个单步函数。
执行函数类别具有默认配置,并且您需要覆盖特定单步函数的配置。
通过使用代码映射编辑器或代码映射 API 函数 setFunction
,为各个单步函数配置代码映射。使用这些接口,您可以将函数与在模型的 Embedded Coder 字典中定义的函数自定义模板相关联,并完全自定义单步函数原型。
此示例说明如何为基于速率的单任务模型自定义单步函数名称和参量。
打开配置对话框
1.打开模型 ConfigurationInterface.slx
。
open_system("ConfigurationInterface");
2.打开 Embedded Coder。
3.在 C 代码选项卡上,选择代码接口 > 个体元素代码映射。
4.在代码映射编辑器中,点击函数选项卡。
5.对于单步函数行,在函数预览列中,点击原型超链接以打开“配置 C 单步函数接口”对话框。
在“配置 C 单步函数接口”对话框中,C 函数原型字段显示您对函数原型所做更改的预览。
有关配置为生成多实例代码的模型,请参阅从顶层模型生成可重入代码。
自定义函数名称
1.在“配置 C 单步函数接口”对话框中,将 C 单步函数名称设置为 configinterface_run
。函数预览会更新以反映新函数名称。
2.点击应用,关闭对话框,然后保存模型。
3.生成代码并验证名称更改。
点击代码选项卡。在代码视图的文件列表中,选择文件
ConfigurationInterface.h
。在搜索字段中,验证代码元素列表是否包含函数名称configinterface_run
。要查看声明,请选择函数名称。
声明在代码中高亮显示:
验证文件
ConfigurationInterface.c
中的名称更改。要查看源代码(定义),请在搜索字段中,选择configinterface_run
。
有关更多示例,请参阅为单个 C 入口函数配置名称。
自定义函数参量
配置全局数据结构体
默认情况下,顶层模型或引用模型使用 void-void
单步函数传递数据。借助此类型的函数,生成的代码可通过访问存储为共享内存中的数据结构体的全局数据与外部代码进行通信。
要将模型配置为具有 void-void
单步函数,请打开“配置 C 单步函数接口”对话框,并清除为单步函数原型配置参量复选框。验证 C 函数原型预览中的更改。
配置参量
基于速率的模型单步函数可以使用参量传递数据。您可以自定义下列参量设置:
返回值
类型限定符
名称
顺序
示例
1.要配置模型的函数原型,默认存储类必须设置为 'Default'
。
在代码映射编辑器中,在数据默认值选项卡上,将输入端口和输出端口的存储类设置为
Default
。
在输入端口选项卡上,将 In1 的存储类设置为
Model default
。
2.打开“配置 C 单步函数接口”对话框。在代码映射编辑器中,点击函数选项卡。然后,点击单步函数的函数预览。
3.在“配置 C 单步函数接口”对话框中,选择为单步函数原型配置参量。
4.点击获取默认值。对话框将展开,以显示用于配置函数返回值的字段和用于列出具有默认设置的输入和输出参量的表。
4.自定义单步函数的返回值。将 C 返回参量设置为 void
或输出参量之一。对于此示例,选择 void
。
5.对于每个参量,指定一个 C 类型限定符。
类型限定符:
Value
:值,例如,arg
Const
:具有const
限定符的值,例如,const arg
Pointer to const
:具有const
限定符并由指针引用的值,例如,const
*
arg
Pointer
:由指针引用的值,例如,*
arg
Const pointer to const
:具有const
限定符、引用指针以及指针本身的值,例如,const
*
const arg
包含引用模型的模型
对于引用模型,单步函数接口中根输入参量的类型限定符设置为
Auto
。代码生成器通过生成从源信号中丢弃const
限定符的类型转换来使用接口设定。对于引用模型的父模型,源信号的类型限定符设置为
Auto
以外的值。要覆盖此行为,请在引用模型中添加一个const
类型限定符。
对于此示例,不要更改 C 类型限定符。
6.通过编辑 C 标识符名称列中的值来自定义参量名称。
对于此示例,通过删除下划线来更改参量的名称,例如,将 arg_In1 更改为 argIn1。
7.通过将表行拖到新位置来自定义参量顺序。
对于此示例,将 Out1 移至第一个位置。
8.验证、应用更改、关闭对话框并保存模型。
9.生成代码并在代码视图中确认更改。
通过检查搜索字段是否包含
configinterface_run
函数,确认您在文件ConfigurationInterface.h
中所做的更改。要查看函数声明,请选择函数名称。
验证您在文件
ConfigurationInterface.c
中的更改。要查看函数的定义,请选择函数名称configinterface_run
。
实际原型不同于原型预览
在“配置 C 单步函数接口”对话框中,引用模型的函数原型预览可能比生成代码中的函数原型显示更少的参量。
例如,假设有名为 mdlref_counter
的模型,该模型包含输入端口 (arg_input
)、输出端口 (arg_output
) 及饱和模块,该饱和模块具有两个限值参数参量,它们在工作区中的名称为 lower_saturation_limit
和 upper_saturation_limit
。“配置 C 单步函数接口”对话框将函数原型预览显示为:
mdlref_counter_custom(arg_input, arg_output)
在生成的代码中,原型包括以下参量:
mdlref_counter_custom(real_T arg_input, real_T arg_output, real_T rtp_lower_saturation_limit, real_T rtp_upper_saturation_limit)
优化参量的缓冲
您可以在模型的单步函数中优化 I/O 参量所需的缓冲。如果在配置输入端口和输出端口对组时遵守以下要求,则代码生成器会合并对应的参量并重用相关联的缓冲区。
Inport 和 Outport 模块必须具有相同的属性,包括数据类型、维度和采样率。
Inport 和 Outport 模块的采样率必须与模型的基本速率相同。
条件执行子系统不能驱动 Outport 模块。
单个非虚拟模块输出必须驱动 Outport 模块。例如,合并多个缓冲区的 Mux 模块不能驱动 Outport 模块。
在“配置 C 单步函数接口”对话框中,必须使用相同的 C 类型限定符和标识符名称配置输入端口和输出端口。
本节说明如何合并示例模型 ConfigurationInterface
的端口 In2
和 Out1
的参量。
1.打开模型 ConfigurationInterface
的“配置 C 单步函数接口”对话框。
2.通过选择为单步函数原型配置参量打开参量的显示。
3.对于端口 In3
和 Out2
,将 C 类型限定符设置为 Pointer
,将 C 标识符名称设置为 sharedArg
。
4.确认预览显示 argIn3
和 argOut2
的合并后的参量。
5.验证、应用更改、关闭对话框并保存模型。
6.生成并查看代码。在代码视图中,搜索 configinterface_run
函数并检查函数接口。对于此示例,共享参量显示在 Inport 模块的读取代码中和 Outport 模块的写入代码中。
以编程方式配置 C 入口函数的代码生成设置
要为 C 代码生成自动配置模型函数,请使用代码映射的编程接口。例如,当创建自定义模块库或应用程序测试环境的一部分时,可使用编程接口来自动化函数配置。
这些函数的典型用途包括:
创建一个函数接口。
修改一个现有函数接口。
基于模型的默认配置信息创建一个函数接口。
将该模型函数接口重置为默认 ERT 函数配置。
有关如何以编程方式配置 C 入口函数的代码生成设置的示例,请参阅Configure Default Data and Function Code Generation Programmatically。此示例说明如何为函数类别和单个函数配置默认设置。
如何与生成的入口函数对接
为模型生成代码后,使用代码视图查看生成的入口函数,以及表示外部输入和输出端口的变量(如果适用)。
将
#include
语句添加到外部代码中,这些语句包括声明模型入口函数的生成的头文件。添加一条
#include
语句以包含生成的文件rtwtypes.h
。此文件提供类型定义、#define
语句和枚举。初始化目标特定的数据结构体和硬件,如 ADC 或 DAC。
如果适用,为可重用模型的每个实例初始化数据。
如果适用,将输入数据写入表示模型 Inport 模块的生成变量。
调用生成的入口函数或设置
rt_OneStep
函数的使用。如果适用,从表示模型 Outport 模块的生成变量中读取数据。
有关详细信息,请参阅Deploy Applications to Target Hardware。
C 函数接口自定义限制
生成的 C 函数接口的自定义有以下限制:
您必须选择模型配置参数单一输出/更新函数。
支持多速率模型,但您必须为单任务配置模型。
您必须配置根级输入端口和输出端口以使用
Default
存储类。如果您选择自定义函数接口,您必须提供自己的自定义
main
程序。您无法使用 MathWorks® 提供的静态rt_main.c
来配置函数接口。指定非默认的函数接口配置会导致生成的代码与默认静态rt_main.c
不匹配。代码生成器会删除模型根输入端口的数据结构体,除非由不可重用函数实现的子系统使用一个或更多个输入端口的值。
代码生成器会删除模型的根输出端口的数据结构体,除非您启用 MAT 文件记录或者一个或更多个输出端口的采样时间不是基本速率(包括恒定速率)。
如果您复制子系统模块以在新模型或同一模型中创建模块,则原始子系统模块的函数接口信息不会复制到新子系统模块中。
如果您有 Stateflow®,则对于使用模型根输入端口值或调用使用模型根输入端口值的子系统的 Stateflow 图,请执行以下操作之一来生成代码:
在 Stateflow 图中,清除初始化时执行(进入)图复选框。
将 Stateflow 函数设置为不可重用的函数。
在根输入端口后立即插入 Simulink® Signal Conversion 模块。在 Signal Conversion 模块参数对话框中,选择从 ''模块简化'' 优化中排除此模块。
如果模型根输入端口值连接到 Simscape™ 转换模块,请在根输入端口和 Simscape 转换模块之间插入 Simulink Signal Conversion 模块。在 Signal Conversion 模块参数对话框中,选择从 ''模块简化'' 优化中排除此模块。
当编译配置有函数接口的引用模型时,不要使用虚拟总线作为引用模型的输入或输出。请改用非虚拟总线。
如果 C 函数接口不是默认值,则忽略模型配置参数为代码生成按值传递固定大小的标量根输入的值。有关详细信息,请参阅Pass fixed-size scalar root inputs by value for code generation。
另请参阅
Simulink Function | Function Caller