Engee 文档
Notebook

为 Arduino 生成代码(直接数字合成)

本示例介绍了一个信号直接数字合成(DDS)模型,随后可在 Arduino 上执行。

引言

直接数字合成的任务是在具有可调参数的振荡器输出端产生给定形状的信号。在本示例中,将通过外部离散信号实现正负斜率锯齿波、三角波、正弦波和蜿蜒波等五种输出波形之间的切换。两个外部模拟信号将控制输出信号的频率和振幅。

硬件

在本示例中,Arduino MEGA 2560 调试板被用作目标设备。输出信号由输出 #9 产生。使用 PWM 和 RC 低通滤波器对信号进行数模转换。PWM 频率为$f_{PWM} = 62.5 кГц$ ,RC 滤波器截止频率为$f_{c} = 14.185 кГц$ ,滤波器阶数为 2。RC 电路参数:$R_ф = 330 Ом ,\ C_ф = 34 нФ$ 。

输出波形开关信号通过上拉电阻$R_п = 10 кОм$ 和并联电容器$C_ш = 75 нФ$ 上的去抖电路,从按钮触点输入 2 号数字输入端。

为了控制输出信号的频率和振幅,带有电阻$R_{reg} = 10 кОм$ 的电位器被连接到 Arduino 调试板的模拟输入端 A0 和 A1。

元件连接图如下图所示。

arduino_dds_bb.png

在低通滤波器的输出端使用示波器 Hantec DSO 采集输出信号。此外,在滤波器之后还通过限流电阻器连接了一个 3.5 毫米音频输出插座$R_д = 10 кОм$ ,以便将信号输出到扬声器。

型号说明

arduino_dds 模型使用四个模块与控制器外围设备C Function 通信: *DigitalInput_Mode - 初始化 2 号数字输入,轮询输入状态。在Engee中建模时,它会产生周期性锯齿信号,为计数器模块输入ModeCounter 提供负边沿,并切换输出波形。 *AnalogInput_Freq - 轮询模拟输入 A0 的频率值。在Engee中建模时,它会设置输出信号的条件频率$frequency = 0.5$ 。 *AnalogInput_Amp - 查询模拟输入 A1 的振幅值。在Engee中建模时,设置输出信号的条件振幅$amplitude = 1.0$. *HFPWM_Output - 以最大可用频率(62.5 kHz)初始化 9 号输出端的 PWM 操作,并将新的脉宽值发送至 PWM 控制模块。

外围模块的详细操作见这些模块代码的注释。

image_2.png

子系统中定义了计算五种给定波形的算法: PositiveSaw -NegativeSaw - 负斜率锯齿波、Triangle - 三角波、Sinusoidal - 正弦波和Square - 斜率为 50%的蜿蜒波。输出信号形状算法之间的切换使用块Multiport Switch ,由子系统ModeCounter 控制。在子系统ModeCounter 中,输入信号的负边沿被高亮显示,按钮触点的按压次数被计数。

因此,在Engee中建模时,频率和振幅设置不变的输出信号将在指定波形之间周期性切换。

建模结果

让我们加载并执行创建的模型:

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

data = engee.run(m);

根据获得的模型数据,绘制生成的信号:

In [ ]:
using Plots
plotlyjs()
plot(data["pwmduty"].time, data["pwmduty"].value,
    legend=false, size=(900,300), lw=2, st=:step)
xlabel!("Время, сек")
ylabel!("Значение")
Out[0]:

可以看出,大约每隔 0.2 秒,输出信号的形状就会发生一次变化。

为 Arduino 生成代码

要上传到 Arduino*,您需要从开发的模型中生成代码:

In [ ]:
engee.generate_code( "$(@__DIR__)/arduino_dds.engee",
                     "$(@__DIR__)/arduino_dds_code")
[ Info: Generated code and artifacts: /user/start/examples/codegen/arduino_dds/arduino_dds_code

我们将把生成的文件连接到用户草图arduino_dds.ino 中指定的目录。下载这些文件,并使用 Arduino IDE 将其加载到 Arduino MEGA

所附草图定义了宏和全局变量,连接了用户生成的文件和第三方库,调用了初始化函数和模型的循环计算。草图还包含注释,用于解释代码如何工作。

程序在 Arduino 上的运行

成功编译并将草图加载到目标设备后,将数字示波器 Hantec DSO 连接到 RC 滤波器的输出端,并拍摄生成的信号波形。测量结果显示,在生成的波形之间切换,然后生成频率可调的锯齿波信号,之后生成振幅可调的锯齿波信号。

dds_good1.gif

为了使 DDS 模型更具代表性,我们在 RC 链的输出端连接了一个扬声器,并将产生的声音录制到文件arduino_dds_audio.wav 中。下一个代码单元允许您将接收到的音频文件加载到脚本中并播放。播放音轨以确保开发的模型正常工作。它记录了输出信号波形连续切换时的声音,然后以正斜率调整锯齿信号的频率和振幅。

In [ ]:
using WAV, Base64
x, fs = wavread( "$(@__DIR__)/arduino_dds_audio.wav" );

buf = IOBuffer();
wavwrite(x, buf; Fs=fs);
data = base64encode(unsafe_string(pointer(buf.data), buf.size));
markup = """<audio controls="controls" {autoplay}>
              <source src="data:audio/wav;base64,$data" type="audio/wav" />
              Your browser does not support the audio element.
              </audio>"""
display( "text/html", markup );

结论

在本演示中,我们开发了一个直接数字信号合成模型,其频率和振幅可调,并能在锯齿波正负、三角波、正弦波和蜿蜒波之间切换波形。在Engee中的仿真结果与在目标设备上的执行结果完全一致。

示例中使用的块