Engee 文档
Notebook

创建特定于目标平台的主函数

此示例演示如何使用Engee代码生成器模板生成函数。 main(). 这允许您生成一个函数 main 包含自定义代码(例如,具有MC计时器设置的依赖于平台的代码等)。). 此方法还允许您在RTOS中嵌入模型代码。

一个例子是有限状态机上的计数器模型

作为一个例子,让我们以一个使用有限状态机实现的计数器为例。 实现包含在计数器_PWM模型中:

In [ ]:
demoroot = @__DIR__
mdl = engee.load(joinpath(demoroot,"Counter_PWM.engee"); force = true)
engee.open(mdl)
Out[0]:
System(
	name: root
	id: 7a75407c-b1ea-4bb4-af3a-1767064410f7
)

假设您需要以20Hz的频率调用此计数器,并在不同的硬件平台上实现它:STM32F4和Arduino。

柜台如何运作

image.png

仪表的工作原理是在模拟的每一步增加电池。 如果电池值达到由输入常数设置的阈值THRSHLD,则电池被复位并且isr标志被提升。 对于THRSHLD等于4,结果如下所示:

image_2.png

为了确保系统正常工作,我们将使用ISR标志打开或关闭LED。

主模板

我们已经知道可以使用源代码生成器模板自定义块的代码。 对于main也可以这样做。 主要区别在于主模板中的目标代码量将显着大于宿主语言中的代码量。 此外,主模板只能在使用命令控制生成源代码时使用。

作为一个例子,让我们来看看Arduino的最简单的模板:

In [ ]:
run(`cat "arduino_main.jl"`) 
#include "$(model_name).h"


void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
    $model_init
}

void loop() {
  static unsigned long lastCallTime = 0;
  const unsigned long interval = 50; // 50 ms = 20 Hz

  unsigned long currentTime = millis();

  // Check if 50 ms has elapsed
  if (currentTime - lastCallTime >= interval) {
    $model_step
    digitalWrite(LED_BUILTIN,(uint8_t)$(output(2)))
    lastCallTime = currentTime; // Update last call time
  }
}
Out[0]:
Process(`cat arduino_main.jl`, ProcessExited(0))

正如您所看到的,模板几乎是纯C代码,具有特殊指令,如 $model_<>

В отличии от обычных функций, применяемых в шаблонах, эти директивы раскрываются как вызовы соответствующих функций API модели. Например, вызов $model_step 对于计数器_PWM模型,它将打开为 Counter_PWM_step();

要为每个测试平台生成main,请使用开关:

image.png

并运行下面的代码单元格:

In [ ]:
target = "Arduino" # @param ["STM","Arduino"]
Out[0]:
"Arduino"
In [ ]:
hw = lowercase(target);
engee.generate_code(joinpath(demoroot,"Counter_PWM.engee"),
                    joinpath(demoroot,"$(hw)_code"),
                    target = "c",
                    template_path = "$demoroot/$(hw)_main.jl");
[ Info: Generated code and artifacts: /user/work/code_generation/main_template/arduino_code

您可以使用下面的命令查看生成的代码:

In [ ]:
src = "$(hw)_code/main.c";
run(`cat $src`)
/* Code generated by Engee
 * Model name: Counter_PWM.engee
 * Code generator: release-1.1.17
 * Date: Fri Jun 20 12:36:46 2025
 */

#include "Counter_PWM.h"


void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
    Counter_PWM_init();
}

void loop() {
  static unsigned long lastCallTime = 0;
  const unsigned long interval = 50; // 50 ms = 20 Hz
unsigned long currentTime = millis();

// Check if 50 ms has elapsed
  if (currentTime - lastCallTime >= interval) {
Counter_PWM_step();
digitalWrite(LED_BUILTIN,(uint8_t)Counter_PWM_Y.ISR)
lastCallTime = currentTime; // Update last call time
  }
}
Out[0]:
Process(`cat arduino_code/main.c`, ProcessExited(0))

组装生成的代码

STM装配

装配的步骤在Stm32f4上的闪烁LED示例中描述STM32](https://engee.com/community/ru/catalogs/projects/migaiushchii-svetodiod-na-stm32f4#Выполнение-модели-на-STM32)

Arduino的组装

组装的步骤在Arduino(PWM信号生成)的示例代码中描述了将模型转移到Arduino。唯一的改进是我们将立即重命名main。c到arduino_code。井野

In [ ]:
mv("./arduino_code/main.c", "./arduino_code/arduino_code.ino";force=true)
Out[0]:
"./arduino_code/arduino_code.ino"

操作示范(STM32)

最后,让我们确保示例有效。 为此,我们将使用STM32F4发现卡。 我们将组装项目并将其上传到董事会。 可以看出LED开始闪烁:

![Untitled Project(1).gif](attachment:Untitled Project(1).gif)

结论

Main函数的模板允许您为特定于硬件平台的模型代码生成绑定。 这确保了算法的完全可移植性。

示例中使用的块