Engee 文档
Notebook

为 Milander 1986BE91T 生成代码(行车灯)

简介

在本示例中,将考虑从 PKK Milandr a.s. 公司的1986BE91T微控制器的Engee模型生成代码。该模型再现了微控制器调试板上 "运行灯 "的操作,项目在Keil μVision环境下构建,可执行代码通过J-Link调试器加载。

硬件部分

目标设备是 PKK Milandr, a.s. 的微控制器。1986VE91T (MDR32F9Q1).示例中使用了用于微芯片 1986VE91T1986VE94T(版本 5)的 调试模块

plata.jpg

该示例测试微控制器PORTD 端口的数字输出PORT_Pin_10 -PORT_Pin_14 的工作情况,这些输出与调试板上的 LED VD5 - VD9 相连。为了测试运行情况,我们将重现 "流水灯"--LED 的顺序开启和关闭。每个 LED 的亮起时间设置为 100 毫秒。

型号说明

示例模型为mdr32f9q1_running_lights.engee 。向数字输出端输出高电平信号的持续时间由模块period_msec 设置。

model_2.jpg

Chart](https://engee.com/helpcenter/stable/ru/state-machines/chart.html)块再现了按设定周期依次改变输出 LED 编号的算法。程序块Demultiplexer 根据输出 LED 的编号向相应的输出端口输出 1。Chart 程序块实现的有限自动机包括五个依次循环激活的状态。

chart.jpg

要在有限自动机的不同状态之间转换,需要使用时态逻辑

外围程序块

程序块PORTD_CONFIGPORT1 -PORT5 将 C 代码添加到模型中,以便与控制器外围设备协同工作。为了在生成的代码中添加连接必要头文件的行,需要在PORTD_CONFIG 块的Build options 选项卡中指定要连接的头文件的名称和路径。这些文件本身不包含代码,在建模过程中也不会使用。构建项目时,将从微控制器支持包中添加插件文件。

cfunc_options.jpg

程序块PORTD_CONFIG 为模型生成的代码添加了用于初始化项目中使用的端口的功能,程序块PORT1 -PORT5 则为代码添加了用于设置和重置相应数字引脚有效状态的功能。
外设块代码单元的内容由条件预处理器指令 "封装":

#if defined ( USE_MDR1986VE9x )
    // 用户代码
#endif

这样,代码块中的代码只能在特定目标设备上执行,例如,在 Engee 中建模时将忽略这些代码。

建模结果

让我们加载并运行示例模型:

In [ ]:
# @markdown **Программное управление моделированием:**  
# @markdown Требуется ввести только имя модели
имя_модели = "mdr32f9q1_running_lights" # @param {type:"string"}
if имя_модели in [m.name for m in engee.get_all_models()]
    модель = engee.open( имя_модели );
else
    модель = engee.load( "$(@__DIR__)/"*имя_модели*".engee" );
end
данные = engee.run(модель);

绘制输出变量图。缩放通道的单脉冲信号,使其更加清晰:

In [ ]:
gr(size = (900,400))
plot(данные["channel"].time, [данные["channel"].value, 1.05.*данные["vd5"].value,
     1.1.*данные["vd6"].value, 1.15.*данные["vd7"].value, 1.2.*данные["vd8"].value, 1.25.*данные["vd9"].value,];
     label=[:none "vd5" "vd6" "vd7" "vd8" "vd9"], title="Бегущие огни", st = :step)
Out[0]:

从图中可以看出,有限自动机和解复用器按照给定的算法工作,以给定的持续时间向五个通道依次输出脉冲信号。

代码生成

让我们根据开发的模型生成代码。

In [ ]:
# @markdown **Генерация кода:**  
# @markdown Папка для результатов генерации кода будет создана в папке скрипта:
папка = "code" # @param {type:"string"}

# @markdown Генерация кода для подсистемы:
включить = false # @param {type:"boolean"}
if(включить)
    подсистема = "" # @param {type:"string"}
    engee.generate_code( "$(@__DIR__)/"*имя_модели*".engee", "$(@__DIR__)/"*папка;
                     subsystem_name = подсистема)
else
    engee.generate_code( "$(@__DIR__)/"*имя_модели*".engee", "$(@__DIR__)/"*папка)
end

# @markdown Генерировать `main.c`?
использовать = false # @param {type:"boolean"}

if (!использовать)
    cd("$(@__DIR__)/"*папка)
    rm("main.c")
end
[ Info: Generated code and artifacts: /user/start/examples/codegen/mdr32f9q1_running_lights/code

由于准备就绪的main.c 将在项目中使用,因此上面的代码单元删除了从模型生成的模板main.c ,以消除混淆。现在必须将准备好的main.c 和从模型生成的文件添加到 Keil μVision 开发环境项目中。

项目组成

要在开发环境中使用微控制器,必须安装支持软件包。在本例中,我们使用了非官方支持包

以下是在 Keil μVision 中工作的标准步骤。- 创建一个项目,为所需外设添加源文件,为设备配置添加头文件,并配置生成器和调试器。然后,我们从\code 以及main.c 文件夹中下载示例文件,并将其添加到 Keil 项目中。

project.jpg

然后,您就可以继续构建项目并加载/调试代码了。

构建项目和加载代码

让我们构建 Keil 项目,之后环境终端中会显示类似的信息:

构建开始: 项目:new_project_1
*** Using Compiler 'V6.22', folder: 'C:\Users\engeeuser\AppData\Local\Keil_v5ARM\ARMCLANG\Bin'.
构建目标 'Target_1
编译 main.c...
mdr32f9q1_running_lights.c(49): warning: variable 'seq' is uninitialised when used here [-Wuninitialized].
   49 | cfunc_symbols->seq = seq;
      | ^~~
mdr32f9q1_running_lights.c(44): note: initialise the variable 'seq' to silence this warning
   44 | int8_t seq;
      | ^
      | = '\0'
mdr32f9q1_running_lights.c(291): 警告:比较不同符号的整数:"int64_t"(又名 "long long")和 "uint64_t"(又名 "unsigned long long") [-Wsign-compare].
  291 | 返回 counter * numerator >= (uint64_t)ceil(condition * denominator);
      | ~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mdr32f9q1_running_lights.c(338): warning: unused variable 'seq'.[-Wunused-variable] (未使用变量
  338 | double seq = PORTD_CONFIG_cfunc_symbols.seq;
      | ^~~
mdr32f9q1_running_lights.c(351): warning: variable 'Chart_selector' set but not used [-Wunused-but-set-variable] (未使用但已设置的变量)
  351 | int Chart_selector;
      | ^
生成 4 条警告。
编译 mdr32f9q1_running_lights.c...
链接...
程序大小: 代码=5264 RO-data=224 RW-data=16 ZI-data=1672  
".\Objects\new_project_1.axf" - 0 个错误,4 个警告。
已耗费的构建时间:00:00:00

汇编没有出错,接下来就把代码加载到微控制器中。连接电路板电源和 JTAG 调试器。本例中使用的是 SEGGER J-link

devboard_4.png

如果可执行代码成功加载到微控制器中,环境命令行上将显示类似信息:

加载 "D:\HARDWARE\Milandr\\new_project_1\Objects\\new_project_1.axf" 
* JLink Info: Device "CORTEX-M3" selected.
将 JLink 项目文件设置为 "D:\HARDWARE\Milandr\new_project_1\JLinkSettings.ini"。
* JLink Info: Device "CORTEX-M3" selected.
 
JLink 信息:
------------
DLL: V8.12a, 已编译 2025 年 1 月 9 日 14:34:24
固件:J-Link ARM V8,已编译 2014 年 11 月 28 日 13:44:46
硬件:V8.00
功能:RDI,FlashDL,FlashBP,JFlash,GDB 
 
* JLink Info: Found SW-DP with ID 0x2BA01477
* JLink Info:检测到 DPv0
* JLink Info: CoreSight SoC-400 或更早版本
* JLink Info:扫描 AP 地图以找到所有可用 AP
* JLink Info: AP[1]: 停止 AP 扫描,因为已到达 AP 地图的尽头
* JLink Info: AP[0]: AHB-AP (IDR: 0x24770011, ADDR: 0x00000000)
* JLink Info:遍历 AP 映射以找到要使用的 AHB-AP
* JLink Info: AP[0]: Core found
* JLink Info: AP[0]: AHB-AP ROM base: 0xE00FF000
* JLink Info: CPUID 寄存器: 0x412FC230。实现者代码:0x41(ARM)
* JLink Info: Found Cortex-M3 r2p0, Little endian.
* JLink Info:FPUnit:6 个代码 (BP) 插槽和 2 个字面插槽
* JLink Info: CoreSight 组件:
* JLink Info: ROMTbl[0] @ E00FF000
* JLink Info: [0][0]: E000E000 CID B105E00D PID 002BB000 SCS
* JLink Info: [0][1]: E0001000 CID B105E00D PID 002BB002 DWT
* JLink Info: [0][2]: E0002000 CID B105E00D PID 002BB003 FPB
* JLink Info: [0][3]: E0000000 CID B105E00D PID 002BB001 ITM
* JLink Info: [0][4]: E0040000 CID B105900D PID 002BB923 TPIU-Lite
ROMTableAddr = 0xE00FF000
* JLink Info: Reset type: NORMAL (https://wiki.segger.com/J-Link_Reset_Strategies)
* JLink Info: Reset: Halt core after reset via DEMCR.VC_CORERESET.
* JLink Info: Reset: 通过 AIRCR.SYSRESETREQ 复位设备。
 
目标信息:
------------
器件:MDR1986BE91
目标电压 = 3.319V
引脚状态: 
Tck: 1,TDI: 1,TDO: 0,TMS: 1,TRES: 1,TRST: 1
硬件断点: 6
软件断点: 8192
观察点: 4
JTAG 速度: 2000 kHz
 
* JLink 信息:内存映射 "启动完成点后 "处于活动状态
全芯片擦除完成。
编程完成。
验证确定。
* JLink Info:"启动完成点之前 "的内存映射处于活动状态。
* JLink Info: Reset type: NORMAL (https://wiki.segger.com/J-Link_Reset_Strategies)
* JLink 信息:复位:通过 DEMCR.VC_CORERESET 复位后停止内核。
* JLink Info: Reset:通过 AIRCR.SYSRESETREQ 重置设备。
* JLink Info:内存映射 "启动完成点后 "处于活动状态。
应用程序正在运行 ...
闪存加载于 10:40:49 完成

在微控制器上执行代码

下载完成后,代码会自动在控制器上运行,这可以通过电路板上的运行指示灯来验证:

running_light_4.gif

加载的代码会执行 Engee 模型给出的算法。

输出

在本示例中,我们使用Engee 有限自动机库时序运算符 开发了一个重现 "跑马灯 "算法的 Engee 模型,从该模型中生成代码,并通过组装该项目和从 Keil μVision 环境将其加载到 Milandr 1986BE91T 微控制器上验证了其运行。

示例中使用的块