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

本文介绍如何利用MATLAB的Simulink将一个PID控制器模型转换为C语言代码,并在Visual Studio 2013中进行编译及应用。通过详细步骤说明,帮助读者快速掌握Simulink到C代码的转换过程。

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

背景

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

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

平台

  1. VS 2013
  2. MATLAB 2015a
  3. 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 语言代码 Simulink 是一种强大的建模工具,能够自动生成多种目标平台所需的代码。以下是关于如何通过 Simulink 导出 C 语言代码的具体说明。 #### 使用 Simulink 自动生成 C 代码 Simulink 提供了一种便捷的方式来自动生成适用于不同硬件平台的 C 代码。这种方法降低了手动编码复杂逻辑的需求,从而减少了开发时间和错误率[^1]。具体来说: - **模型准备阶段** 需要先构建好完整的 Simulink 模型验证其功能正确无误。这一步骤至关重要,因为任何未解决的功能缺陷都会直接影响最终生成的代码质量。 - **配置参数设置** 打开 Configuration Parameters 对话框(可通过 Simulation 菜单下的 Model Configuration Parameters 访问),进入 Code Generation 页面完成必要的选项设定。这些选项可能涉及优化级别、目标处理器架构以及实时操作系统支持等内容。 - **启动代码生成功能** 完成上述准备工作之后,可以通过点击菜单栏上的 Build Model 或者直接按 Ctrl+B 来触发代码生成过程。此操作会依据所选模板自动创建对应的源文件(.c 和 .h 文件)。 #### 动态链接库的应用场景 除了基本的 C 文件导出外,有时还需要进一步将生成的结果封装成为共享对象(shared object),即 `.so` 文件形式以便于其他应用程序加载使用。例如,在 Linux 平台下如果希望把由 Simulink 得来的算法作为服务提供给 Python 等高级脚本调用,则需经历如下额外步骤[^2]: 1. 将生成好的动态库拷贝至标准路径 `/usr/lib` 下面; 2. 创建一个新的宿主应用来负责实际业务流程控制,比如读取外部数据源、传递参数给内部计算模块再收集返回值加以后续分析处理等等。 #### 修改默认入口点以满足特定需求 对于某些特殊场合而言,默认提供的 main 函数未必完全契合项目预期效果。此时可以考虑调整原始 ERT(Embedded Real-Time)框架所提供的样板代码 `ert_main.cpp` 。通过对其中的关键部分如 `rt_OneStep()` 进行定制化改造,允许开发者灵活定义每次迭代期间的行为模式——无论是存储中间状态还是重新指定新一批输入变量皆可轻松达成目的[^3]。 ```cpp // 示例:修改后的 rt_OneStep() 实现方式之一 void myCustomOneStepFunction(SimStruct *S){ // 原始仿真步执行动作保持不变... original_RtOneStepFuncitonCallHere(); // 新增特性加入此处,假设我们要记录当前时刻所有输出端口数值到日志当中去. logCurrentOutputsToFile(getAllOutputValues()); } ``` 以上就是有关利用 MathWorks 的旗舰产品 MATLAB/Simulink 工具链来进行高效快速原型设计的同时还能兼顾后期移植维护便利性的几个核心要点概述。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值