DSP

MATLAB/Simulink自动代码生成(一)

2019-07-13 18:29发布

        Simulink自带了种类繁多、功能强大的模块库,在基于模型设计的开发流程下,Simulink不仅通过仿真可以进行早期设计的验证,还可以生成C/C++、PLC等代码直接应用于PC、MCU、DSP等平台。在嵌入式软件开发中发挥着重要的作用,本文以Simulink模型生成嵌入式C代码为例分析代码生成的原理及应用。 一、根据需求建立系统框图      低通滤波:又叫一阶惯性滤波,或一阶低通滤波,是使用软件编程实现普通硬件RC低通滤波器的功能。适用于单个信号有高频干扰信号的情形。     一阶低通滤波的算法公式为:     式中:是滤波系数;是本次采样值;是上次滤波输出值;是本次滤波输出值。 根据以上计算公式可以建立如下图所示模型: 二、代码生成  SimulinkSimulink Coder工具箱提供了将模型转换为可优化的嵌入式C代码的功能。  Configuration Parameter中集中管理着模型的代码生成方法、格式等约束条件。为了生成嵌入式代码,至少需要配置三部分:模型的解算器solver,模型的系统目标文件(如ert. tlc或其他自定义的嵌入式系统目标文件),硬件实现规定(Hardware Implenmatation)。        按下Ctrl+E打开模型的Configuration Parameter对话框,如下图所示:   2.1 solver页面的设置           solver页面如下图所示:  解算器类型必须选择固定点解算器。固定点solver中提供了多种算法,此模型由于没有连续状态,可以选择discrete方法。步长默认auto在简单的通用嵌入式代码生成过程中此参数没有实际作用,可以采用默认或设置0.01s。而在针对目标芯片定制的代码生成过程中,硬件驱动具箱往往会将步长step size作为其外设或内核中定时器的中断周期,使得生成的算法代码在硬件芯片中以同样的时间间隔执行。并且由于解算器步长为整个模型提供了一个基础采样频率,故被称为基采样率(base-rate)。 2.2 Optimization页面的设置 当模型中使用参数变量,如Gain模块的增益值,在生成代码时,如果希望使用该参数的值直接展开到代码中就需要设置参数内联选项,如下图所示框中选项:          Inline parameters选项决定是否将参数内联到代码中去。勾选此选项后,代码生成时模型的参数将以常数方式直接生成到代码逻辑中,不再以一个参数变量的形式生成。当模型中的参数需要作为实时可调的参数生成到代码中时,不勾选Inline parameter,参数将作为变量生成;如果不需要实时调整参数,可以选择节省存储空间的方式,勾选Inline parameter将参数以数值常数的形式生成到代码中。   2.3 Hardware Implenmatation页面的设置       Hardware Implenmatation选项是规定目标硬件规格的选项。在这个选项卡中可以配置芯片的厂商和类型,设置芯片的字长、字节顺序等。学习使用通用嵌入式芯片为目标的代码生成流程及原理,选择32位嵌入式处理器作为芯片类型,如下图所示框中部分:     另外一个关键的设置选项是控制整个代码生成过程的系统目标文件System Target Fileert. tlc文件是Embedded Coder提供的能够生成专门用于嵌入式系统C代码的系统目标文件。在Code Generation页面中,单击下图所示右上角Browse按钮可以弹出对话框以选择系统目标文件: 在选择框中选择ert. tlc之后Code Generation标签页下面的子标签也会发生变化,提供更多的功能选项标签,如下图所示,方框内为新增子标签: (1)Report子标签能够打开设置关于生成代码报告的页面,可以选择是否创建HTML格式的代码生成报告,并通过勾选框选择是否在模型编译结束后自动打开。其对话框页面如下图7所示:         Metrics 组的 Static code metrics 选择框,勾选时将会在代码生成报告中包含静态代码的参数指标。      推荐勾选 Create Code Generation Report Open report automatically 两个选项,模型生成代码完毕后会自动弹出报告列表,而不需要到文件夹中逐一将源文件手动查找并打开。  (2)Comments子标签中包含对生成代码中注释内容的配置,其对话框如下图所示:         Include comments选项的勾选决定是否在生成代码中添加Simulink自带的注释。
      启动此选项后Auto Generated comments组及Custom comments组的选项便被使能,我们可以根据需要选择希望生成的注释内容。  
 
        推荐启动 Include comments 选项并勾选 Simulink block Stateflow object comments 选项以生成注释,注释中带有可以从代码跳转到对应模型的超链接,方便追溯模块与代码的对应关系。     (3)Symbol子标签页面用于设置ert.tlc—族系统目标文件控制下的代码生成不变定义规则,如下图所示:     这些符号包括数据变量和数据类型定义、常量宏、子系统方法、模块的输出变量、局部临时变量及命名的最长字符数等。 Identifier format control 参数组里默认使用标示符 $R$N$M$TEmbedded Coder 内部使用的标示符,如下图所示:   这些标示符的具体意义如下表所列:    通过上表各种标示符的不同组合,即可规定生成代码中各部分(变量、常量、函数名、结构 体及对象)的名称的生成规则。            Simulink提供的这些标示符生成的变量名虽然可读性不强,但是不会引起代码编译错误。推荐使用默认设置,不要为了提高生成代码可读性轻易进行修改,以免造成不必要的错误。以后会学习更好更安全的提高代码可读性的优化方法。     (4)Custom Code子标签页面主要用于添加用户自定义的或者编译模型时必需的源文件、头文件、文件夹或者库文件等,其页面如下图所示:            (5)Interface 子标签页面中包含3组参数Software EnvironmentCode Interface、Data Exchange其对话框如下图所示:  Software Envirionment 组的参数中提供 CPL(Code Placement Library)的选择,CPL 中 定义一个表,根据表格将Simulink模块与所对应目标语言的数学函数及操作函数库挂接,以便从模型生成代码。Embedded Coder提供默认的CPL Support参数组由7个选择框构成,如下:    每个选择框代表一种嵌人式编码器对代码生成的支持功能,其中一些功能是需要Simulink供的头文件来支持才能编译为目标文件的,这些头文件一部分存储在路径为MATLABroot simulinkinclude的文件夹中,一部分是在模型生成代码过程中自动生成的(rt开头的头文)。具体参考下表:  Code Interface与Data Exchange参数组用来配置生成代码的接口及数据记录的方式,如无特殊要求建议使用默认配置。 (6)Code Style子标签页面提供了一些关于生成代码风格的选择框选项,如if else分支的完整性确保,if else与switch case语句的选用,生成括号的频度,是否保留函数声明中extern关键字等,如下所示:
   (7)Template子标签页面内嵌入式编码器提供了一组默认的代码生成模版,如下图所示:        ert_code_template.cgt 中使用TLC变量方式规定了文件生成的顺序及添加模型信息注释的位置。模型生成的源文件、头文件及全局数据存储和外部方法声明文件的生成可以使用统一模板。          ert_code_template.cgt中主要规定了代码段的顺序,section包含了源文件从注释到变量再到函数体各种分 段,如下图所示:      顺序从上到下,依次为:文件 说明的注释(File Banner)、头文件包含(Includes)、宏定义 (Defines)、数据结构类型的定义(Types)和枚举类型的定义(Enum)、各种变量的定义(Definitions),以及函数体的声明(Declarations)和闲数体定义(Functions)。我们在相邻的段中插人自定义内容,但是不要打乱既存段的对顺序。    (8)Code Placetnem子标签提供的选项将影响生成代码的文件组织方式和数据存储方式及头文件包含的分隔符选择等,其页面如下图所示:   常用的选项是File packaging format,表示生成文件的组织方式,对应的生成文件个数不同,内容紧凑程度也不同。具体如下表所列:     省去的只是文件个数,其内容被合并到了其他文件中,内容的转移如下表所列:  我们可以使用默认设置,如果希望减少生成代码列表中文件的个数,可以考虑使用Compact 的组织方式 (9)Data Type Replacement子标签默认情况下仅提供一个选择框选项:      勾选之后则弹出3列数据类型类表,分别是Simulink Name,Code Generation Name Replacement勾选 Replace data选项之后界面如下图所示: 前两列按照数据类型的对应关系给出了每种数据类型在Simulink和嵌入式编码器生成代码中的类型名,第3列则供用户设置,填人自定义的类型名之后,生成代码时将使用自定义的类型名替换Code Generation Name。 用户填人的自定义类型名不仅是一个别名字符串,还必须在Base Workspace中定义其作为Simulink .AliasType类型对象才可以。 如定义U16数据别名对象来替换uint16_T这个内部类型。第3列的edit框不必全部填入自定义类型名,可以根据应用场合选择部分或全部来使用。并且可以使用同一个数据类型名替代多个内建数据类型,如使用U8同时替换uint8_T和Boolean_T类型。 (10)  Memory section子标签中设置函数、常数、输人/输出、数据和参数的存储段。如无须生成pragma等存储段指定命令则此子标签页面下使用默认设置即可。   Code Generation标签页下提供的子标签页功能说明均已完成。   2.3 启动编译  当这些配置好以后,我们就可以启动模型编译: 或者按下ctrl+B,模型左下角从ready显示为building:   片刻后弹出Code Generation Report界面,如下图所示:     与模型名相同的.c若模型配置无误,则文件中包含model_step()函数,这里的代码表示模型所搭建的逻辑:    
  1. rtb_Delay += (rtU.In1 - rtb_Delay) * rtU.In2;
  2. rtY.Out1 = rtb_Delay;
未经优化的代码可读性较差,但是从四则运算关系中及结构体的成员名上可以看出每一个变量所代表的意义。   除此之外,生成的代码还提供了 Code to Model追踪功能,单击下图方框中的超链接,可以直接跳转到模型中对应的模块,该模块或子系统将会以蓝 {MOD}显示。如下所示:     我们单击来演示这个超链接,这个追踪功能提示用户模型与代码的对应关系,即直接跳转到模型中对应的模块,该模块或子系统将会以蓝 {MOD}显示。如下所示: 转发自:https://blog.csdn.net/weixin_41695564/article/details/80751543