Simulink代码生成:通过Matlab Function集成C函数

本文研究如何在Matlab Function模块中调用外部的C函数,以及一些注意点。

1 问题引入

博主以前写过一篇博客《Simulink代码生成:通过Legacy Code Tool集成C函数》,可以在Simulink模型中调用外部的C代码。在Matlab Funciton中,用m语言写着代码,突然想要调用一个现成的C文件中的函数是不是也可以呢。答案是肯定的,而且调用的方法比LCT还要更简单一些。本文会用一个简单的例子来演示在Matlab Function模块中调用外部的C函数的方法。

2 简单例程

2.1 创建C文件和头文件

首先先在当前路径下创建一个C文件和一个头文件,如下图所示:
在这里插入图片描述
C文件内容如下所示,实现了一个简单的勾股定理的计算:

//gougu.c
#include <math.h>
#include "gougu.h"

float gougu(float a, float b)
{
    
    
    float c;
    c = sqrt((pow(a,2) + pow(b,2)));
    return c;    
}

头文件内容如下所示,对函数进行外部声明:

// gougu.h
extern float gougu(float a, float b);

2.2 在Matlab Function中调用C函数

1)新建一个Simulink空白模型demo.slx,在其中加入两个输入port,一个输出port和Matlab Function:
在这里插入图片描述
这里博主把数据类型强制设为single,为了和C代码匹配,否则后面会报错。在实际使用的过程中如果调用的C代码传参类型和Matlab中不一致也会报错,这个要注意。

2)双击进入Matlab Function,改成如下m代码:
在这里插入图片描述
代码很精简,但是其中每一部分都很重要。

首先是用了coder.cinclude和coder.updateBuildInfo函数,添加了调用函数的C文件和头文件。

coder.cinclude('gougu.h');
coder.updateBuildInfo('addSourceFiles', 'gougu.c');

接下来先要对输出参数做一个初始化,这点是符合C语言的用法,最好要做,否则有可能Matlab Function无法编译通过。

y = single(0);

然后再用coder.ceval函数调用外部函数,其中的第一个参数是函数名,后面的参数依次为C函数传入的参数(将Matlab变量传参进入C函数),等号左边是C函数的返回值赋值给Matlab变量。

y = coder.ceval('gougu',u,u2);

这样就完成了这个简单的例子,可以在Simulink里仿真C函数了。

2.3 仿真及代码生成

1)将Matlab Function的输入改成常数,输出改成disp模块,可以先仿真看一下调用的效果。
在这里插入图片描述
注意到Matlab当前路径下生成了一个demo_sfun.mexw64文件,这是编译C代码的过程中产生的mex文件。因此,如果修改了C代码后,要先删掉这个mex64文件再重新运行Simulink仿真。

2)在初步验证仿真结果后,把输入输出改成Port,配置代码生成。生成的demo.c文件如下图所示。
在这里插入图片描述
图中可以看出,在生成的代码中调用了gougu()这个C函数。

在生成的demo.h文件中也会包含gougu.h这个头文件。
在这里插入图片描述
最后软件编译的时候不要忘记把外部的C文件和头文件一起加进去。

3 其他技巧和注意点

3.1 在Simuink中配置C文件和头文件

如果模型中有很多地方用了Matlab Function调用外部C文件,每个地方都写上coder.cinclude和coder.updateBuildInfo配置C文件和头文件会很繁琐。这时,可以考虑在Simuink中配置C文件和头文件,该配置会作用于所有Matlab Function。

首先将Maltab Function中的前两行注释掉:

function y = fcn(u , u2)
% coder.cinclude('gougu.h');
% coder.updateBuildInfo('addSourceFiles', 'gougu.c');

y = single(0);
y = coder.ceval('gougu',u,u2);

end

接着在Simulink配置中的Simulation Target中加上C文件和头文件:
在这里插入图片描述
然后删除当前路径下的mex64文件,再重新仿真Simulink即可。

3.2 C函数传入指针参数

在C语言中,可以传入指针的参数,利用这个指针获取计算的结果,而不是函数return的返回值。这一点也是可以用MatlabFunction做到的。

例如,将C文件和头文件修改一下:

//gougu.c
#include <math.h>
#include "gougu.h"

void gougu(float a, float b, float* c)
{
    
    
    *c = sqrt((pow(a,2) + pow(b,2)));
}
// gougu.h
extern void gougu(float a, float b ,float* c);

这样的情况下,函数返回为void类型,而返回的结果用float* c这个指针来代替。这样的话,函数体内的计算结果会存放在该指针所指向的内存空间中。

在Matlab Function中要改成如下所示:

function y = fcn(u , u2)
coder.cinclude('gougu.h');
coder.updateBuildInfo('addSourceFiles', 'gougu.c');

y = single(0);
coder.ceval('gougu',u,u2,coder.wref(y));

end

区别就在于coder.ceval函数调用外部函数时,将等号左边去掉,而是加了一个coder.wref(y)这样的参数来对应C代码中的float* c。具体用法可以参照coder.wref的帮助文档。

生成代码后,如下所示:
在这里插入图片描述
在step函数中调用gougu()函数时,第三个参数传入了Out1的地址(利用&字符取地址),从而也实现了同样的效果。

4 总结

本文研究了通过Matlab Function集成C函数的方法,做了简单的示例。在实际使用时,会遇到比demo更加复杂的情况,例如数组、结构体怎么处理,再例如C代码没办法进去调试等。因此,使用这种方法需要慎重,要进行充分的验证才行。

>>返回个人博客总目录

猜你喜欢

转载自blog.csdn.net/u013288925/article/details/123385821