??MicroPython 是Python 3编程语言的精简高效实现, 其中包含 Python 标准库的一小部分,并针对在单片机和受限环境中运行进行了优化。MicroPython遵循python的语法规则。当我们想要添加MicroPython模块时,一般有两种方法,一种是用python脚本编写,一种是用C语言编写。python脚本编写时更方便,更快捷,但是功能受限,灵活度受限。用C语言编写,然后编译进固件,更灵活,自由度更大,但是难度也更大。如果想要编写一些更加贴近底层的模块,例如直接操作寄存器来控制单片机做某种功能,然后暴露给Python层,被Python直接调用,则必须用C语言编写MicroPython模块。 ??MicroPython的官网为https://micropython.org/,源代码在github上,地址为:https://github.com/micropython/micropython。 ??MicroPython可以调用不同的模块(module),这些模块可以包含变量函数,以及类型等。在MicroPython中可以使用help()函数查看简单的帮助。例如在REPL下直接输入help(),可以显示基本的帮助界面,以ESP32的MicroPython为例,显示如下:
Welcome to MicroPython on the ESP32!
For generic online docs please visit http://docs.micropython.org/
For access to the hardware use the 'machine' module:
import machine
pin12 = machine.Pin(12, machine.Pin.OUT)
pin12.value(1)
pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)
print(pin13.value())
i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))
i2c.scan()
i2c.writeto(addr, b'1234')
i2c.readfrom(addr, 4)
Basic WiFi configuration:
import network
sta_if = network.WLAN(network.STA_IF); sta_if.active(True)
sta_if.scan()
sta_if.connect("<AP_name>", "<password>")
sta_if.isconnected()
Control commands:
CTRL-A -- on a blank line, enter raw REPL mode
CTRL-B -- on a blank line, enter normal REPL mode
CTRL-C -- interrupt a running program
CTRL-D -- on a blank line, do a soft reset of the board
CTRL-E -- on a blank line, enter paste mode
For further help on a specific object, type help(obj)
For a list of available modules, type help('modules')
??通过输入help(‘modules’),可以查看运行的固件里面MicroPython 支持的所有固件
__main__ flashbdev select ujson
_boot framebuf socket uos
_onewire gc ssl urandom
_thread hashlib struct ure
_webrepl heapq sys uselect
apa106 inisetup time usocket
array io ubinascii ussl
binascii json ucollections ustruct
btree machine ucryptolib utime
builtins math uctypes utimeq
cmath micropython uerrno uzlib
collections network uhashlib websocket
errno os uhashlib zlib
esp random uheapq
esp32 re uio
Plus any modules on the filesystem
一、help(‘modules’)运行的C语言流程
??在MicroPython 源码的builtinhelp.c文件里面有mp_builtin_help函数,该函数的作用是创建内部的help功能。
STATIC mp_obj_t mp_builtin_help(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
mp_print_str(MP_PYTHON_PRINTER, MICROPY_PY_BUILTINS_HELP_TEXT);
} else {
mp_help_print_obj(args[0]);
}
return mp_const_none;
}
??当调用mp_builtin_help函数时,如果没有传入参数,则打印帮助文档,帮助文档为MICROPY_PY_BUILTINS_HELP_TEXT。在mpconfig.h文件内有
#ifndef MICROPY_PY_BUILTINS_HELP_TEXT
#define MICROPY_PY_BUILTINS_HELP_TEXT mp_help_default_text
#endif
??而在mpconfigport.h文件内又有如下定义:
#define MICROPY_PY_BUILTINS_HELP_TEXT esp32_help_text
??说明如果宏定义MICROPY_PY_BUILTINS_HELP_TEXT 没有定义,则MICROPY_PY_BUILTINS_HELP_TEXT 指向的是mp_help_default_text,否则指向的是esp32_help_text。esp32_help_text就是上面当输入help()时打印的字符串数组。 ??如果调用mp_builtin_help函数时传入了参数参数,则会执行mp_help_print_obj函数。mp_help_print_obj函数定义如下:
STATIC void mp_help_print_obj(const mp_obj_t obj) {
#if MICROPY_PY_BUILTINS_HELP_MODULES
if (obj == MP_OBJ_NEW_QSTR(MP_QSTR_modules)) {
mp_help_print_modules();
return;
}
#endif
mp_obj_type_t *type = mp_obj_get_type(obj);
mp_print_str(MP_PYTHON_PRINTER, "object ");
mp_obj_print(obj, PRINT_STR);
mp_printf(MP_PYTHON_PRINTER, " is of type %q\n", type->name);
mp_map_t *map = NULL;
if (type == &mp_type_module) {
map = &mp_obj_module_get_globals(obj)->map;
} else {
if (type == &mp_type_type) {
type = MP_OBJ_TO_PTR(obj);
}
if (type->locals_dict != NULL) {
map = &type->locals_dict->map;
}
}
if (map != NULL) {
for (uint i = 0; i < map->alloc; i++) {
if (map->table[i].key != MP_OBJ_NULL) {
mp_help_print_info_about_object(map->table[i].key, map->table[i].value);
}
}
}
}
??该函数的内容就是打印所有的module,还是打印引入的module。打印所有的module调用的是mp_help_print_modules函数,mp_help_print_modules函数定义如下:
STATIC void mp_help_print_modules(void) {
mp_obj_t list = mp_obj_new_list(0, NULL);
mp_help_add_from_map(list, &mp_builtin_module_map);
#if MICROPY_MODULE_WEAK_LINKS
mp_help_add_from_map(list, &mp_builtin_module_weak_links_map);
#endif
#if MICROPY_MODULE_FROZEN_STR
extern const char mp_frozen_str_names[];
mp_help_add_from_names(list, mp_frozen_str_names);
#endif
#if MICROPY_MODULE_FROZEN_MPY
extern const char mp_frozen_mpy_names[];
mp_help_add_from_names(list, mp_frozen_mpy_names);
#endif
mp_obj_list_sort(1, &list, (mp_map_t*)&mp_const_empty_map);
#define NUM_COLUMNS (4)
#define COLUMN_WIDTH (18)
size_t len;
mp_obj_t *items;
mp_obj_list_get(list, &len, &items);
unsigned int num_rows = (len + NUM_COLUMNS - 1) / NUM_COLUMNS;
for (unsigned int i = 0; i < num_rows; ++i) {
unsigned int j = i;
for (;;) {
int l = mp_print_str(MP_PYTHON_PRINTER, mp_obj_str_get_str(items[j]));
j += num_rows;
if (j >= len) {
break;
}
int gap = COLUMN_WIDTH - l;
while (gap < 1) {
gap += COLUMN_WIDTH;
}
while (gap--) {
mp_print_str(MP_PYTHON_PRINTER, " ");
}
}
mp_print_str(MP_PYTHON_PRINTER, "\n");
}
mp_print_str(MP_PYTHON_PRINTER, "Plus any modules on the filesystem\n");
}
??mp_help_print_modules函数利用mp_help_add_from_map函数和mp_help_add_from_names函数将整个MicroPython系统可用的module全部组合加到了一起存储到了结构体list里面,然后逐个打印list里面的module。
二、C语言编写的模块的(module)分类及添加
??在mp_help_print_modules函数里面一共增加了四次module,内容如下:
mp_help_add_from_map(list, &mp_builtin_module_map);
#if MICROPY_MODULE_WEAK_LINKS
mp_help_add_from_map(list, &mp_builtin_module_weak_links_map);
#endif
#if MICROPY_MODULE_FROZEN_STR
extern const char mp_frozen_str_names[];
mp_help_add_from_names(list, mp_frozen_str_names);
#endif
#if MICROPY_MODULE_FROZEN_MPY
extern const char mp_frozen_mpy_names[];
mp_help_add_from_names(list, mp_frozen_mpy_names);
#endif
??这些编译进内核的模块(module),有C语言编写的 ,也有Python语言编写的。其中mp_builtin_module_map和mp_builtin_module_weak_links_map都是用C语言编写的模块。
2.1、mp_builtin_module_weak_links_map
??mp_builtin_module_weak_links_map的定义如下
#if MICROPY_MODULE_WEAK_LINKS
STATIC const mp_rom_map_elem_t mp_builtin_module_weak_links_table[] = {
MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS
};
MP_DEFINE_CONST_MAP(mp_builtin_module_weak_links_map, mp_builtin_module_weak_links_table);
#endif
??mp_builtin_module_weak_links_map最终指向的是宏定义MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS。
2.2、mp_builtin_module_map
??mp_builtin_module_map的定义如下:
STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
{ MP_ROM_QSTR(MP_QSTR___main__), MP_ROM_PTR(&mp_module___main__) },
{ MP_ROM_QSTR(MP_QSTR_builtins), MP_ROM_PTR(&mp_module_builtins) },
{ MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_module_micropython) },
#if MICROPY_PY_ARRAY
{ MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_module_array) },
#endif
#if MICROPY_PY_IO
{ MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) },
#endif
#if MICROPY_PY_COLLECTIONS
{ MP_ROM_QSTR(MP_QSTR_ucollections), MP_ROM_PTR(&mp_module_collections) },
#endif
#if MICROPY_PY_STRUCT
{ MP_ROM_QSTR(MP_QSTR_ustruct), MP_ROM_PTR(&mp_module_ustruct) },
#endif
#if MICROPY_PY_BUILTINS_FLOAT
#if MICROPY_PY_MATH
{ MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) },
#endif
#if MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH
{ MP_ROM_QSTR(MP_QSTR_cmath), MP_ROM_PTR(&mp_module_cmath) },
#endif
#endif
#if MICROPY_PY_SYS
{ MP_ROM_QSTR(MP_QSTR_sys), MP_ROM_PTR(&mp_module_sys) },
#endif
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
{ MP_ROM_QSTR(MP_QSTR_gc), MP_ROM_PTR(&mp_module_gc) },
#endif
#if MICROPY_PY_THREAD
{ MP_ROM_QSTR(MP_QSTR__thread), MP_ROM_PTR(&mp_module_thread) },
#endif
#if MICROPY_PY_UERRNO
{ MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) },
#endif
#if MICROPY_PY_UCTYPES
{ MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) },
#endif
#if MICROPY_PY_UZLIB
{ MP_ROM_QSTR(MP_QSTR_uzlib), MP_ROM_PTR(&mp_module_uzlib) },
#endif
#if MICROPY_PY_UJSON
{ MP_ROM_QSTR(MP_QSTR_ujson), MP_ROM_PTR(&mp_module_ujson) },
#endif
#if MICROPY_PY_URE
{ MP_ROM_QSTR(MP_QSTR_ure), MP_ROM_PTR(&mp_module_ure) },
#endif
#if MICROPY_PY_UHEAPQ
{ MP_ROM_QSTR(MP_QSTR_uheapq), MP_ROM_PTR(&mp_module_uheapq) },
#endif
#if MICROPY_PY_UTIMEQ
{ MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&mp_module_utimeq) },
#endif
#if MICROPY_PY_UHASHLIB
{ MP_ROM_QSTR(MP_QSTR_uhashlib), MP_ROM_PTR(&mp_module_uhashlib) },
#endif
#if MICROPY_PY_UCRYPTOLIB
{ MP_ROM_QSTR(MP_QSTR_ucryptolib), MP_ROM_PTR(&mp_module_ucryptolib) },
#endif
#if MICROPY_PY_UBINASCII
{ MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) },
#endif
#if MICROPY_PY_URANDOM
{ MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_module_urandom) },
#endif
#if MICROPY_PY_USELECT
{ MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) },
#endif
#if MICROPY_PY_USSL
{ MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) },
#endif
#if MICROPY_PY_LWIP
{ MP_ROM_QSTR(MP_QSTR_lwip), MP_ROM_PTR(&mp_module_lwip) },
#endif
#if MICROPY_PY_WEBSOCKET
{ MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&mp_module_websocket) },
#endif
#if MICROPY_PY_WEBREPL
{ MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) },
#endif
#if MICROPY_PY_FRAMEBUF
{ MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) },
#endif
#if MICROPY_PY_BTREE
{ MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) },
#endif
MICROPY_PORT_BUILTIN_MODULES
};
MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);
??mp_builtin_module_map指向的的是一个名字为mp_builtin_module_table的结构体数组,该数组内存储量大量的模块定义,其中宏定义MICROPY_PORT_BUILTIN_MODULES是跟端口密切相关的,及跟平台单片机密切相关的。
三、与硬件平台相关的模块
??与硬件平台密切相关的固件都存储在宏定义MICROPY_PORT_BUILTIN_MODULES和宏定义MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS中。这两个宏定义的定义在mpconfigport.h文件内,以ESP32为例:
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_collections), (mp_obj_t)&mp_module_collections }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_hashlib), (mp_obj_t)&mp_module_uhashlib }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_heapq), (mp_obj_t)&mp_module_uheapq }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_io), (mp_obj_t)&mp_module_io }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&mp_module_urandom }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlib), (mp_obj_t)&mp_module_uzlib }, \
??我们编写的模块可以添加到MICROPY_PORT_BUILTIN_MODULES宏定义的后面,这样在系统加载模块式,我们的模块就可以被加载进去了。
|