(控制)把SIMULINK转成C语言并在VS中调用

本文分享如何利用MATLAB的SIMULINK工具将PID控制器模型转换为C语言,包括设置模型参数、生成C代码、导入VS项目及处理依赖问题。适合初学者和需要在VS中集成MATLAB控制的读者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

最近发现SIMULINK其实是可以转成C语言的(再次感叹MATLAB的神奇),这个功能大大地减少了我的工作量。由于时间不允许,在转换过程中我没有对这里的一些细节进行研究,而且网络上关于这个方法把这个方法的文章不多(主要是本人懒得看英文资料……),所以把它写成博客,既方便以后回来看也希望能和大家交流。

本人编程基础差且没有对这个方法进行深究,这篇文章仅作为本人笔记和交流知识的作用,文中很可能有大量错误,也希望大家能指出

平台

VS 2013
MATLAB 2015a
Windows 10
方法
下面以建立一个PID控制器为例说明这个方法的过程。

首先在SIMULINK中搭建一个模型,注意给模型添加起码一个输入端口和一个输出端口。在这里,因为我需要搭一个PID控制器,所以另外分别加入P、I、D三个输入端口,最终得到的模型如下图所示,注意这里端口的命名,转成C代码后输入输出点的命名将和他们相对应。因为我最后是用这个控制器来控制云台摄像头的转动的,其实这里应该设计成离散控制系统,由于本人偷懒,随便做了个连续的PID控制器就用了起来,最后调整好PID后效果也还行,就不管了。
PID控制器
在这里插入图片描述

然后在当前的模型窗口中依次打开Simulation->Model Configuration Parametersta弹出以下窗口。
设置
在这里插入图片描述

一定要把Stop time设为inf,把Solver options下的Type设为Fixed-step编译才能正常进行,否则会报错。这里设置的好像是系统状态更新的方式, 我没有仔细研究,如果大家希望详细了解这些选项的意思可以把鼠标放在相关选项上然后右击,会出来一个What’s this选项,点进去就可以(感叹MATLAB的友好度)。

点击右侧窗口的Code Generation按键可以选择生成C代码(默认)或者C++代码,以及选定IDE。

另外对于要在单片机中实现控制的同学可以在右侧窗口点击Hardware Implementation,会出来一个选择设备的下拉选框,这个可能需要设置一下(没有经过测试),但是因为本文只要在VS中实现控制,所以就不需要选了。

设置好之后关闭Configuration窗口,依次点击Code->C/C++ Code->Build Model。此时SIMULINK已经开始编译了,等到MATLAB的Command Window窗口进入就绪状态,这时就已经编译成功了。打开MATLAB当前的工作目录你会发现多了一个文件夹,文件夹名称为“你的模型名称”+_grt_rtw。例如我这里的模型为PIDController.slx,那么生成的文件夹名称为PIDController_grt_rtw。为了便于说明,MATLAB自动生成的文件和函数等的命名一并以这个例子为例,具体情况请根据相应的模型名替换。在资源管理器中打开这个文件夹你会发现里面有一个批处理文件,虽然不知道有什么用,我一般都会运行一下(-.- !)。

下一步就是把这些文件导入到VS里面去了。先建立一个VS的项目。可以选择把这一整个文件夹的文件拷进VS的工程文件里,或者在VS工程里添加这个文件夹作为头文件目录和源码目录。在头文件中右击,点击添加->现有项…,然后把PIDController_grt_rtw里面所有的头文件和源文件添加进工程。

在这些文件中我们只要关心PIDController.h这个文件就行了。在工程的入口函数所在的源文件处加上

include “PIDController.h”

这一行。接下来Build这个工程,你会发现有很多找不到文件的错误,这是因为PIDController_grt_rtw这个文件夹中的源码都引用了MATLAB安装目录底下的一些源码。因为找不到更好的方法,我只能按照报错的源头一个一个文件地从MATLAB安装目录中找出来并且添加进工程。我这个应该是很笨的方法,如果有简单的方法请告诉我。

把所有应该添加的文件都添加进来之后就可以在程序中调用这个PID控制器了。阅读PIDController.h这个文件你会发现有以下代码

//...
/* External inputs (root inport signals with auto storage) */
extern ExtU_PIDController_T PIDController_U;

