Engee 文档
Notebook

为 Arduino 生成代码(有限自动机上的 PWM)

在本示例中,我们将使用有限自动机库构建算法,并使用C Function 块与目标设备的外设通信,在Engee中开发一个简单的模型,用于在 Arduino 兼容板的输出上进行脉宽调制。

简介

本示例旨在展示使用终端自动机库为 Arduino 兼容平台开发 PWM 触点控制算法的过程。在本示例中,与演示示例arduino_blink_chart 不同的是,算法的所有可能状态都简化为单一状态,输出变量在条件转换中发生变化。这样就有可能减少加载到目标设备中的编译文件的大小,哪怕是很小的大小。此外,该示例还展示了如何使用C Function 块访问控制器外设和 Arduino 开发环境的功能。

<br 本示例中使用的硬件与arduino_blink_chart 示例中的硬件相同。

型号说明

在 Arduino 板 PWM 引脚控制模型中,Сhart 块直接再现了控制算法,其输出引脚cntout 用于输出和存储相应的变量。C Function 块用于通过 Arduino IDE 中的函数与控制器外围设备通信。模型中的块Outport ("Cnt") 是成功生成代码所必需的。

image_2.png

C Function 块的 "in "输入端接收 PWM 脉冲持续时间的值,然后将其传输到 Arduino 板的 PWM 引脚(~13)。

状态图

如前所述,在本示例中,程序块Chart 的状态图由单一状态Counter 表示。从下图中可以看出,除了对过渡条件的检查外,该状态不执行任何操作。在模型计算的每一步,都会按照指定的顺序检查过渡条件,直到其中一个条件满足为止。当条件满足时,条件体被执行,并过渡到初始状态,之后循环往复。

image.png

条件体为 PWM 脉宽变量out 分配 6 个可能值之一,并使计数器变量cnt 增量。其中一个转换的条件是计数器变量在指定范围内。当计数器变量cnt 达到最大值 "1000 "时,计数器复位 (cnt = 0;) 并将 PWM 脉冲持续时间设置为 "0"。

。 这样,我们就可以在OutChart 的输出端获得 PWM 脉冲持续时间的阶跃变化。

image.png

如状态图中的信号设置菜单所示,输出变量的初始值为 "0"。

程序块C Function

C Function 块在所考虑的模型中专门用于代码生成。因此,为了成功编译和验证 Engee 模型,C Function 部分的用户代码被括入条件编译指令#ifdef ... #endif 中。代码C Function 中写入的编译条件只有在连接头文件Arduino.h 时才会执行,这在从 Arduino IDE 编译时会自动发生,而在 Engee 建模环境中编译时不会发生。
<br 程序块的StartCode 部分用于初始化控制器外设,并将在 Arduino IDE 的函数setup() 中调用一次。

image.png

OutputCode 部分用于改变 PWM 脉冲的持续时间,并将该值输出到串行端口。 它将在函数loop() 中每 1 毫秒调用一次。

image_3.png

每个程序的详细说明见程序块注释C Function

建模结果

让我们加载所述模型:

In [ ]:
if "pwm_chart" in [m.name for m in engee.get_all_models()]
    m = engee.open( "pwm_chart" );
else
    m = engee.load( "$(@__DIR__)/pwm_chart.engee" );
end

data = engee.run(m);

根据获得的模型数据,绘制计数器值和 PWM 脉宽的变化图:

In [ ]:
using Plots
plotlyjs();
plot(data["Chart.cnt"].time, data["Chart.cnt"].value,
    label="Cnt", size=(900,300), lw=2)
plot!(data["Chart.out"].time, data["Chart.out"].value,
    label="Out", size=(900,300), lw=2)
xlims!(0.0,3.0)
Out[0]:

从仿真结果可以看出,接收到的计数器信号Cnt 从 "0 "到 "1000",每 1 毫秒以 "1 "为增量增加 1 秒。PWM 脉宽调制信号Out 根据计数器的数值逐步增加:"51"、"102"、"153"、"204"、"255"。 现在,在确保算法和模型正常工作后,我们可以继续生成代码,并在目标设备上重现模型的工作。

将代码上传到 Arduino

为了将开发的模型传输到目标设备,让我们生成 C 代码:

In [ ]:
engee.generate_code( "$(@__DIR__)/pwm_chart.engee",
                     "$(@__DIR__)/pwm_chart_code" )
Out[0]:
"Created directory - /user/start/examples/codegen/arduino_pwm_chart/pwm_chart_code"

插件文件已在指定目录pwm_chart_code 中生成。此外,在演示示例的目录arduino_pwm_chart 中还有一个预先编写的 Arduino 草图,其名称为arduino_pwm_chart.ino 。在该草图中,连接了代码生成过程中获得的头文件,初始化并调用了模型计算时间变 量,并调用了模型计算函数。同时,模型计算函数现在不仅用于计算控制算法,还用于控制控制器外围。代码注释中对草图进行了详细描述。 要在 Arduino 上执行代码,需要下载arduino_pwm_chart 目录,并将arduino_pwm_chart.ino 草图从 Arduino IDE 上传到目标设备。在我们的例子中,如前所述,目标设备是 Amperka 的 Iskra Neo。 成功编译并将可执行代码下载到目标设备后,Arduino IDE 诊断窗口会显示操作成功和输出文件大小的信息:

image.png

在 Arduino 上执行代码

由于在C Function 代码块中,我们不仅使用 PWM 周期持续时间值来控制 PWM 通道,还将计算值输出到计算机的串行端口,因此让我们进入 Arduino IDE 工具,通过串行连接运行连接绘图仪。连接绘图器将输出变量out 在每个计算步骤中的变化。

.gif

image.png

从绘图仪的图表中可以看出,PWM 脉冲持续时间的变化周期为 200 毫秒,持续时间的值与之前显示的值相同。此外,在 Arduino 电路板上可以观察到内置 LED 的亮度以 1 秒钟为周期逐步增加,因为 LED 和电路板的 13 号引脚连接到控制器的同一通道。

捕捉 Arduino 电路板的信号

为了完成在目标设备上对模型运行的测试,我们将对 Arduino 板 13 引脚的所需信号进行示波器测量。

imag098.png

示波器显示 PWM 脉冲持续时间逐渐增加,持续时间变化周期约为 200 毫秒,持续时间增加周期的总持续时间为 1 秒。

结论

在本演示中,我们基于一个无限自动机库,为 Arduino 兼容平台开发了一个 PWM 控制算法模型。此外,还考虑了通过块C Function 与目标设备的外围设备协同工作的问题。根据从微控制器接收到的数据和从调试板获取的振荡图可以确定,从 Engee 模型生成的 C 代码完全再现了算法并与仿真结果一致。

示例中使用的块