Engee 文档
Notebook

为 Arduino 生成代码(生成 PWM 信号)

在本示例中,我们将向您展示如何在Engee中生成程序代码,以便在 Arduino 平台上生成 PWM 信号。

简介

创建脉宽调制(PWM)信号的方法有很多。我们将用基本元件实现一个模型,尽可能与演示示例arduino_blink 相似。也就是说,我们将控制 LED 亮起和熄灭之间的时间延迟。

其他可以使用的方法:

  • 将平滑变化的模拟信号与锯齿波信号进行比较,并在交点时刻切换二极管。
  • 使用 Arduino 的一个内置功能

平台准备

本示例需要一个 Arduino 兼容平台(Uno、Leonardo、Iskra 等)和一根合适的 USB 电缆。您还需要在计算机上安装 Arduino IDE,查找并安装 附加驱动程序(如有必要),并通过 USB 连接现有电路板。

image_2.png

型号说明

在这个示例中,我们将从模型pwm.engee 生成代码。

该模型的界面与arduino_blink 示例中的界面相同。在计算的每一步,它都会

  1. 利用out_LED_BUILTIN 的输出切换 LED 的状态(最初等于 1,每个周期变为 "相反")、
  2. 利用param_WAIT_MS 的输出向 Arduino 返回延时值(以毫秒为单位)。

image_2.png

有效值将随程序块Sine 中设置的频率变化为正弦波。最大值在同一程序块中设置为振幅,此处设置的偏移量可使延迟值永远不小于 0,否则 Arduino 平台会出错并停止程序执行。

param_WAIT_MS 值的帮助下,我们将控制脉冲宽度,用不同长度的脉冲打开或关闭 Arduino 平台的 "板载 "LED。

PWM 信号的特点是,在$T_d$ 的固定周期内,它会改变状态1 和状态0 ,其持续时间总计等于$T_d$ ,但其比例可通过参数$w$ (脉冲宽度)来改变。

image.png

我们将使用该信号在 Arduino 平台上模拟 LED 亮度的平滑控制。

数据类型转换

在大多数情况下,Engee 模型块直接反映在 Arduino 的代码中。并非所有平台都使用相同的 C/C++ 语言标准。当然,在创建代码时,您始终需要考虑底层的实现细节。

在本例中,我们在Engee中克服的问题是自动类型转换。在 Arduino 平台上

  • 将布尔数据类型添加到数值数据类型时,输出为布尔型。
  • 将双倍数据类型添加到无符号整数时,输出为无符号整数(如果不指定特殊数据类型,正弦波将无法正常工作)。

数据类型的问题出在哪里?

image_3.png

因此,我们需要设想数据类型的操作在 C 代码中的表现形式,并相应地配置模型块(用绿色"√"标记):

*Constant 模块应返回数据类型Float32 *Compare To Zero 模块不应返回bool ,而应返回uint8

所有这些设置都在相应的块中设置。有时,这些问题可以通过使用Data Type Conversion 块来解决,这种转换也会传递到生成的代码中。

模型测试

半自然建模过程 包括在模拟环境中运行模型进行调试和优化,随后在硬件平台上控制相同的算法。

在我们的案例中,值得考虑的是 Arduino 以自己的时钟频率运行,不同的命令可以在不同的时钟周期内执行。为了依赖真实物理时间,最好创建一个基于实时系统的代码生成模板。

不过,我们已经可以展示我们的解决方案将如何工作。

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

data = engee.run(m);

让我们绘制一个 LED 开关延迟时间图(参数传递给delay() )。

In [ ]:
using Plots
plot( data["param_WAIT_MS"].time, data["param_WAIT_MS"].value,
      label="param_WAIT_MS", st=:step, size=(900,300))

# Подкрасим переменное время задержки (LED вкл/выкл)
plot!( data["param_WAIT_MS"].time, [iseven(i) ? d : NaN for (i,d) in enumerate(data["param_WAIT_MS"].value)],
      label="задержка при выключенном LED", st=:step, size=(900,300), c=:black, lw=2)
plot!( data["param_WAIT_MS"].time, [isodd(i) ? d : NaN for (i,d) in enumerate(data["param_WAIT_MS"].value)],
      label="задержка при включенном LED", st=:step, size=(900,300), c=:red, lw=2)
Out[0]:

我们看到了什么?延时param_WAIT_MS 在时间上的变化是这样的:每两个相邻值相加总是在 10 毫秒左右。正弦波给出了调节这一过程的规律。
<br

如果我们将两个输出信号正确地组合在一起,就会看到控制 LED 输出端电流开关的 PWM 信号。

In [ ]:
plot( cumsum(data["param_WAIT_MS"].value),
             data["out_LED_BUILTIN"].value,
      st=:step, size=(900,200))
Out[0]:

该模型并非用于模拟实际运行时间,因此您可能会注意到模型时间(2 秒-模拟持续时间)与 CPU 时间不相等(根据图表,约为 1 秒,公差较大)。为了提供这种特性,您需要以不同的方式建立模型。

代码生成

在本演示中,我们建议使用以下命令生成代码:

In [ ]:
engee.generate_code( "$(@__DIR__)/pwm.engee",
                     "$(@__DIR__)/sketch_pwm_custom/pwm_code" )
Out[0]:
"Created directory - /user/start/examples/codegen/arduino_pwm/sketch_pwm_custom/pwm_code"

结果,在sketch_pwm_custom 目录中,我们将找到pwm_code 文件夹,在该文件夹中,我们将找到.c.h 文件,其中包含我们模型的代码。

项目文件

我们的项目中只有一个模型。在生成的文件中,我们只需要包含该模型代码的文件:源代码pwm.c 和头文件pwm.h

值得注意的是项目文件和目录的结构:

image_2.png

  • 文件sketch_pwm_custom.ino 包含模型-Arduino 接口的描述sketch_pwm_custom 级目录必须与`.ino` 文件命名相同(Arduino IDE 要求)、
  • 目录pwm_code 包含生成代码的文件,我们将把这些代码包含在文件*.ino 中。

将模型传输到 Arduino

将项目转移到 Arduino 的标准步骤如下:

1.从文件浏览器下载目录sketch_pwm_custom ,解压压缩包; 2. 打开文件sketch_pwm_custom.ino ,点击按钮Upload

结果如下(LED 灯平稳闪烁):

20240127_042956_2.GIF

结论

我们创建了一个比闪烁的 LED 稍为复杂的模型。这种创建 PWM 信号的方法可让您控制 LED 或伺服电机等简单机械。

我们必须考虑数据类型转换在目标平台上是如何工作的。不过,我们已经看到,Engee 平台可以通过代码生成,为几乎可以在硬件平台上无缝运行的组件建模。