检索 使用 MATLAB Function 模块集成 C 代码
从 Simulink 模型中调用 C 代码
您可以使用 MATLAB Function 模块从 Simulink® 模型中调用外部 C 代码。请执行下列简要步骤:
首先找到包含源 (.c) 和头 (.h) 文件的现有 C 代码。
在 MATLAB Function 模块中,输入调用 C 代码的 MATLAB® 代码。使用函数 coder.ceval。要通过引用传递数据,请使用 coder.ref、coder.rref 或 coder.wref。
在 Model Configuration Parameters 对话框的 Simulation Target 窗格中,指定用于仿真的 C 源文件和头文件。使用双引号引起头文件,例如 #include "program.h"。如果需要访问位于工作文件夹之外的 C 源文件和头文件,请在 Simulation Target 窗格的 Include Directories 文本框中列出文件的路径。
或者,使用 coder.cinclude 和 coder.updateBuildInfo 函数在 MATLAB 代码中指定源文件和头文件。要开发与外部代码的接口,您可以使用 coder.ExternalDependency 类。要查看支持的工作流,请参阅Import custom code。
测试 Simulink 模型并确保它正常工作。
如果您拥有 Simulink Coder™ 许可证,则可以使用此方法为目标生成代码。要使用相同的源文件和头文件进行代码生成,请在 Code Generation > Custom Code 窗格中点击 Use the same custom code settings as Simulation Target。还可以指定不同的源文件和头文件。
要条件化您的代码以执行仿真的不同命令和代码生成,可以使用 coder.target 函数。
在 MATLAB Function 模块中使用 coder.ceval
此示例说明如何从 MATLAB Function 模块中调用简单的 C 程序 doubleIt。
1.在当前工作文件夹中创建源文件 doubleIt.c。
#include "doubleIt.h"
double doubleIt(double u)
{
return(u*2.0);
}
2.在当前工作文件夹中创建头文件 doubleIt.h。
#ifndef MYFN
#define MYFN
double doubleIt(double u);
#endif
3.新建一个 Simulink 模型。将其保存为 myModel。
4.在 Library Browser 的 User-Defined Functions 中,将 MATLAB Function 模块添加到模型中,然后双击该模块打开编辑器。
5.输入调用 doubleIt 程序的代码:
function y = callingDoubleIt(u)
y = 0.0;
y = coder.ceval('doubleIt',u);
6.将值为 3.5 的 Constant 模块连接到 MATLAB Function 模块的输入端口。
7.将 Display 模块连接到输出端口。
8.在 Model Configuration Parameters 对话框中,打开 Simulation Target 窗格。
9.在 Insert custom C code in generated 部分,从列表中选择 Header file,然后在 Header file 文本框中输入 #include "doubleIt.h"。
10.在 Additional build information 部分中,从列表中选择 Source files,在 Source files 文本框中输入 doubleIt.c,然后点击 OK。
11.运行仿真。值 7 将出现在 Display 模块上。
控制导入的总线和枚举类型定义
此过程仅适用于仿真。
Simulink 会为 MATLAB Function 模块和 Stateflow® 生成代码以进行模型仿真。使用 MATLAB Function 模块或 Stateflow 调用外部 C 代码时,您可以控制在模型仿真中导入的总线和枚举的类型定义。
Simulink 可以生成类型定义,您也可以提供包含类型定义的头文件。您可以使用 Model Configuration Parameters 对话框中的 Generate typedefs for imported bus and enumeration types 复选框来控制此行为。
要提供定义枚举和总线类型的自定义头文件,请执行以下操作:
清除 Generate typedefs for imported bus and enumeration types 复选框。
在 Simulation Target 窗格上的 Header file 文本框中列出头文件。
要配置 Simulink 自动生成类型定义,请执行以下操作:
选中 Generate typedefs for imported bus and enumeration types 复选框。
不要列出与总线或枚举对应的头文件。
coder.ceval
调用外部 C/C++ 函数全页折叠
语法
coder.ceval(cfun_name)
coder.ceval(cfun_name,cfun_arguments)
coder.ceval('-global',cfun_name)
coder.ceval('-global',cfun_name,cfun_arguments)
cfun_return = coder.ceval(___)
说明
示例
coder.ceval(cfun_name) 执行 cfun_name 指定的外部 C/C++ 函数。在外部 C/C++ 源文件或库中定义 cfun_name。将外部源代码、库和头文件提供给代码生成器。
示例
coder.ceval(cfun_name,cfun_arguments) 使用参数 cfun_arguments 执行 cfun_name。cfun_arguments 是按照 cfun_name 要求的顺序排列的逗号分隔的输入参数列表。
默认情况下,只要 C/C++ 支持按值传递参数,coder.ceval 就会按值向 C/C++ 函数传递参数。要使 coder.ceval 按引用传递参数,请使用 coder.ref、coder.rref 和 coder.wref 构造。如果 C/C++ 不支持按值传递参数,例如说参数是一个数组,则 coder.ceval 将按引用传递参数。如果您不使用 coder.ref、coder.rref 或 coder.wref,则生成的代码中可能会出现参数的副本,以强制执行用于数组的 MATLAB® 语义。
示例
coder.ceval('-global',cfun_name) 执行 cfun_name,并指示 cfun_name 使用一个或多个 MATLAB 全局变量。然后,代码生成器可以产生与此全局变量用法一致的代码。
coder.ceval('-global',cfun_name,cfun_arguments) 使用参数 cfun_arguments 执行 cfun_name,并指示 cfun_name 使用一个或多个 MATLAB 全局变量。
示例
cfun_return = coder.ceval(___) 执行 cfun_name 并返回单个标量值 cfun_return,它对应于 C/C++ 函数在 return 语句中返回的值。为了与 C/C++ 保持一致,coder.ceval 只能返回标量值。它不能返回数组。可以将此选项与前面语法中的任何输入参数组合一起使用。
示例
全部折叠
调用外部 C 函数
从要从其生成 C 代码的 MATLAB 函数调用 C 函数 foo(u)。
为函数 foo 创建 C 头文件 foo.h,该函数接受两个 double 类型的输入参数,并返回 double 类型的值。
double foo(double in1, double in2);
编写 C 函数 foo.c。
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
double foo(double in1, double in2)
{
return in1 + in2;
}
编写使用 coder.ceval 调用 foo 的函数 callfoo。将源代码和头文件提供给函数中的代码生成器。
function y = callfoo %#codegen
y = 0.0;
if coder.target('MATLAB')
% Executing in MATLAB, call MATLAB equivalent of
% C function foo
y = 10 + 20;
else
% Executing in generated code, call C function foo
coder.updateBuildInfo('addSourceFiles','foo.c');
coder.cinclude('foo.h');
y = coder.ceval('foo', 10, 20);
end
end
为函数 callfoo 生成 C 库代码。codegen 函数在 codegenlibcallfoo 子文件夹中生成 C 代码。
codegen -config:lib callfoo -report
调用 C 库函数
从 MATLAB 代码中调用 C 库函数:
编写 MATLAB 函数 myabsval。
function y = myabsval(u)
%#codegen
y = abs(u);
通过使用 -args 选项指定输入参数的大小、类型和复/实性,为 myabsval 生成 C 静态库。
codegen -config:lib myabsval -args {0.0}
codegen 函数在文件夹 codegenlibmyabsval 中创建库文件 myabsval.lib 和头文件 myabsval.h。(库文件扩展名可以根据您的平台而有所不同。)它在同一个文件夹中生成函数 myabsval_initialize 和 myabsval_terminate。
编写一个 MATLAB 函数,以使用 coder.ceval 调用生成的 C 库函数。
function y = callmyabsval(y)
%#codegen
% Check the target. Do not use coder.ceval if callmyabsval is
% executing in MATLAB
if coder.target('MATLAB')
% Executing in MATLAB, call function myabsval
y = myabsval(y);
else
% add the required include statements to generated function code
coder.updateBuildInfo('addIncludePaths','$(START_DIR)codegenlibmyabsval');
coder.cinclude('myabsval_initialize.h');
coder.cinclude('myabsval.h');
coder.cinclude('myabsval_terminate.h');
% Executing in the generated code.
% Call the initialize function before calling the
% C function for the first time
coder.ceval('myabsval_initialize');
% Call the generated C library function myabsval
y = coder.ceval('myabsval',y);
% Call the terminate function after
% calling the C function for the last time
coder.ceval('myabsval_terminate');
end
生成 MEX 函数 callmyabsval_mex。在命令行中提供生成的库文件。
codegen -config:mex callmyabsval codegenlibmyabsvalmyabsval.lib -args {-2.75}
您可以使用 coder.updateBuildInfo 在函数中指定该库,而不是在命令行中提供库。使用此选项可预配置编译。将以下行添加到 else 模块中:
coder.updateBuildInfo('addLinkObjects','myabsval.lib','$(START_DIR)codegenlibmyabsval',100,true,true);
运行调用库函数 myabsval 的 MEX 函数 callmyabsval_mex。
callmyabsval_mex(-2.75)
ans =
2.7500
调用 MATLAB 函数 callmyabsval。
callmyabsval(-2.75)
ans =
2.7500
callmyabsval 函数在 MATLAB 和代码生成中的执行均展示出了预期的行为。
调用使用全局变量的 C 函数
调用修改全局变量的 C 函数时,请使用 '-global' 标志。
编写调用 C 函数 addGlobal 的 MATLAB 函数 useGlobal。使用 '-global' 标志向代码生成器指示 C 函数使用全局变量。
function y = useGlobal()
global g;
t = g;
% compare execution with/without '-global' flag
coder.ceval('-global','addGlobal');
y = t;
end
为函数 addGlobal 创建 C 头文件 addGlobal.h。
void addGlobal(void);
在文件 addGlobal.c 中编写 C 函数 addGlobal。此函数包含代码生成器在您为函数 useGlobal 生成代码时创建的头文件 useGlobal_data.h。此头文件包含 g 的全局变量声明。
#include "addGlobal.h"
#include "useGlobal_data.h"
void addGlobal(void) {
g++;
}
为 useGlobal 生成 MEX 函数。要定义代码生成器的输入,请在工作区中声明全局变量。
global g;
g = 1;
codegen useGlobal -report addGlobal.h addGlobal.c
y = useGlobal_mex();
使用 '-global' 标志时,MEX 函数产生结果 y = 1。'-global' 标志向代码生成器指示 C 函数可能修改全局变量。对于 useGlobal,代码生成器产生以下代码:
real_T useGlobal(const emlrtStack *sp)
{
real_T y;
(void)sp;
y = g;
addGlobal();
return y;
}
如果没有 '-global' 标志,MEX 函数将产生 y = 2。因为没有关于 C 函数修改 g 的指示,代码生成器假定 y 和 g 是相同的。将生成以下 C 代码:
real_T useGlobal(const emlrtStack *sp)
{
(void)sp;
addGlobal();
return g;
}