Engee 文档
Notebook

为 STM32 生成代码(有限自动机上的按钮和闪烁的 LED)

本演示将介绍用于控制 STM32* 微控制器数字输入和输出的 Engee 模型。

介绍

本示例的目的是利用Engee有限自动机库的嵌套状态和超瞬态,为一个相当简单的程序开发一个Engee模型,以控制STM32F446RE微控制器的数字输入和输出。 本演示是 STM32 代码生成(有限自动机上闪烁的 LED)* 示例的功能开发。

模型描述

示例模型 -stm32_button_blink.engee 包括三个模块C Function ,用于配置和连接控制器外设:
GPIO_PC13_INPUT (USER_BUTTON) - 在程序初始化期间,将微控制器的 *PC13 引脚配置和初始化为输出。在逐步执行程序期间,它将返回数字输出的状态PinState 。在 NUCLEO-F446RE 调试板上,用户按钮 B1 "USER " 与该引脚相连。 GPIO_5_OUTPUT (LED) - 在程序初始化期间,将微控制器的 *PA5 引脚配置和初始化为输入。在逐步执行过程中,它将分配给PinState 的状态。调试板 NUCLEO-F446RE 上的 LED LD2 "GREEN " 连接到该引脚。 *DELAY - 在程序初始化期间配置和初始化内部定时器SysTick 。在分步执行过程中,在其帮助下产生与建模步长相等的延迟Ts

image.png

可调参数Tscallbacks中的函数PreLoadFunc 定义,用作模型求解器的步长、模块DELAY 的输入值和模块Pulse Generator 的计算步长。

Pulse Generator 程序块模拟在仿真期间周期性按下调试板上的 B1 按钮。按键持续时间为 10 秒,周期为 20 秒。在仿真过程中,该程序块的信号通过数字输入程序块,不会发生变化。

在程序块Blink 中,借助 状态图 实现了 LED 闪烁的脉冲生成逻辑。

状态图

STM32 代码生成示例(有限状态机上闪烁的 LED)* 的状态图包含一个父状态,而本示例的块Chart 则包含两个父状态,它们之间有超级转换。

chart.png

内部变量FullTime 可设定 LED 闪烁的持续时间--如果未按下 B1 按钮且输入变量ChangeFreq 等于$0$ ,则在父状态Period_and_Clock 下为$100\cdot T_s$ 秒,否则在父状态Period_and_Clock_2 下为$50\cdot T_s$ 秒。当处于父状态时,计数器变量CurrentTime 会递增,当离开父状态时,计数器变量 会重置。

连接外设

STM32(有限自动机上闪烁的 LED)代码生成示例中使用 STM32 硬件抽象层(HAL)库来处理外设不同,这里的外设块根据头文件stm32f4xx.h 使用寄存器访问。C Functions 的构建选项(Build options)中连接了该文件。stm32f4xx.h 文件本身位于示例文件夹中,仅用于建模和代码生成,无需进一步添加到集成开发环境项目中。

image.png

代码注释中对外围程序块代码作了进一步解释。

建模结果

为了模拟按下按钮产生控制脉冲的算法,让我们加载并运行模型stm32_button_blink.engee

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

data = engee.run(m);

根据获得的模拟数据,我们绘制出信号Blink.Out - 内置 LED 的状态和Pulse Generator.1 - 按钮的状态:

In [ ]:
using Plots
plotlyjs()
plot(data["Pulse Generator.1"].time,
     data["Pulse Generator.1"].value,
     label="Переключение частоты", size=(900,300),
     lw=2, legend=:topright)
plot!(data["Blink.Out"].time,
     data["Blink.Out"].value,
     label="Состояние светодиода", lw=2, )
Out[0]:

从图中可以看出,模型通过按下按钮为 LED 生成了频率可变的周期信号。

代码生成

让我们根据模型生成代码,将控制算法加载到微控制器中:

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

stm32_button_blink_code 文件夹中创建的文件--头文件stm32_button_blink.h 和源文件stm32_button_blink.c 将在项目组装中进一步使用。

在开发环境中准备项目

用于构建项目并将其加载到目标设备的开发环境是带有 PlatformIO 附加组件的 VS Code。环境和连接的配置与 STM32 代码生成(有限自动机上闪烁的 LED)* 示例中的配置一致。

创建新项目后,您需要添加在Engee中生成的文件以及包含主程序代码的文件main.c (添加到示例文件夹中):

stm32.png

之后,您就可以继续构建项目并加载程序了。

在 STM32 上执行模型

让我们将调试板 NUCLEO-F446RE 连接到计算机的 USB 端口,然后在 PlatformIO 中观察连接的设备。要正确识别该调试板的连接,需要使用 ST-Link V2 驱动程序。

连接成功后,我们开始构建项目:"PLATFORMIO -> PROJECT TASKS -> nucleo_f446re -> General -> Build"。如果没有构建错误,请将编译好的代码加载到微控制器中:"PLATFORMIO -> PROJECT TASKS -> nucleo_f446re -> nucleo_f446re -> General -> Upload"。
在调试板上加载程序后,可以观察到 LED 以 1 Hz 的频率闪烁。按下 B1 按钮时,LED 闪烁频率为 2 Hz。

btn_blnk.gif

为了在示例中进行演示,将 Hantec DSO 数字示波器连接到调试板的相应引脚(D13)上,并使用 DSO Analyzer 外壳通过计算机的串行端口读取波形。 从上面的动画中可以看到,按下内置按钮时,输出信号的频率会加倍。

结论

在本例中,我们考虑了开发Engee模型,用于控制作为NUCLEO调试板一部分的STM32F446RE微控制器上闪烁的 LED 程序。该算法是利用Engee自动机库中Engee**块Chart 的嵌套状态和超级转换实现的,适合代码生成。开发的模型与生成的文件一起嵌入到VS代码PlatformIO环境项目中,并在目标设备上进一步组装、加载和执行。

示例中使用的块