本页对应的英文页面已更新,但尚未翻译。 若要查看最新内容,请点击此处访问英文页面。

使用 C Caller 模块集成 C 代码

您可以使用 C Caller 模块将新的或现有的 C 代码集成到 Simulink® 中。要在 Simulink 模型中创建自定义模块,C Caller 模块允许您调用在外部源代码和库中指定的外部 C 函数。C Caller 模块具有以下优势:

  • 简单 C 函数的自动化集成

  • Simulink Coverage™Simulink Test™Simulink Design Verifier™ 的集成

  • Simulink Coder™ 的集成

C Caller 模块允许您将 C 算法引入 Simulink。要对动态系统进行建模,请改用 S-Function Builder。接下来的步骤说明使用 C Caller 模块将 C 代码集成到 Simulink 中的工作流。

指定源代码和依存关系

指定包含您的 C 函数的外部源代码文件。

  1. 从 Simulink 工具条中,打开 Configuration Parameters

  2. 在左窗格中,选择 Simulation Target

  3. 要启用通过 C Caller 模块的代码解析,请确保选中 Import custom code 框。

    目录和文件路径可以是模型目录或当前工作目录的绝对和相对文件路径。请参阅指定自定义代码的相对路径 (Stateflow)

  4. 选择 Header file,输入具有 #include 标记的头文件的名称。

  5. Additional build information 下,选择 Include directories,并输入存储其他编译信息(如头文件)的文件夹。

  6. 选择 Source files,并输入源文件的路径和名称。如果模型和源文件在不同目录中,请在文件名之前输入包含源文件的目录。

注意

如果在头文件中声明了一个函数但没有在源代码中实现该函数,则会自动生成空 stub 函数来仿真和编译模型。

定义默认函数数组布局

您可以指定矩阵数据在 Simulink 中的存储顺序。进出您的 C 函数的矩阵数据会转换为您指定的默认函数数组布局。如果未指定函数数组布局,矩阵数据将按照与 Simulink 数据相同的顺序通过 C Caller,由于行-列优先混乱,可能会出现计算错误。确保对所有 Simulink 数据使用相同的默认函数数组布局。

  • Column-Major - C Caller 模块按列优先顺序处理 Simulink 数据。假设您有一个 3×3 矩阵。在 C Caller 模块中,该矩阵按以下顺序存储:第一列、第二列和第三列。

  • Row-Major - C Caller 模块按行优先顺序处理 Simulink 数据。假设您有一个 3×3 矩阵。在 C Caller 模块中,该矩阵按以下顺序存储:第一行、第二行和第三行。

  • Any - 数组数据可以按列优先顺序和行优先顺序存储在 C Caller 模块中。因此,您能以列优先方式和行优先方式生成代码。

  • Not specified - 数组数据可以按列优先顺序和行优先顺序存储。与 Any 设置相比,您只能以列优先方式生成代码。

要了解有关 Simulink 中行优先和列优先数组布局的更多信息,请参阅 Default function array layout

  1. 选择 Default Array Function Layout 下的一个数组布局选项。

  2. 如果您需要对代码中的某些函数应用特定的数组布局,请点击 Specify by Function 以选择这些函数。

  3. 点击 Apply 以接受您的更改。

  4. 点击 OK 关闭 Configuration Parameters

调用 C Caller 模块并指定端口

您可以在 Simulink 画布中键入 C Caller,以开始在 Simulink 中集成您的自定义 C 代码。或者,从 Library Browser > User-Defined Functions 中拖动一个 C Caller 模块。双击该模块打开 Block Parameters 对话框,查看您的函数名称和端口设定。

  1. 点击 Refresh custom code 导入您的源代码及其依存关系。

  2. 您的 C 函数显示在 Function Name 下。如果您看不到完整的函数列表,请点击 重新导入您的源代码。

  3. 要在头文件中查看函数声明或函数的输入/输出变量,请点击 Go to function declaration 以导航源文件。

  4. 要更改源文件及其依存关系,或者要定义并选择函数数组布局,请点击 Custom code settings 以在 Configuration Parameters 中打开 Simulation Target 选项卡。

将 C 函数参数映射到 Simulink 端口

您可以使用 C Caller 模块中的 Port specification 表,并通过命令行创建 FunctionPortSpecification 对象,将源代码中的 C 函数参数映射到 Simulink 端口。在源代码中,头文件包含要连接到 Simulink 端口的 C 函数参数。

extern void mean_filter(const unsigned char* src,
                           unsigned char* dst,
                           unsigned int width, unsigned int height,
                           unsigned int filterSize);

Port specification 显示您的参数的详细内容,以及它们如何连接到您在 Simulink 中的 C Caller 模块。

Arg name - 指定输入和输出参数的名称。Arg name 是源代码中的 C 函数中定义的函数实参或形参名称。此列仅供参考。

Scope - 指定 C 函数参数如何映射到 Simulink 作用域。您的参数根据函数定义具有默认作用域,并且您可以根据源代码中的函数定义来更改作用域。

Simulink Scope作用域到模块的映射
input模块输入端口
output模块输出端口
inputoutput模块输入和输出端口
parameter模块可调参数
constant常量值

当具有常量限定符定义(如 const double *u)时,该参数必须为 input 或 parameter 类型。如果没有常量限定符,则该参数默认为 output 类型,您可以将其更改为 “input”、“inputoutput” 或 “parameter” 作用域。在这种情况下,请确保 C 函数不会修改指针指向的内存。如果参数是 output 类型,则在该函数的每次调用中,该指针指向的每个元素都应该重新分配。

