别再覆盖你的ert_main.c了!Simulink代码生成后与外部集成的3个关键设置
Simulink代码生成与外部集成的工程化实践指南
每次修改完ert_main.c文件后,下一次代码生成时所有心血付诸东流——这可能是许多Simulink开发者都经历过的噩梦。本文将分享一套经过实战验证的工程化方法,帮助开发者避免常见陷阱,实现生成代码与外部系统的无缝集成。
1. 理解Simulink代码生成的核心机制
Simulink的自动代码生成功能为嵌入式开发带来了革命性的效率提升,但同时也引入了一些特有的工作流程挑战。要避免文件被意外覆盖,首先需要理解其代码生成的基本逻辑。
代码生成过程中,Simulink会根据模型配置参数决定哪些文件需要重新生成。默认情况下,ert_main.c被视为"生成产物"而非"用户修改文件",因此每次生成时都会被覆盖。这种设计源于Simulink对代码一致性的保证机制——它假设所有生成文件都应完全由模型决定。
关键配置文件位置:
model.slx:主模型文件model_ert_rtw/:默认代码生成目录ert_main.c:默认生成的主程序框架model.h/model.c:核心算法实现文件
重要提示:任何需要保留的修改都应通过定制化模板或后期处理脚本实现,而非直接修改生成文件
2. 配置参数的关键设置
2.1 防止文件覆盖的配置方法
在Configuration Parameters中,有几个关键设置决定了代码生成行为:
代码生成→模板文件:
- 指定自定义的
ert_main.c模板 - 路径:Configuration Parameters → Code Generation → Templates
- 指定自定义的
代码生成→接口:
- 取消勾选"Generate an example main program"
- 这将避免生成默认的
ert_main.c
代码生成→报告:
- 启用"Create code generation report"
- 便于追踪生成文件的变化
推荐配置组合:
| 配置项 | 安全值 | 作用 |
|---|---|---|
| Generate example main | Off | 不生成默认ert_main.c |
| Custom template | 指定路径 | 使用定制化模板 |
| Override template | On | 确保使用自定义模板 |
2.2 自定义模板的实现步骤
创建不会被覆盖的自定义主程序:
- 复制原始
ert_main.c到安全目录(如/custom_templates) - 进行所需修改(如添加硬件特定初始化)
- 在模型中指定该模板路径:
set_param(gcs, 'ERTCustomFileTemplate', 'custom_templates/ert_main.c'); - 验证模板应用:
get_param(gcs, 'ERTCustomFileTemplate')
3. 工程化代码打包技术
3.1 packNGo的高级用法
packNGo命令是Simulink提供的代码打包工具,但大多数开发者只使用了其基本功能。以下是一些进阶技巧:
结构化打包命令:
load('buildInfo.mat'); packNGo(buildInfo, 'packType', 'hierarchical', ... 'fileName', 'generated_code.zip', ... 'nestedZipFiles', false);打包内容控制参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| packType | flat/hierarchical | 目录结构方式 |
| includeReport | true/false | 是否包含生成报告 |
| ignoreFileMissing | true/false | 忽略缺失文件 |
| additionalPaths | cell array | 添加额外依赖路径 |
3.2 自动化打包脚本示例
创建可复用的打包脚本package_code.m:
function package_code(modelName) % 加载构建信息 buildInfoFile = fullfile([modelName '_ert_rtw'], 'buildInfo.mat'); if ~exist(buildInfoFile, 'file') error('BuildInfo file not found. Generate code first.'); end % 设置打包选项 packOpts = struct(); packOpts.packType = 'hierarchical'; packOpts.includeReport = true; packOpts.additionalPaths = {'../drivers', '../config'}; % 执行打包 load(buildInfoFile); packNGo(buildInfo, packOpts); % 移动打包文件 movefile('*.zip', '../deliverables/'); end4. 代码路径管理的专业实践
4.1 自定义生成路径的完整方案
标准的model_ert_rtw生成路径往往不符合工程管理规范。以下是设置自定义路径的完整方法:
基础路径设置命令:
Simulink.fileGenControl('set',... 'CodeGenFolder','./generated_code',... 'CacheFolder','./cache',... 'CreateDir',true);推荐的项目目录结构:
project_root/ ├── models/ # Simulink模型文件 ├── generated_code/ # 自定义代码生成目录 │ ├── controller/ # 各模块生成代码 │ └── shared/ # 共享文件 ├── external/ # 外部代码 ├── drivers/ # 硬件驱动 └── build/ # 编译输出4.2 多模型协同开发的路径管理
当多个模型需要协同工作时,共享文件的管理尤为关键:
- 设置共享工具链目录:
set_param(gcs, 'SharedUtilsTgtDir', 'generated_code/shared'); - 为每个模型指定独立输出目录:
set_param(gcs, 'CodeGenFolder', 'generated_code/controller'); - 验证路径设置:
Simulink.fileGenControl('getConfig')
5. 外部代码集成的工程化方法
5.1 安全的接口设计原则
要实现生成代码与外部代码的安全集成,应遵循以下接口规范:
数据接口:
- 使用明确的
#include语句 - 避免直接访问模型内部数据结构
- 通过函数接口交换数据
- 使用明确的
时间接口:
- 统一时间基准
- 明确任务调度时序
- 处理多速率集成
示例接口头文件model_interface.h:
#ifndef MODEL_INTERFACE_H #define MODEL_INTERFACE_H #include "model.h" #ifdef __cplusplus extern "C" { #endif /* 初始化接口 */ void model_init(void); /* 单步执行接口 */ void model_step(float input1, float input2, float* output); /* 终止接口 */ void model_terminate(void); #ifdef __cplusplus } #endif #endif /* MODEL_INTERFACE_H */5.2 多模型集成的架构设计
当需要集成多个生成模型时,推荐采用以下架构:
分层架构:
- 底层:硬件抽象层(HAL)
- 中间层:各功能模块
- 上层:协调调度层
接口适配器模式:
// 多模型协调示例 void control_loop(void) { static bool initialized = false; if (!initialized) { model1_initialize(); model2_initialize(); initialized = true; } // 读取传感器数据 float sensor1 = read_sensor(1); float sensor2 = read_sensor(2); // 执行各模型步进 float temp_output; model1_step(sensor1, &temp_output); model2_step(temp_output, sensor2, &final_output); // 写入执行器 write_actuator(final_output); }
6. 版本控制集成策略
将Simulink代码生成纳入版本控制系统时,应考虑以下实践:
应纳入版本控制的内容:
- 原始模型文件(
.slx) - 自定义模板文件
- 关键配置脚本
- 接口定义文件
不应纳入版本控制的内容:
- 自动生成的代码(应在构建时生成)
- 临时文件
- 大型数据文件
.gitignore示例:
# Simulink生成文件 *_ert_rtw/ slprj/ *.asv *.autosave # 编译输出 build/ *.exe *.obj在实际项目中,我们发现最有效的策略是将模型文件与生成代码分开管理,通过CI/CD管道自动化整个构建过程。这既保证了可重复性,又避免了不必要的版本控制负担。
