生成独立的可执行程序部署到目标硬件
默认情况下,嵌入式编码器®软件生成独立的可执行程序,不需要外部实时执行或操作系统。一个独立的程序需要适应目标最小修改硬件。独立的程序架构支持执行模型与单个或多个样本率。金宝app
生成一个独立的程序
生成一个独立的程序:
选择模型配置参数主程序生成一个例子。这使目标操作系统菜单。
从目标操作系统菜单中,选择
BareBoardExample
。生成的代码。
不同的代码生成多重速率的模型依赖于这些因素:
模型执行单一任务是否或多任务模式。
是否可重用的代码生成。
这些因素会影响生成的代码中使用的调度算法,并在某些情况下影响模型入口点的API函数。下面的章节将讨论这些变体。
独立的程序组件
一个独立的核心程序主循环。在每次迭代中,主循环执行一个背景或零任务和检查终止条件。
主循环是周期性地打断了计时器。这个函数rt_OneStep
要么是安装定时器中断服务程序(ISR),或从一个计时器ISR在每个时钟的步骤。
执行驱动程序,rt_OneStep
,调用序列
功能。的操作模型
_steprt_OneStep
取决于不同的单频、多频生成模型。在单频模型中,rt_OneStep
简单地调用
函数。在多重速率的模型中,模型
_steprt_OneStep
重视和时间表执行块根据利率他们运行。
主程序
操作的概述
下面的伪代码显示了主程序的执行。
main(){初始化(包括安装rt_OneStep作为一个实时时钟中断服务例程)初始化并开始定时器硬件启用中断(没有错误)和(时间<最后一次)后台任务EndWhile禁用中断(从执行禁用rt_OneStep)完成任何后台任务关闭}
伪代码是一个利用设计程序来驱动你的模型。主程序部分实现这个设计。你必须修改它根据你的规格。
修改主程序的指导方针
本节描述最小修改你应该在您的生产版本的主程序模块来实现利用程序。
调用
。模型
_initialize初始化有针对性的数据结构和硬件,比如adc和dac。
安装
rt_OneStep
作为一个计时器ISR。初始化定时器硬件。
启用定时器中断并启动计时器。
请注意
rtModel
不是一个有效的状态直到
被称为。定时器中断服务应该才开始模型
_initialize
被称为。模型
_initialize可选地,在主循环中插入后台任务调用。
在主循环的终止(如果适用):
禁用定时器中断。
归零法dac等进行有针对性的清理。
检测和处理错误。请注意,即使你的程序被设计为运行下去,你可能需要处理严重的错误条件,如定时器中断超支。
您可以使用宏
rtmGetErrorStatus
和rtmSetErrorStatus
检测和信号错误。
rt_OneStep和调度方面的考虑
操作的概述
的操作rt_OneStep
取决于
是否你的模型是单频或多重速率的。在单频模型中,示例中的所有块模型,模型的固定步长,都是一样的。一个模型的样本时间和步长不符合这些条件称为多重速率的。
你的模型的解算器模式(
SingleTasking
与多任务处理
)
嵌入式实时系统的目标文件允许解算器模式总结了单频、多频模型允许解算器模式。请注意,对于单频模型,SingleTasking
解算器模式是允许的。
嵌入式实时系统的目标文件允许解算器模式
模式 | 单频 | 多重速率的 |
---|---|---|
|
允许 |
允许 |
|
不允许 |
允许 |
|
允许 (默认为 |
允许 (默认为 |
生成的代码rt_OneStep
(和相关的计时数据结构和支持功能)是根据利率的数量模型,解算器模式。金宝app下面的章节将讨论每一个可能的情况下。
单频单任务操作
唯一有效的为单频模型解算器模式SingleTasking
。这样的模型运行在“单频”操作。
下面的伪代码显示的设计rt_OneStep
在单频程序。
rt_OneStep(){检查中断溢出或其他错误使“rt_OneStep”(计时器)中断Model_Step()——时间步结合输出日志、更新}
单一税率的情况下,生成的
函数是模型
_step
无效模型_step(空白)
单频rt_OneStep
设计执行
在一个时钟周期。执行这个时间约束,模型
_steprt_OneStep
维护和检查计时器溢出国旗。条目,定时器中断被禁用,直到被国旗和其他错误条件检查。如果被国旗是明确的,rt_OneStep
设置标志,并继续进行启用定时器中断。
被国旗只成功回来了
。因此,如果模型
_steprt_OneStep
是重新中断之前完成
,通过被检测到reinterruption标志。模型
_step
Reinterruption的rt_OneStep
一个错误条件的计时器。如果检测到这种情况rt_OneStep
信号错误并立即返回。(注意,你可以改变这种行为,如果你想处理条件不同。)
注意的设计rt_OneStep
假设在禁用中断rt_OneStep
被称为。rt_OneStep
应该noninterruptible直到中断溢出标志已经检查。
多重速率的多任务操作
在多重速率的多任务系统中,代码生成使用优先,抢先多任务处理计划执行不同的样本率模型中。
下面的伪代码显示的设计rt_OneStep
在一个多重速率的多任务处理程序。
rt_OneStep(){检查基础概率中断泛滥使“rt_OneStep”中断利率确定哪些需要运行这个时间步Model_Step0()——运行基础概率为N = 1:时间步代码NumTasks-1——迭代sub-rate任务如果(sub-rate任务N计划)检查sub-rate打断Model_Step泛滥N()——运行sub-rate时间步代码EndIf EndFor}
任务标识符。块的执行有不同的抽样率是分解成任务。每一块执行在一个给定的采样率是分配一个任务标识符(tid
),将它与一个任务执行速度。哪里有NumTasks
任务系统中,任务标识符的范围是0 . .NumTasks
1。
基础概率和Subrate任务的优先级。任务优先级,按照降序排列。的基础概率最快的速度运行的任务是任务系统(硬件时钟频率)。基础概率任务优先级最高(tid
0)。下一个任务(最快tid
1)第二优先级最高,等等最慢,最低优先级的任务(tid
NumTasks
1)。
较慢的任务,在基准利率的倍数,被称为subrate任务。
率分组和评估具体model_step功能。在单频模型中,块的输出计算执行在一个函数,
。多任务模型,多重速率的代码生成器试图使用一个不同的策略。这种策略被称为率分组。率分组生成单独的模型
_step
功能基本利率任务和每个subrate任务模型。这些函数的函数命名约定模型
_step
模型_stepN
在哪里
是一个任务标识符。例如,对于一个名叫模型N
my_model
有三个利率,生成以下功能:
空白my_model_step0(无效);空白my_model_step1(无效);空白my_model_step2(无效);
每一个
函数执行模块共享模型
_stepN
tid
;换句话说,在任务执行的代码块N
分为相关吗N
函数。模型
_stepN
调度model_stepN执行。在每个时钟周期,rt_OneStep
维护调度计数器,事件标志为每个subrate任务。计数器实现taskCounter
数组索引上tid
。事件的旗帜被实现为数组索引tid
。
调度计数器和任务国旗sub-rates维护rt_OneStep
。调度计数器基本上是时钟频率分隔器,计算样本时期与每个sub-rate相关联的任务。一对任务交换数据维护国旗的交互速度越快。任务交互标志表明,快速和缓慢的计划运行任务。
事件标志指示是否一个给定的任务计划执行。rt_OneStep
维护事件标志反驳说,基于一个任务是在主程序模块维护的代码模型。当计数器显示任务的示例时期已经过去,这一任务的主要代码集事件标志。
在每次调用,rt_OneStep
更新其基础概率任务调度数据结构和步骤(rt_OneStep
调用
因为基础概率任务必须执行在每个时钟的步骤)。然后,模型
_step0rt_OneStep
遍历调度旗帜tid
秩序,无条件地调用
对于任何标志设置的任务。任务优先级的顺序执行。模型
_stepN
抢占。注意的设计rt_OneStep
假设在禁用中断rt_OneStep
被称为。rt_OneStep
应该noninterruptible直到基础概率中断溢出标志已经检查(见上面的伪代码)。
使用的事件标志数组和循环变量rt_OneStep
被存储为本地(栈)变量。因此,rt_OneStep
是可重入的。如果rt_OneStep
是重新中断,高优先级的任务抢占低优先级任务。从中断返回时,低优先级的任务恢复事先安排的秩序中。
被检测。多重速率的rt_OneStep
还维护一个数组定时器溢出的旗帜。rt_OneStep
检测到定时器溢出时,每个任务,与单频相同的逻辑rt_OneStep
。
请注意
如果你开发了多频S-functions,或者如果你使用一个定制的静态主程序模块,明白了率分组遵从性和兼容性问题如何适应你的代码信息分组的兼容性。这种适应允许多重速率的,多任务模型生成更高效的代码。
多重速率的单任务操作
在一个多重速率的单一任务计划,根据定义,样例次模型必须是整数模型的固定大小的倍数。
在多重速率的单一任务程序块执行在不同的利率,但在相同的任务标识符。的操作rt_OneStep
在这种情况下,是一个多重速率的多任务操作的简化版本。如何分组是不习惯的。唯一的任务是基础概率的任务。因此,只有一个
生成函数:模型
_step
无效模型_step(空白)
在每个时钟周期,rt_OneStep
检查被国旗和调用
。一个多重速率的单一任务的调度函数程序模型
_steprate_scheduler
(而不是rate_monotonic_scheduler
)。调度程序维护调度计数器在每个时钟周期。有一个计数器中每一个采样率模型。计数器实现的内部(tid)索引数组时机
内部结构rtModel
。
计数器的时钟频率分隔器,计算样本时期与每个subrate相关联的任务。当计数器显示样本时期对于一个给定的速度运行,rate_scheduler
清理柜台。这种情况表明,模块运行速度,应该在下一个调用执行
负责检查计数器。模型
_step
修改rt_OneStep指南
rt_OneStep
不需要大量的修改。唯一需要修改后再允许中断泛滥旗帜和错误条件检查。如果适用,你也应该
保存和恢复你的FPU上下文在入口和出口
rt_OneStep
。集模型输入与基准利率之前调用
。模型
_step0得到模型输出与调用后的基准利率
。模型
_step0请注意
如果你修改
rt_OneStep
读一个值从一个连续的输出端口在每个基础概率模型步骤,参见下面有关警戒指南。在多重速率的多任务模型,将模型输入与subrates之前调用
在subrate循环。模型
_stepN
在多重速率的多任务模型,得到模型输出与subrates后调用
在subrate循环。模型
_stepN
注释rt_OneStep
表明添加代码的地方。
在多重速率的rt_OneStep
通过展开,可以提高性能为
和而
循环。
此外,你可以选择修改溢出行为错误恢复完成后继续执行。
也观察这些警示指南:
你不应该修改的方式计数器、事件标志,或其他时间数据结构
rt_OneStep
,或者在函数调用rt_OneStep
。的rt_OneStep
数据结构(包括时间rtModel
)和逻辑操作生成的关键程序。如果你有定制的主程序模块读取模型输出每个基础概率模型步骤后,请注意,选择模型配置参数金宝app支持:连续时间和单输出/更新功能在一起会导致输出值读取
主要
连续输出端口中相应的输出值略有不同模式的记录数据。这是因为,虽然记录数据的快照输出步骤,主要时候输出读取主要
基础概率模型后一步可能反映了干预较小的时间步长。消除这种差异,要么单独生成的输出和更新功能(清除单输出/更新功能参数)或放置一个零块之前连续输出端口。可以观察之间的不匹配的结果模拟和记录垫文件中生成的代码的结果如果不设置模型输入阶跃函数在每次调用模型。在主程序生成的例子,下面的评论显示的位置设置输入和步进模型与代码:
/ *这里集模型输入* / / * * /步骤模型
如果你的模型适用于信号复用和您正在使用
MatFileLogging
比较仿真结果对生成的代码,修改rt_OneStep
写模型输入在每个时间步是由这些评论。或者,你可以选择银或公益诉讼的方法核查。
静态主程序模块
概述
的策略部署生成的代码是使用模型配置参数主程序生成一个例子的选择生成主程序模块(一个例子ert_main.c
或. cpp
)。有关更多信息,请参见生成一个独立的程序。
或者,您可以清除主程序生成一个例子参数和使用生成的静态主程序模块作为一个例子或开发嵌入式应用程序的模板。静态MathWorks提供的主程序模块®包括:
——金宝app支持matlabroot
/ rtw / c / src /共同/rt_main.c那种一次性的功能
设置模型配置参数代码接口包装。
——金宝app支持matlabroot
/ rtw / c / src /共同/rt_malloc_main.c可重用的功能
设置参数代码接口包装。您必须选择模型配置参数使用动态内存分配模型初始化并设置参数通过根级I / O来模型数据结构的一部分
。
——金宝app支持matlabroot
/ rtw / c / src /共同/rt_cppclass_main.cppc++类
设置参数代码接口包装。
静态的主要程序并不生成的代码的一部分。提供的程序为基础开发自定义修改,用于模拟。
一个静态的主程序包含:
rt_OneStep
——一个定时器中断服务例程(ISR)的入口点函数,调用
执行处理为一个时钟周期的模型。模型
_step骨骼
主要
提供功能,主要
仅用于仿真。你必须修改主要
实时中断驱动执行。
对于单频模型,操作的rt_OneStep
和主要
函数在静态主程序,都是一样的自动生成的版本中描述生成独立的可执行程序部署到目标硬件。对于多重速率的,多任务模型,静态主程序和生成的代码在下一节中描述的不同。
开发一个应用程序通过使用一个静态主程序:
将程序模块复制到你的工作目录。
重命名文件。例如,重命名
rt_main.c
来
。模型
_rt_main.c自定义程序模块内容。
修改模板makefile或工具链设置,构建过程创建一个相应的对象文件,等
(在UNIX®,模型
_rt_main.obj
),在构建文件夹。模型
_rt_main.o
如果你的现有应用程序依赖于一个静态的ert_main.c
R2012b之前开发的版本,rt_main.c
,rt_malloc_main.c
,或rt_cppclass_main.cpp
,您可能需要继续使用静态主程序。
率分组和静态主程序
ERT-based系统目标文件可以使用一个静态模型的主程序模块和禁止使用配置参数主程序生成一个例子。一个定制的系统目标文件并不禁止使用模型配置参数已经有针对性的改变时的静态主程序和修改必须保留。生成的示例主程序不保留更改静态主程序。
模型配置为多任务(对待每个离散率作为一个单独的任务被选中)或并发性(允许任务并发执行的目标选择),代码生成器使用分组方案,生产步骤为每个率(入口点函数
,在那里模型
_stepN
识别速度)。代码接口报告列出了单独的入口点函数,主程序可以调用。N
指定,只有率步函数生成包装器函数,用TLC变量RateBasedStepFcn
。如果你的目标直接调用率分组兼容的函数,集合RateBasedStepFcn
来1
。在这种情况下,不生成包装器函数。
在你的系统目标文件,之前%包括“codegenentry.tlc”
声明中,设置TLC变量RateBasedStepFcn
来1
。另外,组RateBasedStepFcn
来1
在你的target_settings.tlc
文件。
修改静态主程序
主循环和做一些修改rt_OneStep
函数。看到修改主程序的指导方针和修改rt_OneStep指南。
取代rt_OneStep
在主循环调用后台任务调用或空语句。
其他您可能需要修改:
如果适用,请遵循关于在哪里添加代码注释的代码阅读和写作模型I / O和保存和恢复FPU上下文。
如果你修改
rt_main.c
,rt_malloc_main.c
,或rt_cppclass_main.cpp
读一个值从一个连续的输出端口在每个基础概率模型步骤中,看到有关的准则修改rt_OneStep指南。当你明确的模型配置参数主程序生成一个例子,代码生成器生成
rtmodel.h
主程序模块之间提供一个接口和模型生成代码。如果您创建自己的静态主程序模块,包括rtmodel.h
。或者,您可以压制的一代
rtmodel.h
,包括
直接在你的主程序模块。抑制代模型
。hrtmodel.h
系统中,使用以下语句目标文件:%分配AutoBuildProcedure = 0
如果你有了模型配置参数终止功能要求,删除或注释掉以下项目生产的版本
rt_main.c
,rt_malloc_main.c
,或rt_cppclass_main.cpp
:的
#如果TERMFCN……
编译时错误检查调用
MODEL_TERMINATE
因为只有
rt_main.c
:如果你不要结合输出和更新功能,清晰的模型配置参数单输出/更新功能做出以下改变生产的版本rt_main.c
:代替打电话
MODEL_STEP
与调用MODEL_OUTPUT
和MODEL_UPDATE
。删除
#如果ONESTEPFCN……
错误检查。
静态程序模块
rt_main.c
不支持金宝app可重用的功能
包装代码接口。如果你使用可重用的功能
非法代码接口包装,这个错误检查提出了一个编译时错误。#如果MULTI_INSTANCE_CODE = = 1
主要修改静态分配和访问模型实例数据
如果您正在使用一个静态的主程序模块和配置您的模型可重用的功能
代码接口包装,但模型配置参数使用动态内存分配模型初始化清除,必须分配模型实例数据调用静态或动态的主要代码。指向个体模型数据结构如阻塞IO, DWork和参数必须设置在顶层实时模型的数据结构。
支持主金宝app要的修改,这些实时模型的构建过程生成一个子集(RTM)宏,基于模型的数据需求,
。模型
。h
RTM宏观语法 | 描述 |
---|---|
rtmGetBlockIO (rtm) |
块I / O数据结构 |
val rtmSetBlockIO (rtm) |
组块的I / O数据结构 |
rtmGetContStates (rtm) |
得到连续状态的数据结构 |
val rtmSetContStates (rtm) |
设置连续状态的数据结构 |
rtmGetDefaultParam (rtm) |
获得默认参数的数据结构 |
val rtmSetDefaultParam (rtm) |
设置默认参数的数据结构 |
rtmGetPrevZCSigState (rtm) |
前面的讨论二阶导数过零信号状态的数据结构 |
val rtmSetPrevZCSigState (rtm) |
设置之前讨论二阶导数过零信号状态数据结构 |
rtmGetRootDWork (rtm) |
DWork数据结构 |
val rtmSetRootDWork (rtm) |
设置DWork数据结构 |
rtmGetU (rtm) |
得到根输入数据结构(当根输入传递的模型数据结构) |
val rtmSetU (rtm) |
设置根输入数据结构(当根输入传递的模型数据结构) |
rtmGetY (rtm) |
得到根输出数据结构(当根输出传递的模型数据结构) |
val rtmSetY (rtm) |
设置根输出数据结构(当根输出传递的模型数据结构) |
在RTM访问单个模型数据结构数据结构,在静态主程序中使用这些宏。例如,假设模型的例子rtwdemo_reusable
配置了可重用的功能
包装代码界面,使用动态内存分配模型初始化清除,通过根级I / O设置为个人观点
,优化窗格中选择删除根水平I / O零初始化清除。构建模型生成这些模型数据结构和模型的切入点之一rtwdemo_reusable.h
:
/ *块状态(自动存储)系统的<根> * / typedef struct {real_T Delay_DSTATE;/ * < Root > /延迟的* /}D_Work;/ *参数(自动存储)* / struct Parameters_ {real_T k1;/ *变量:k1 *引用:“< Root > /增益”* /};/ *模型入口点函数* /走读生空白rtwdemo_reusable_initialize (RT_MODEL * const rtM, real_T * rtU_In1 real_T * rtU_In2 real_T * rtY_Out1);外面的空白rtwdemo_reusable_step (RT_MODEL * const rtM, real_T rtU_In1, real_T rtU_In2, real_T * rtY_Out1);
如果你不选择模型配置参数主程序生成一个例子的模型,rtwdemo_reusable.h
包含了RTM宏定义rtmGetDefaultParam
,rtmsetDefaultParam
,rtmGetRootDWork
,rtmSetRootDWork
。
供参考,生成的rtmodel.h
文件包含的示例参数定义初始值(nonexecuting代码):
#如果0 / *示例参数数据定义与初始值* /静态参数rtP ={2.0 / *变量:k1 *引用:“< Root > /增益”* /};/ * * / # endif修改参数
在静态的定义部分主要文件,您可以使用下面的代码静态分配的数据结构和参数的实时模型rtwdemo_reusable
模型:
静态RT_MODEL rtM_;静态RT_MODEL * const rtM = &rtM_;/ * * /静态参数实时模型rtP ={2.0 / *变量:k1 *引用:“< Root > /增益”* /};/ *修改的参数* /静态D_Work rtDWork;* / / * / *可观察状态的< Root > / In1 * /静态real_T rtU_In1;/ * < Root > / In2”* /静态real_T rtU_In2;/ * < Root > /着干活的* /静态real_T rtY_Out1;
在体内的主要功能,您可以使用以下RTM宏调用设置模型参数和DWork数据的实时模型数据结构:
int_T main (int_T命令行参数个数,const char * argv []) {…/ *把模型数据进RTM * / rtmSetDefaultParam (RTM、rtp);&rtDWork rtmSetRootDWork (rtM);/ *初始化模式* / rtwdemo_reusable_initialize (rtM、&rtU_In1 &rtU_In2, &rtY_Out1);…}
按照类似的方法设置的多个实例模型数据,实时的为每个实例模型的数据结构都有自己的数据。特别是,参数结构(rtP
必须为每个实例初始化),你想要的值,静态的一部分rtP
数据定义或在运行时。
率分组遵从性和兼容性问题
主程序的兼容性
当你明确的模型配置参数主程序生成一个例子,代码生成器产生不同速率分组代码,兼容老的静态ert_main.c
模块。看到率分组和静态主程序获取详细信息。
让你S-Functions率分组兼容
内置的仿真软件金宝app®块,以及DSP系统工具箱™块,生成率分组代码符合要求。然而,用户编写的多重速率的内联S-functions可能不是率分组兼容。不合规的块生成更高效的代码,但否则兼容率分组。充分利用效率率分组、升级多重速率的内联S-functions完全率分组兼容。你应该升级你的TLC功能实现,如本节所述。
使用不合规的多重速率的块生成rate-grouping代码生成死代码。这可能会导致两个问题:
减少代码效率。
在编译时警告消息发布。这些警告是死代码引用时引起的临时变量初始化。自死代码没有运行,这个问题并不影响生成的代码的运行时行为。
让你S-functions率分组兼容,您可以使用以下TLC函数来生成ModelOutputs
和ModelUpdate
代码,分别为:
OutputsForTID(块,系统,tid) UpdateForTID(块,系统,tid)
下面的代码清单说明一代的输出计算没有率分组(清单1)和分组(清单2)。请注意以下几点:
的
tid
参数是一个任务标识符(0 . . NumTasks-1
)。只有保护的代码
tid
传递给OutputsForTID
是生成的。的如果(% < LibIsSFcnSampleHit (portName) >)
测试是不习惯OutputsForTID
。当生成率分组代码,
OutputsForTID
和/或UpdateForTID
在代码生成。当生成non-rate-grouping代码,输出
和/或更新
被称为。在率分组兼容的代码中,顶层
输出
和/或更新
函数调用OutputsForTID
和/或UpdateForTID
函数为每个率(tid
)参与。返回的代码OutputsForTID
和/或UpdateForTID
必须有相应的守卫tid
警卫:如果(% < LibIsSFcnSampleHit (portName) >)
如清单2所示。
清单1:输出代码生成没有分组
% % multirate_blk。薄层色谱%implements "multirate_blk" "C" %% Function: mdlOutputs ===================================================== %% Abstract: %% %% Compute the two outputs (input signal decimated by the %% specified parameter). The decimation is handled by sample times. %% The decimation is only performed if the block is enabled. %% Each port has a different rate. %% %% Note, the usage of the enable should really be protected such that %% each task has its own enable state. In this example, the enable %% occurs immediately which may or may not be the expected behavior. %% %function Outputs(block, system) Output /* %Block: % */ %assign enable = LibBlockInputSignal(0, "", "", 0) { int_T *enabled = &% ; %if LibGetSFcnTIDType("InputPortIdx0") == "continuous" %% Only check the enable signal on a major time step. if (% && ... % ) { *enabled = (% > 0.0); } %else if (% ) { *enabled = (% > 0.0); } %endif if (*enabled) { %assign signal = LibBlockInputSignal(1, "", "", 0) if (% ) { %assign y = LibBlockOutputSignal(0, "", "", 0) % = % ; } if (% ) { %assign y = LibBlockOutputSignal(1, "", "", 0) % = % ; } } } %endfunction %% [EOF] sfun_multirate.tlc
清单2:输出代码生成率分组
% % example_multirateblk。薄层色谱%implements "example_multirateblk" "C" %% Function: mdlOutputs ===================================================== %% Abstract: %% %% Compute the two outputs (the input signal decimated by the %% specified parameter). The decimation is handled by sample times. %% The decimation is only performed if the block is enabled. %% All ports have different sample rate. %% %% Note: the usage of the enable should really be protected such that %% each task has its own enable state. In this example, the enable %% occurs immediately which may or may not be the expected behavior. %% %function Outputs(block, system) Output %assign portIdxName = ["InputPortIdx0","OutputPortIdx0","OutputPortIdx1"] %assign portTID = [%, ... % , ... % ] %foreach i = 3 %assign portName = portIdxName[i] %assign tid = portTID[i] if (% ) { % } %endforeach %endfunction %function OutputsForTID(block, system, tid) Output /* % Block: % */ %assign enable = LibBlockInputSignal(0, "", "", 0) %assign enabled = LibBlockIWork(0, "", "", 0) %assign signal = LibBlockInputSignal(1, "", "", 0) %switch(tid) %case LibGetGlobalTIDFromLocalSFcnTID("InputPortIdx0") %if LibGetSFcnTIDType("InputPortIdx0") == "continuous" %% Only check the enable signal on a major time step. if (% ) { % = (% > 0.0); } %else % = (% > 0.0); %endif %break %case LibGetGlobalTIDFromLocalSFcnTID("OutputPortIdx0") if (% ) { %assign y = LibBlockOutputSignal(0, "", "", 0) % = % ; } %break %case LibGetGlobalTIDFromLocalSFcnTID("OutputPortIdx1") if (% ) { %assign y = LibBlockOutputSignal(1, "", "", 0) % = % ; } %break %default %% error it out %endswitch %endfunction %% [EOF] sfun_multirate.tlc
生成代码,取消引用数据从内存地址
这个例子展示了如何生成代码读取信号的价值非关联化一个你指定的内存地址。使用这种技术,您可以生成一个控制算法与内存硬件填充(例如,内存,存储在单片机模拟-数字转换器的输出)。
在本例中,您生成一个算法,获得输入数据从一个16位的内存块的地址0 x8675309
。假设一个硬件设备异步填充只有较低的10位的地址。该算法必须把地址为只读(常量
)、挥发性(挥发性
)数据,忽略上面的6位的地址。
生成的代码可以访问的数据通过定义一个宏,取消引用0 x8675309
和面具不必要的部分:
#定义A2D_INPUT((*(挥发性const uint16_T *) 0 x8675309) &0x03FF)
配置一个模型来生成代码定义和使用这个宏:
创建示例模型。
创建包,包含定义数据类和存储类。
使用自定义存储类设计器创建一个存储类。
定义一个类来存储属性存储类的设置。
写目标语言编译器(TLC)代码发出正确的C代码存储类。
定义一个类的尺寸数据。
包加载到嵌入式编码字典。
配置模型根级尺寸使用存储类。
生成和检查代码。
为例,展示了如何使用自定义存储类设计师没有编写TLC代码,看看创建和应用存储类。
作为替代TLC写代码,您可以使用内存部分来生成代码,包括语法。根据您的构建工具链,你可以使用语法来指定文字存储一个全局变量的内存地址。更多信息关于记忆部分,看到控制数据和函数放置在内存中插入语法。
推导的宏观语法
在这个示例中,您可以配置生成的代码来定义和使用非关联化宏。为宏观确定正确的语法,首先记录目标地址。
0 x8675309
地址是一个指针指向一个16位整数。使用仿真软件编码金宝app器数据类型名称uint16_T
。
(uint16_T *) 0 x8675309
添加存储类型限定符常量
因为生成的代码必须不写地址。添加挥发性
因为硬件可以在任意时间填充地址。
0 x8675309波动(const uint16_T *)
废弃的地址。
*(挥发性const uint16_T *) 0 x8675309
废弃后操作,应用一个面具只保留10位硬件填充。使用显式的括号来控制操作的顺序。
(*(挥发性const uint16_T *) 0 x8675309) &0x03FF
作为一个安全的编码实践,将整个结构一层括号。
((*(挥发性const uint16_T *) 0 x8675309) &0x03FF)
创建示例模型
创建示例模型ex_memmap_simple
。
尺寸的块,设置输出数据类型uint16
。名字的信号A2D_INPUT
。的轮廓尺寸
块和信号行代表硬件的数据填充。
获得块,设置输出数据类型双
。
创建包,包含定义数据类和存储类
在当前文件夹中,创建一个文件夹命名+ MemoryMap
。文件夹命名定义了一个包MemoryMap
。
让外面的包使用您当前的文件夹,您可以添加文件夹包含+ MemoryMap
文件夹到MATLAB路径。
创建存储类
生成的代码定义和读取A2D_INPUT
作为一个宏,你必须创建一个存储类,您可以应用到模型根级尺寸。后来,你写TLC补充了存储类的代码。
在高级模式打开自定义存储类设计师。设计一个存储类定制TLC之间运行的代码,您必须使用先进的模式。
cscdesigner (“MemoryMap”,“先进”);
在自定义存储类设计器中,单击新。一个新的自定义存储类,NewCSC_1
,出现在列表中存储类的定义。
重命名的存储类MemoryMappedAddress
。
为MemoryMappedAddress
,在一般选项卡,设置:
类型来
其他
。存储类可以通过定制的TLC稍后您写的代码。数据范围来
出口
。对于使用这个自定义存储类的数据项,仿真软件编码器生成定义(例如,金宝app#定义
声明定义一个宏)。数据初始化来
没有一个
。金宝app仿真软件编码器不生成代码初始化数据项。使用这个设置,因为这个自定义存储类代表只读数据。你不选择宏
因为自定义存储类设计师不允许您使用宏
信号数据。定义文件来
指定
(离开文本框为空)。消耗内存的数据项在生成的代码中,定义文件指定了。c
源文件,分配内存。存储类产量一个宏,不需要记忆。通常情况下,头文件(。h
),而不是。c
文件,定义宏。设置定义文件来指定
而不是具体的实例
防止不必要的存储类指定的用户定义文件。头文件来
具体的实例
。控制文件位置的宏定义,存储类的用户必须为每个数据项指定头文件,使用这个存储类。老板来
指定
(离开文本框为空)。老板只适用于数据项消耗内存。
选择设置完成后,点击应用和保存。
现在,当您应用存储类数据项,如尺寸三机一体
,您可以指定一个头文件包含生成的宏定义。你还不能指定一个内存地址的数据项。要启用规范的一个内存地址,创建一个自定义属性类,你可以的MemoryMappedAddress
存储类。
为存储类定义类来存储属性设置
定义一个MATLAB类来存储数据项使用存储类的附加信息。在这种情况下,额外的信息是内存地址。
在MemoryMap
包(+ MemoryMap
文件夹),创建一个文件夹命名@MemoryMapAttribs
。
在@MemoryMapAttribs
文件夹中,创建一个文件命名MemoryMapAttribs
。文件定义了一个类,它来源于内置类金宝appSimulink.CustomStorageClassAttributes
。
classdefMemoryMapAttribs < 金宝appSimulink.CustomStorageClassAttributes属性(PropertyType =“字符”)MemoryAddress =”;结束结束
之后,你将这类MATLAB与MemoryMappedAddress
存储类。然后,当您应用存储类数据项,您可以指定一个内存地址。
写TLC发出正确的C代码的代码
编写TLC代码使用存储类的属性,如HeaderFile
和MemoryAddress
为每个数据项,生成正确的C代码。
在+ MemoryMap
文件夹中,创建一个文件夹命名薄层色谱
。
导航到新文件夹。
检查内置模板TLC文件,TEMPLATE_v1.tlc
。
编辑(fullfile (matlabroot,…“工具箱”,“环球套票”,“目标”,“是”,“csc_templates”,“TEMPLATE_v1.tlc”))
保存一份TEMPLATE_v1.tlc
在薄层色谱
文件夹中。重命名复制memory_map_csc.tlc
。
在memory_map_csc.tlc
控制生成c代码,找到部分数据声明。
%例“声明”% % LibDefaultCustomStorageDeclare是默认声明函数% %声明一个全局变量的标识符的名称数据。%返回“走读生% < LibDefaultCustomStorageDeclare(记录)>“% %打破% % = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
的声明
例(%的情况
)构造一个返回值(%返回
),代码生成器产生的头文件指定为每个数据项。控制的C代码声明每个数据项,调整的返回值声明
的情况。
取代现有的%的情况
满意这个新代码,它指定一个不同的返回值:
%例“声明”% %在TLC代码中,记录的是一个数据项(例如,一个信号线)。% %的LibGetRecordIdentifier返回数据项的名称。%分配id = LibGetRecordIdentifier(记录)%分配dt = LibGetRecordCompositeDataTypeName(记录)% %的“CoderInfo”属性数据项存储% %的仿真软件。金宝appCoderInfo”对象,该商店代码生成设置% %,如存储类或自定义存储类,你为项目指定% %。%分配ci = record.Object.ObjectProperties。代码rInfo %% The 'ci' variable now stores the 'Simulink.CoderInfo' object. %% By default, the 'CustomAttributes' property of a 'Simulink.CoderInfo' %% object stores a 'Simulink.CustomStorageClassAttributes' object. %% This nested object stores specialized code generation settings %% such as the header file and definition file that you specify for %% the data item. %% %% The 'MemoryMap' package derives a new class, %% 'MemoryMapAttribs', from 'Simulink.CustomStorageClassAttributes'. %% The new class adds a property named 'MemoryAddress'. %% This TLC code determines the memory address of the data item by %% acquiring the value of the 'MemoryAddress' property. %assign ca = ci.Object.ObjectProperties.CustomAttributes %assign address = ca.Object.ObjectProperties.MemoryAddress %assign width = LibGetDataWidth(record) %% This TLC code constructs the full macro, with correct C syntax, %% based on the values of TLC variables such as 'address' and 'dt'. %% This TLC code also asserts that the data item must be a scalar. %if width == 1 %assign macro = ... "#define %((*(volatile const % *)%) & 0x03FF)" %else %error( "Non scalars are not supported yet." ) %endif %return "% " %%break %% ==========================================================================
新的TLC代码使用内置的TLC记录功能,例如LibGetRecordIdentifier
和其他TLC命令和操作来访问数据项的信息。临时变量,如dt
和地址
存储这些信息。TLC代码构造完整的宏,使用正确的C语法,通过扩展变量,和商店的宏观变量宏
。
在同一个文件中,找到控制生成数据定义的一部分。
%例”定义“% % LibDefaultCustomStorageDefine是默认定义函数来定义一个全局变量% %的标识符的名称数据。如果% %数据参数,定义也是静态初始化% %其标称值(如在MATLAB)。%返回“% < LibDefaultCustomStorageDefine(记录)>“% %打破% % = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
的定义
获得一个返回值,代码生成器发出。c
文件,它定义了数据项消耗内存。
取代现有的%的情况
满意这个新内容:
%例“定义”%返回" % %打破% % = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
MemoryMappedAddress
收益率宏观在生成的代码中,所以你使用声明
情况下,而不是定义
建造和发射的宏。为了防止定义
从发出重复的宏定义,新的TLC代码返回一个空字符串。
找到控制生成的代码的一部分初始化数据。
%例“初始化”% % % % LibDefaultCustomStorageInitialize是默认初始化函数,初始化一个标量元素的一个全局变量为0。%返回LibDefaultCustomStorageInitialize(记录,idx雷姆)% %打破% % = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
的初始化
情况下生成的代码(例如,在初始化数据项模型_initialize
功能)。
取代现有的%的情况
满意这个新内容:
%例“初始化”%返回" % %打破% % = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
MemoryMappedAddress
产量一个宏,所以生成的代码不能尝试宏的值进行初始化。新的TLC代码返回一个空字符串。
完整的存储类的定义
你的新MATLAB类,MemoryMapAttribs
你的存储类,可以让用户,MemoryMappedAddress
为每个数据项,指定一个内存地址。允许这个规范MemoryMapAttribs
与MemoryMappedAddress
。生成正确的C代码根据您指定的信息对于每一个数据项,将定制的TLC文件,memory_map_csc.tlc
,MemoryMappedAddress
。
导航到包含的文件夹+ MemoryMap
文件夹中。
再次打开自定义存储类设计师。
cscdesigner (“MemoryMap”,“先进”);
为MemoryMappedAddress
,在其他属性选项卡,设置:
薄层色谱文件名称来
memory_map_csc.tlc
。CSC属性类来
MemoryMap.MemoryMapAttribs
。
点击应用和保存。
定义信号数据类
应用存储类数据元素模型,MemoryMap
包,您必须创建一个源自MATLAB类金宝appSimulink.Signal
。当你配置的信号模型,你选择这个新数据类而不是默认的类,金宝appSimulink.Signal
。
在MemoryMap
包的下面,创建一个文件夹命名@Signal
。
在@Signal
文件夹中,创建一个文件命名Signal.m
。
classdef信号< Simul金宝appink.Signal方法函数setupCoderInfo(这)useLocalCustomStorageClasses(这一点,“MemoryMap”);返回;结束结束结束
该文件定义了一个类命名MemoryMap.Signal
。类定义覆盖setupCoderInfo
方法,该方法的金宝appSimulink.Signal
类已经实现。新的实现指定的对象MemoryMap.Signal
类使用定制的存储类MemoryMap
包(而不是存储类的金宝app
包)。当您配置模型通过选择一个信号MemoryMap.Signal
类,你可以选择新的自定义存储类,MemoryMappedAddress
。
包加载到嵌入式编码字典
导航到文件夹,其中包含示例模型和打开模型。
打开嵌入式编码器应用程序。
开放的嵌入式编码字典。在C代码选项卡上,选择代码接口>嵌入式编码字典。
在嵌入式编码字典,点击管理包。
在管理包的对话框,点击刷新。当刷新完成,选择方案MemoryMap
。点击负载。
关闭嵌入式编码字典。
配置根级尺寸使用存储类
在嵌入式编码器应用程序,使用映射的代码编辑器和属性检查器来配置尺寸三机一体
使用的存储类的定义。
打开代码映射编辑器。在C代码选项卡上,选择代码接口>单个元素的代码映射。
在代码映射编辑器中,在港口选项卡上,选择尺寸。三机一体
。设置存储类三机一体
来MemoryMappedAddress
。
在属性检查器代码,设置HeaderFile财产memory_mapped_addresses.h
和MemoryAddress财产0 x8675309
。
保存模型。
生成和检查代码
从模型中生成代码。
# # #开始构建过程:ex_memmap_simple tf =逻辑0 # # #成功完成构建过程:ex_memmap_simple模型建立目标:总结构建模型重建行动的原因= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ex_memmap_simple代码生成和编译代码生成信息文件不存在。1 1模型的建立(0模型已经更新)构建持续时间:0 h 0米32.363秒
检查生成的头文件memory_mapped_addresses.h
。该文件定义了宏A2D_INPUT
,对应于模型中的信号线。
/ *数据与自定义存储类MemoryMappedAddress宣言* / # define A2D_INPUT((*(挥发性const uint16_T *) 0 x8675309) & 0 x03ff)
检查生成的文件ex_memmap_simple.c
。生成的算法代码(对应于获得块)计算模型的输出,rtY.Out1
通过作用于A2D_INPUT
。
/ *模型阶跃函数* /无效步骤(void){/ *外港:“< Root > /着干活”包含:*获得:“< Root > /增益”*尺寸:“< Root > / In1”* /而无。着干活= 42.0 * (real_T) A2D_INPUT;}