C 参数

Simulink Scope

函数返回

output

double u

input”、“parameter”、“constant

double u[]

double u[][2]

double u[2][3]

output”(默认值)、“input”、“parameter

double *u

output”(默认值)、“inputoutput”、“input”、“parameter

const double *u

const double u[]

const double u[][2]

const double u[2][3]

input”(默认值)、“parameter

要将 C 函数参数映射到 “inputoutput” 端口,请在函数定义中将变量定义为指针。

extern void mean_filter(unsigned char* src,
                           unsigned int width, unsigned int height,
                           unsigned int filterSize);

然后,在 Port Specification 表中选择 “inputoutput” 作为端口作用域,并将结果函数输出赋给自定义函数中的输入变量。

Label - 指示 Simulink 模块中对应参数的标签。默认情况下,参数标签与参数名称相同,除非您更改它。

Simulink ScopeSimulink 端口标签

input”、“output

端口名称
inputoutput输入和输出端口中的端口名称

parameter

参数名称

constant

常量值的表达式。

使用输入参数名称的 size 表达式,例如 size(in1,1)

Type - 说明 Simulink 数据类型和 C 函数参数数据类型之间的匹配。

C 参数数据类型Simulink 数据类型
有符号字符int8
无符号字符uint8
charint8 或 uint8,具体取决于编译器
int*int32
无符号 int*uint32
short *int16
long *int32 或 fixdt(1,64,0),取决于操作系统
float单精度
双精度双精度
int8_t*int8
uint8_t*int8
int16_t*int16
uint16_t*uint16
int32_t*int32
uint32_t*uint32
typedef struct {…} AStruct**总线:AStruct
typedef enum {..} AnEnum**枚举:AnEnum

* 如果 C Caller 采用整数类型,例如 int16_t,您可以将其修改为具有匹配的基类型的定点类型,例如修改为 fixdt(1, 16, 3)。

** C Caller 同步按钮提示您将 C 函数使用的结构体或枚举类型导入为 Simulink 总线和枚举类型。

Size - 指定参数中的数据维度。

C 参数维度Simulink 端口维度

double u

标量 (1)

double u[]

double u[][2]

继承 (-1)(默认值)

如果参数用于输出端口,则应指定大小。无法继承输出端口的大小。

double *u

继承 (-1)(默认值)

如果参数是针对 “inputoutput” 端口的,则无法继承大小,即使可以继承 “output” 端口的大小也是如此。

double u[2][3]

大小为 [2, 3]。

创建 FunctionPortSpecification 对象并编辑 C Caller 模块属性

要以编程方式更改 Port Specification 表属性,您可以创建 FunctionPortSpecification 对象并修改其属性。要为模型中的所选 C Caller 模块创建 FunctionPortSpecification 对象,请在命令行中键入:

myCCallerConfigObj = get_param(gcb, 'FunctionPortSpecification')
myCCallerConfigObj = 

  FunctionPortSpecification with properties:

        CPrototype: 'real_T add(real_T u1, real_T u2);'
    InputArguments: [1×2 Simulink.CustomCode.FunctionArgument]
    ReturnArgument: [1×1 Simulink.CustomCode.FunctionArgument]
CPrototype 属性是只读属性,它显示 C 函数输入变量的声明。InputArgumentReturnArgument 属性创建了 FunctionArgument 对象,您可以根据上面为 Port Specification 表定义的规则进一步编辑其属性。请参阅 FunctionPortSpecification 了解详细信息。

创建自定义 C Caller 库

您可以创建一个库模型来对 C Caller 模块进行分组并保持模型组织良好。

  1. 打开一个新库模型。在 Simulation 选项卡上,选择 New > Library

  2. Modeling 选项卡上,在 Design 下,点击 Simulation Custom Code

  3. 根据您的代码,在 Language 选项中选择 CC++,并确保 Import custom code 框已选中。

  4. 按照指定源代码和依存关系中的说明添加源文件及其依存关系。

  5. 创建 C Caller 模块来调用 C 函数。

  6. 要将库模型中的模块插入 Simulink 模型,只需将该模块拖到模型中即可。

为自定义代码生成调试符号

要将外部调试器连接到 MATLAB® 进程,并调试外部 C 代码,请使用以下命令生成调试符号:

Simulink.CustomCode.debugSymbols('on')
在启用此设置并更新模型后,将生成调试符号,您可以将外部调试器连接到 MATLAB 进程。

使用以下命令关闭此设置:

Simulink.CustomCode.debugSymbols('off')

限制

  • Global Initialization of C States - 如果您的 C 函数读取或写入全局或静态变量,请遵守顺序。例如,如果多个 C 函数正在访问同一组全局变量,模块的执行顺序可能会导致意外的结果。

  • Initialization/Termination of Custom Code Settings - 如果您需要为自定义代码分配和取消分配内存,请在自定义代码设置的 Initialize functionTerminate function 字段中插入 allocate 和 deallocate。

  • Complex Data Support - C Caller 模块不支持 Simulink 中的复数数据类型。

  • Continuous Sample Time - C Caller 模块不支持连续采样时间。

  • Variable Arguments - 不支持 C 语言中的变量参数,例如 int sprintf(char *str, const char *format, ...)

  • C++ Syntax - C Caller 模块不直接支持原生 C++ 语法。您需要编写 C 函数封装程序来与 C++ 代码对接。

要测试包含 C Caller 模块的模型,请参阅 Test Integrated C Code (Simulink Test)

另请参阅

| | | | | |

相关主题