/* External outputs (root outports fed by signals with auto storage) */
extern ExtY_PIDController_T PIDController_Y;
/* Model entry point functions */
extern void PIDController_initialize(void);
extern void PIDController_step(void);
extern void PIDController_terminate(void);

从注释我们可以看出这PIDController_U和PIDController_Y分别是模型的输入和输出;PIDController_initialize(void)、PIDController_step(void)和PIDController_terminate(void)三个函数是模型的入口函数。

进一步研究PIDController_U和PIDController_Y的定义,我们可以发现它们其实是两个结构体,分别对应着模型中的输入端口和输出端口。

/* External inputs (root inport signals with auto storage) */
typedef struct {
  real_T In1;                          /* '<Root>/In1' */
  real_T I;                            /* '<Root>/I' */
  real_T D;                            /* '<Root>/D' */
  real_T P;                            /* '<Root>/P' */
} ExtU_PIDController_T;
/* External outputs (root outports fed by signals with auto storage) */
typedef struct {
  real_T Out1;                         /* '<Root>/Out1' */
} ExtY_PIDController_T;

PIDController_initialize(void)、PIDController_step(void)和PIDController_terminate(void)三个函数的功能分别如下:

  • PIDController_initialize(void): 初始化模型
  • PIDController_step(void):对模型的输出端口进行一次更新,有点像PLC中的一个周期
  • PIDController_terminate(void):结束模型

实际使用如下

PIDController_initialize();
PIDController_U.I = 0.0193;
PIDController_U.P = 1.625;
PIDController_U.D = 2.67;
while (!quit_flag){

    //TODO 检测被控量,更新模型的输入newInput

    PIDController_U.In1 = newInput;
    PIDController_step();
    newOutput = PIDController_Y.Out1;

    //TODO 把新的输出newOutput作为被控对象的输入

}
PIDController_terminate(void);
### 在Simulink中集成C语言函数 #### 使用S-Function模块嵌入自定义C代码 为了在Simulink环境中利用已有的C语言函数,通常采用S-Function机制。S-function允许用户创建自定义的动态系统模型组件,支持多种编程语言,包括C/C++。当使用C语言开发时,可以通过编写特定格式的接口函数来定义系统的输入输出行为以及状态更新逻辑。 对于希望直接调用外部C库的情况,应当构建一个遵循S-function API规范的封装层[^2]: ```c // 定义 S 函数入口点 #define S_FUNCTION_NAME my_custom_function #define S_FUNCTION_LEVEL 2 #include "simstruc.h" void mdlInitializeSizes(SimStruct *S){ // 初始化参数... } void mdlOutputs(SimStruct *S, int_T tid){ real_T* y = ssGetOutputPortSignal(S,0); // 调用 C 库中的功能函数计算输出值 } ``` 上述模板展示了最基本的框架结构;实际应用过程中还需要根据具体需求补充更多细节处理部分,例如初始化设置、离散/连续时间管理等。 #### 创建MATLAB MEX文件作为中介桥梁 另一种方式则是借助于MATLAB提供的MEX技术——这是一种能够让Matlab/Simulink执行由其他高级语言(如C/C++)编写的子程序的技术手段。这种方式特别适合那些已经具备成熟算法实现但又期望快速验证效果的情形下使用[^4]。 首先,在本地计算机上准备好待引入的目标C源码片段之后,按照官方文档指导完成相应平台下的编译链接操作,从而得到可被即时加载使用的`.mexw64`二进制扩展件。接着便可在脚本里通过简单的命令行指令来进行交互测试或是进一步组装成更复杂的控制流图样。 最后一步就是把生成好的Mex对象注册给目标Simulink项目里的某个合适位置处,使之成为整个仿线程的一部分参与运算流程之中去。 #### 利用Embedded Coder工具自动化转换过程 如果手头拥有一份完整的C工程且想要尽可能减少手动干预程度的话,则不妨考虑尝试MathWorks推出的专门用于辅助工程师们开展此类工作的Embedded Coder附加包服务[^3]。该软件能自动解析指定路径内的所有关联资源文件,识别出潜在可用作插件式的单元体,进而导出适配当前工作环境的标准构件供后续选用部署。 综上所述,无论是基于传统意义上的S-functions还是现代化的跨平台互操作解决方案,亦或者是高度定制化的编码迁移策略,都能有效地帮助开发者实现在Simulink内部无缝接入第三方C级API的目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值