在之前的导出函数文章中,介绍了如何配置仿真模型并将它导出为函数:使用 Model 模块。
案例中,我们的模型模拟的是代码运行一次的行为。也就是说:假设这些代码要跑在 ECU 里,当模型仿真开始ECU 启动,这些代码就运行,当仿真结束ECU 停止。
这是个有意思的过程,不过,要是你想仿真一些更复杂的场景,比如 ECU 多次启动和关闭的场景呢?
这就是需要用的Initialize Function 和 Terminate Function 模块。
下面的例子模拟了一辆车在两种不同情况下多次启动和关闭的场景:
a.当车在运行时,我们使用计数器累加来跟踪记录发动机的在它的整个生命周期里运行的全部时间。
b. 在正常关停的场景下,车钥匙熄火,我们将累计的时间写入一个 non-volatile 内存。所以,在下次汽车启动的时候它还可以被读出来。
c. 假如电池没电了汽车也会关停,但是这时候我们就没有机会把累计时间写入 non-volatile 内存了。
下面我们来看看如何实现上述逻辑。
使用 Initialize 和 Terminate 事件
首先用一个简单的计数器例子,用来模拟发动机运行时间计数:
把上图这种形式的导出函数模型,使用一个Model 模块引用起来。在 R2016b 里 Model 模块的参数设置对话框里就会出现两个新选项:
勾选这两个选项,Model 模块就多出两个输入端口,可连接 Function-call 信号(见下图)。
作为第一次简单尝试,我们用一个 Stateflow chart 来仿真车钥匙启、停时分别启动和关闭这个计数器 EngineRunTime。
仿真结果如下:
当车钥匙启动时,计数器在增长,而当车钥匙关停时,计数器停止计数。而当车钥匙再次启动的时候,计数器重置了。
自定义Initialize 和 Terminate 事件
就像之前所说的,我们并不希望这个计数器在每一次车钥匙关停的时候都重置,不然就没法累计发动机的运行时间了。
为了保留这个计数器的值,我们这时候就可以使用 Initialization 和 Terminate 模块了。
在 Terminate Function 内部,我们使用 State Reader 模块来获取当前的计数值,并保存在 Data Store 模块里。类似的,在 Initialize Function 内部,我们可以读取这个 Data Store 模块,并用这个值来初始化计数器。
译者补充:熟悉 Simulink 代码生成的朋友都知道,EngineRunTime 模型生成代码时,会生成 step 函数,以及相应的Initialize 和 terminate 函数。默认情况下 Initialize 函数里进行输入、输出以及状态量的初始化,terminate函数里是空的。R2016b 之后,新增加的这个 Initialize 和 terminate 模块,可以让你显示的定义这两个函数里的内容。
我们来看结果:
在车钥匙关闭和重启后,每一次EngineRunTime 被重新调用运行时,是在持续计数的。
Reset Function
就像之前说的,我们还需要模拟由于电池电压过低引起的车辆重启。
这表示,在有些真实场景下,有时候计数器模型结束运行的时候,我们是没机会往Data Store 里写数据的。
为了模拟这种场景,我们把原来的Terminate 模块里面的 Terminate Event Listener 模块的事件类型从 Terminate 改为 Reset,并设置一个有含义的名字 writeNVmem。
这样一来,模型里就不再有Terminate Function 模块了。当仿真触发 terminate 事件后,就会执行默认的模块 terminate 函数。
我们重写 Stateflow 调度器,处理这两种关停的情况:
注意,在上面这个模型中,我们在 Model 的参数对话框里勾选了 "Show model reset ports",所以就出来了这个额外的 writeNVmem 端口。
仿真结果如下:
可以看到,在因为电池失效而引起的关停时,计数器的值并不会保存给下次重启的时候用。
代码生成
现在,仿真结果跟我们想要的一致了,接着我们来生成代码。
在生成的代码里,写入 non-volatile 内存一般都是用户自定义代码来实现,或者是 Embedded target 提供的硬件服务。为了模拟这种情况,我们使用 Function call 模块和 Simulink Function 来实现,以前的帖子有介绍过这两个模块的用法。
简单来说,就是把上面 EngineRunTime 模型里的 Data Store Read/Write 模块替换为 Function call。
另外,为了能在仿真的时候得到同样的结果,我们使用 Simulink Function 来完成读写 Data Store 这个功能,跟之前在Initialize 和Terminate function 的读写功能一样。
这就是整个模型的结构:
之前的帖子有介绍过,在代码生成的时候,可以在 EngineRunTime模型里设置配置选项,告诉 Simulink 在链接的时候,去哪里找这个 writeEngineRunTimNV 和 readEngineRunTimNV 函数。
我们把这个导出函数模型生成如下代码:
-
计数器
+关注
关注
32文章
2259浏览量
94870 -
函数
+关注
关注
3文章
4345浏览量
62867 -
电池
+关注
关注
84文章
10672浏览量
130833
发布评论请先 登录
相关推荐
评论