Simulink代码自动生成(一)
前面介绍了MDB的设计思想并对比了它和传统的嵌入式软件开发之间的差异,现在开始使用Simulink工具演示模型的搭建和C代码的自动生成过程。
Matlab版本:R2018B
一、算法模型的搭建
搭建一个具有计数功能模型,当使能计数时,每运行一次该计数模块计数值加1,当计数值大于目标值时,相应的使能标志位置位,当初始化计数使能时,计数值被初始化为特定的输入值
模型的输入量描述:
InitVal:计数器初始化值
B_Init:为1时,计时器模块被初始化成InitVal值
B_Calc:为1时,计数器模块每运行一次自加1
模型内部变量:
CntTimer:存储当前计数值
模型输出量描述:
B_En: 使能标志位,计数值大于目标值时被置1
CurTimer:当前计数值
设置const、switch block的输出数据类型为Inherit:Inherit via back propagation(继承后项的数据类型)
二、代码的生成
1、使用数据管理,设置变量属性
数据据管理主要是对Simulink/Stateflow模型中的两类数据进行管理,一是信号,一是参数。对应于C代码,我们可以简单的把信号对应到变量上,而参数,则是不通过程序运行而发生变化的,参数的变化,一般是通过人工调节完成的,也就是参数调节,参数调节的目的是为了选择合适的参数以得到最佳的性能。
数据管理的方式,使用的是数据对象进行数据管理,这里的“对象”二字,和我们经常听到的“面向对象编程”里面的“对象”意义相同。Simulink为用户事先定义好两个包,一个是Simulink Package,一个是mpt Package。以Simulink Package为例,包里面有类,分别为Simulink.Signal和Simulink.Parameter两个类。用户可以通过这两个类定义相应的对象(Object),然后通过类提供的属性(Property)定义数据的属性。其实这两个类里面除了属性之外,还定义了方法(Method),一般情况下,我们管理数据,使用属性就够了。
点击Model Explorer图标,进入Model Explorer界面
在Base Workspace中创建信号对象,信号对象名和simulink使用的信号名一致
step1:选择Base Workspace
step2:选择创建一个信号对象,信号对象对应于C代码中的变量
step3:修改创建信号对象的名称,名称应该和模型中的信号一致
step4:设置创建信号对象的属性
注意:CntTimer使用Data store memory模块,创建对象时需要设置Dimersions、Complexity两个属性,这里CntTimer为一维实数,将维度Dimersions设置成1,Complexity设置为real实数即可
Base Workspace中创建singal对象是用来对simulink中使用的信号进行数据定义,模型中的simulink信号对应于生成的C代码中的变量。我们知道C代码中的变量需要指定数据类型,使用前需定义等等,在模型中设置这些属性就是通过sigal对象来指定生成代码的对应变量的数据类型。后面我们在生成代码的配置中会讲到如何将这些signal对象和simulink模型中的信号进行联系起来
2、代码生成配置
第一步,点击simulink中的如下图标,或者使用ctl+e快捷键,进入代码生成和模型仿真的配置界面
第二步,设置slover选项
因为计算机内只能执行离散数据类型,我们想要生成用于单片机器执行的代码,所以这里的解算器选择固定步长,解算器选择离散
fixed-step size:步长的时间,simulink仿真时使用,可根据控制器时钟频率进行设置
第三步,设置Diagnostics选项的Data Validity项容
设置其中对signal信号的解析,选择explicit and implicit项让解析时将simulink中的siganl信号和workspace中创建的同名的signal对象进行联系起来,siganl对象即前面我们介绍的在Model Explore中创建的内容。若这里不进行选择,也就意味着模型的输入输出信号没进行定标,使用默认数据类型生成代码,生成的代码使用结构体来描述输入输出,这样的代码可用性不高。
注:也可以鼠标右键单击signal的信号线,选择properties,勾选“signal name must resolve to simulink siganl object”来进行signal和signal同名对象直接的捆绑。这种方式需要一个个的点击信号线进行设置,没有上述直接选择explicit and implicit项便捷
第四步, 设置Code generation选项
选择系统目标文件为ert.tlc,用于生成嵌入式代码,ert针对嵌入式期间对生成的代码进行了相应的优化处理
勾选Generater code only选项,选择仅生成代码
第五步,设置Code generation选项中的optimization项
这个选项内包含对生成代码的优化,可设置内容比较多,这里只设置了一小部分
remove root level I/O zero initialization:勾选上,在生成代码的初始化函数中不进行对输出变量进行初始化
remove root internal data zero initialization:勾选上,在生成代码的初始化函数中不进行对内部data store memory变量进行初始化
第六步,设置Code generation选项中的Interface项
修改生成代码依赖函数库的存放位置(一般使用定点数计算和查表时会生成相应库函数),取消浮点数、复数的支持,取消terminate函数生成
remove error status field in real-time model data structure:勾选上,不提供用于错误状态的处理接口
第七部,设置Code generation选项中的Templates项
取消勾选generate an example main porgram,设值生成代码时不生成一个main函数的调用例子
也可以修改code templates中的生成代码的模板,自定义生成代码中变量、函数、宏的排放顺序
第八步,点击Apply,执行ctrl+b编译模块,生成代码
配置完成,生成代码,可以看出生成的代码和我们的模型实现的逻辑一致,并且生成的代码还是比较精简的,可读性也很强。
值得注意的是在生成代码的配置中还有其他部分配置可以设置,这里我把这些选项保持默认内容,当然你在使用时可以根据根据自己的需求设置其他选项,如可以设置生成的代码中包含那些头文件,设置编译工具链等等,这里就不一一的介绍了