4.1. 模块导入

嵌入式的运行环境和 PC 有明显区别,在很多的场景下,MCU 甚至没有文件系统。

不过不用担心,PikaScript 已经通过官方自带的工具帮助你轻松的导入模块,你需要做的仅仅是写一行 import,就像平时在 PC 使用 Python 一样。

和 PC 的 Python 不一样的地方仅在于,在用编译器编译 PikaScript 的工程之前,需要运行一次 PikaScript 提供的预编译器(没有什么复杂的参数和选项,仅仅是双击运行)。

4.1.1. 导入 Python 模块

PikaScript 支持导入多个 Python 文件作为模块,而且不需要在 MCU 里面移植文件系统(如果你想基于文件系统,当然也可以)。

PikaScript 的预编译器可以将 Python 文件在 PC 开发机就转换成字节码并打包成一个库,就像是 C 一样。

这样一来,在资源很少的 MCU 里面,就可以省去文件系统的花销了 (通常需要 20kB 的 ROM)。

另一方面,如果你想快速在新平台尝试 PikaScript,也不需要先费一番功夫为新平台移植文件系统,然后再将文件系统和 PikaScript 对接。

(注意,需要内核版本不低于 v1.8.0)

4.1.1.1. 实验

我们仍然以 keil 的仿真工程作为实验平台,这样不需要硬件即可快速实验。

首先参考 keil 的仿真工程文档,获得工程。

然后在 pikascript_simulation-keil/pikascript/ 目录下新建一个 test.py 的 Python 文件 (所有的 Python 模块都要放在这个目录)。

_images/image-20220620175202212.png

然后在 test.py 里面写入测试代码:

  1. # test.py
  2. def mytest():
  3. print('hello from test.py!')
  4. def add(a, b):
  5. return a + b

接着在 main.py 里面引入 test.py,并测试我们在 test.py 里面定义的函数 mytest() 和 add()

  1. import Device
  2. import PikaStdLib
  3. import PikaStdData
  4. import hello
  5. import test
  6. print('test start...')
  7. test.mytest()
  8. print(test.add(3, 5))
  9. print('test end...')

然后直接在 keil 工程里面编译,会发现在开始编译 .c 文件之前,出现了 PikaScript Compiler 的提示信息,包括编译了 test.py。

_images/image-20220620175646395.png

这是因为已经自动运行了 PikaScript 的预编译器,这是一项 Keil 提供的设置,能够在编译开始前执行一段脚本,包括运行 PikaScript 的预编译器。

_images/image-20220620175845943.png

然后我们开始调试运行,打开串口窗口就能看到结果了

_images/image-20220620175959680.png

如果你对原理感兴趣,可以观看 讲解视频

4.1.2. 导入 C 模块

C 模块指的是底层用 C 实现,却仍然可以用 Python 调用的模块。

一个名为 <module> 的C 模块通常由一个 <module>.pyi 文件 (python 的接口文件)和 pikascript-lib/<module> 文件夹组成。

PikaScript 导入 C 模块和导入 Python 模块的方法一样,直接 import,然后运行预编译即可。

在预编译后,还会自动生成一些模块连接文件,所有的模块连接文件都在 pikascript-api 文件夹。因此在引入 C 模块之后,还需要将下面列出的文件添加到工程里参与编译:

  • pikascript-lib/<module> 文件夹下的所有 .c 文件

  • pikascript-api 文件夹下的所有 .c 文件

4.1.2.1. 实验

我们仍然以 keil 的仿真工程作为实验平台。

我们在 main.py 里面引入 PikaStdData.pyi C 模块。

我们打开 PikaStdData.pyi 查看这个 C 模块提供的类和函数。

  1. # PikaStdData.pyi
  2. from PikaObj import *
  3. class List(TinyObj):
  4. def __init__(self): ...
  5. # add an arg after the end of list
  6. def append(self, arg: any): ...
  7. # get an arg by the index
  8. def get(self, i: int) -> any: ...
  9. # set an arg by the index
  10. def set(self, i: int, arg: any): ...
  11. # get the length of list
  12. def len(self) -> int: ...
  13. ...

可以看到里面有一个 List 类。

在 main.py 里面引入 PikaStdData 并通过 List 类新建一个对象 list,然后再测试一下 Listappend()方法,和 get() 方法。

  1. import PikaStdLib
  2. import PikaStdData
  3. print('test start...')
  4. list = PikaStdData.List()
  5. list.append(1)
  6. list.append('test')
  7. list.append(2.34)
  8. print(list.get(0))
  9. print(list.get(1))
  10. print(list.get(2))
  11. print('test end...')

编译时可以看到 PikaScript 的预编译器将 PikaStdData C 模块绑定到了工程里面。

_images/image-20220620191019013.png

仿真运行可以看到结果

_images/image-20220620191048505.png

用户也可以自己制作 C 模块,需要做的就是编写 <module>.pyi Python 接口文件和 pikascript-lib/<module> 里面的 .c 实现文件。

具体请参考C 模块的制作文档