本文介绍博主自己编写的将Simulink模型生成代码的脚本。
1 问题引入
做MBD的博友都会经常将模型生成代码,然后拿去集成、编译。博主在工作中就面临大量的代码生成的工作。这样的工作毫无技术含量,一般是把模型打开,然后Ctrl+B生成代码,最后再把生成好的c文件和h文件拷贝到指定的位置,或者上传到Gitlab服务器做版本管理。
这种工作非常适合通过Matlab脚本做成自动化的,然后可以把时间解放出来去研究一些更有意义的事情。在查阅Matlab帮助文件后,发现生成代码的核心函数就一个,rtwbuild()函数。围绕着这个函数做一些前处理和后处理工作,就能做出一个简单的生成代码小工具。
2 示例代码
这一章节直接把整个生成代码的函数都贴出来,下一章会一点点的解释博主的思路。
function GenerateCode()
%% step1 生成代码准备
mScriptPath = fileparts(mfilename('fullpath'));%本文件所在文件夹路径
[ModelNameSlx,ModelPath] = uigetfile('*.slx');%通过窗口获取模型文件名和模型路径
ModelName = strrep(ModelNameSlx,'.slx','');%不带后缀的模型名
if exist([mScriptPath,'\CodeWorkspace'],'dir')%这3行:如果存在CodeWorkspace文件夹,则删除它再新建一个
rmdir([mScriptPath,'\CodeWorkspace'],'s');
end
mkdir([mScriptPath,'\CodeWorkspace']);
copyfile([ModelPath,'\',ModelNameSlx],[mScriptPath,'\CodeWorkspace\',ModelNameSlx]);%把模型拷贝到工作空间
%% step2 生成代码过程
try
cd([mScriptPath,'\CodeWorkspace']);%将工作空间设为Matlab当前文件夹
load_system(ModelName);%载入模型到计算机内存,不会显示UI界面
rtwbuild(ModelName);%生成代码核心函数
bdclose(ModelName);%关闭模型
LogText = ['Generate code for "',ModelNameSlx,'" Successfully!'];%成功的log信息
catch Me
LogText = ['Failed to generate code for "',ModelNameSlx,'"!',newline,...
'MsgID:',Me.identifier,newline,...
'MsgText:',Me.message,newline];%失败的log信息
bdclose(ModelName);%关闭模型
end
%% step3 生成代码后处理
if contains(LogText,'Successfully')%成功生成代码,则把log文件和代码拷贝到模型路径下
fid = fopen([ModelPath,'\log.txt'],'w');%写入log文件
fprintf(fid,LogText);
fclose(fid);
if exist([ModelPath,'\Code'],'dir')
rmdir([ModelPath,'\Code'],'s');
end
mkdir([ModelPath,'\Code']);
copyfile([mScriptPath,'\CodeWorkspace\',ModelName,'_ert_rtw\*.c'],[ModelPath,'\Code']);%拷贝源文件
copyfile([mScriptPath,'\CodeWorkspace\',ModelName,'_ert_rtw\*.h'],[ModelPath,'\Code']);%拷贝头文件
else
fid = fopen([ModelPath,'\log.txt'],'w');%写入log文件
fprintf(fid,LogText);
fclose(fid);
end
end
3 生成代码脚本说明
第2章节的生成代码分成3个部分:step1 生成代码准备、step2 生成代码过程、step3 生成代码后处理。
3.1 step1 生成代码准备
这一章节主要是生成代码前的准备工作。比较好理解,但是有几点值得注意:
1)uigetfile函数用于弹出文件夹选择窗口,由用户选择需要生成代码的文件夹。并且将可选择文件的类型限定为.slx文件。
2)预先删除CodeWorkspace文件夹再新建一个是为了防止上一次生成代码的临时文件影响到本次代码生成。
3.2 step2 生成代码过程
生成代码过程是指从脚本打开模型到生成代码完毕的过程。
1)try…catch的使用是为了获取生成代码错误时的信息(ME),以便后续脚本输出文件。
2)cd()函数先进入CodeWorkspace中,因为后续生成代码会生成在matlab当前文件夹中。
3)load_system只是将模型加载到内存,而不是手动双击打开模型的UI界面。
4)记得用bdclose关闭内存中的模型。
3.3 step3 生成代码后处理
生成代码结束后,会把代码存放在XXX_ert_rtw文件夹内,同时里面还有其他文件。
然后需要通过copyfile函数把C文件和H文件从中拷贝出来,集中放在模型路径下的Code文件夹中。如果勾选了ASAP2文件的生成,也要把A2L文件拷贝出来。然后再把log文件写出来。
如果判断生成代码失败,那就不要拷贝代码,只要写log文件就行。
4 脚本的改进
博主只是做一个简单的例程,演示了脚本控制模型生成代码的核心方法。根据项目实际需要,可以添枝加叶,增加更多的功能。
改进点1:加入for循环,对很多模型做批量代码生成,并将生成的代码通过脚本分类整理。
改进点2:加入if判断条件,检测模型在代码区没有对应的代码,说明它没有生成过代码,然后再为他生成代码。改进点1和2的结合可以做到提交新的模型就自动生成代码,提高生成代码效率。
改进点3:加入反馈机制,譬如代码生成成功或失败后,脚本会调用邮件系统发送结果给模型的负责人。
改进点4:加入版本管理机制,对模型生成代码后自动将代码上传到Gitlab中,并自动打上标签。
以上几点都是博主工作中摸索出来的经验,非常实用。