前面已经将MicroPython移植到了LPC1788,其中的一些功能已经可以使用。但是片上外设、板载外设还不能访问,需要我们去实现,然后才能在MicroPython中访问。官方文档MicroPython external C modules中对这部分有说明,比较简单。下面通过实战来进一步理解这部分文档。
添加源文件
第一步肯定是创建源文件了,给它命名为machine.c。
并添加到MakeFile里边,不然是不会被编译的。
SRC_C = \
main.c \
uart_core.c \
...
./modules/machine.c
...
创建一个Module
源文件已经建好,接下来就是编码了。在MicroPython中,modules是有确定的结构的。可以把这个结构理解为模板,跟着模板走,总没有错的。先来看看这个模板:
#include "py/obj.h"
#include "py/runtime.h"
#include "py/builtin.h"
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine)},
};
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
const mp_obj_module_t machine_module = {
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&machine_module_globals,
};
上面这部分代码使用mp_obj_module_t类型定义了一个module,并初始化了相关的部分,如基本类型、模块的字典。在字典中,定义了__name__,为machine,这个就是我们这个module的名字。
为了让这个模块能在MicroPython中被import,需要将模块添加到mpconfigport.h的MICROPY_PORT_BUILTIN_MODULES中。注意:不是MICROPY_PORT_BUILTINS!!!
// extra built in modules to add to the list of known ones
extern const struct _mp_obj_module_t machine_module; // 注意_mp_obj_module_t是带下划线前缀的
#define MICROPY_PORT_BUILTIN_MODULES \
{MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module)},
编译并烧录,在MicroPython中使用import machine测试是否成功,不报错就是成功了。
添加一个Function
现在,我们可以添加一个函数到这个模块里面。首先定义一个函数,这里以reset函数来具体说明。
STATIC mp_obj_t machine_reset(void)
{
NVIC_SystemReset();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
这段代码创建了一个名为machine_reset_obj的函数对象,该函数没有参数,被调用时会执行C函数machine_reset。此外,所有的Python函数都必须返回一个mp_obj_t结构对象,但是我们这没有什么可返回的,因此返回None。接下来将这个函数添加到前面创建好的module中。
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine)},
{MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj)},
};
好了,编译看看。报错了,提示下面的信息
In file included from modules/machine.c:1:0:
modules/machine.c:17:18: error: 'MP_QSTR_sys_reset' undeclared here (not in a function)
{MP_ROM_QSTR(MP_QSTR_sys_reset), MP_ROM_PTR(&machine_reset_obj)},
^
../../py/obj.h:92:56: note: in definition of macro 'MP_OBJ_NEW_QSTR'
#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2))
^
modules/machine.c:17:6: note: in expansion of macro 'MP_ROM_QSTR'
{MP_ROM_QSTR(MP_QSTR_sys_reset), MP_ROM_PTR(&machine_reset_obj)},
^
make: *** [build/./modules/machine.o] Error 1
其实上面的操作还缺少一个步骤,就是在qstrdefsport.h.中定义一个Q(reset),再编译就OK了。
Function的参数
前面添加一个函数时使用了MP_DEFINE_CONST_FUN_OBJ_0宏来定义一个不带参数的函数。同样也可以定义一个或多个参数的函数。下面列举出所有支持的类型,具体的使用方法不细说,可以查看各个移植的例子。
宏
说明
MP_DEFINE_CONST_FUN_OBJ_0
不带参数的函数
MP_DEFINE_CONST_FUN_OBJ_1
只有1个参数的函数
MP_DEFINE_CONST_FUN_OBJ_2
有2个参数的函数
MP_DEFINE_CONST_FUN_OBJ_3
有3个参数的函数
MP_DEFINE_CONST_FUN_OBJ_VAR
带可变参数的函数
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN
跟上面类似,但是参数个数有范围
MP_DEFINE_CONST_FUN_OBJ_KW
带关键字参数的函数
在MicroPython中使用Module
import machine # 添加的module的名字叫‘machine’,要使用这个模块首先得导入它
machine.reset() # 调用这个模块的函数