在MicroPython中调用C接口封装自定义模块
要将C语言代码封装为MicroPython模块,需要按照以下步骤操作:
1. 编写C语言功能代码
// example_module.c
#include "py/runtime.h"
// 加法函数(带整数检查)
STATIC mp_obj_t example_add(mp_obj_t a_obj, mp_obj_t b_obj) {
// 检查参数类型
if (!mp_obj_is_int(a_obj) || !mp_obj_is_int(b_obj)) {
mp_raise_TypeError("arguments must be integers");
}
long a = mp_obj_get_int(a_obj);
long b = mp_obj_get_int(b_obj);
return mp_obj_new_int(a + b);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_obj, example_add);
// 返回字符串的函数
STATIC mp_obj_t example_get_string(void) {
return mp_obj_new_str("Hello from C module!", 20);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_get_string_obj, example_get_string);
// 模块全局函数表
STATIC const mp_rom_map_elem_t example_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example) },
{ MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&example_add_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_string), MP_ROM_PTR(&example_get_string_obj) },
};
STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);
// 模块定义结构体
const mp_obj_module_t example_user_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&example_module_globals,
};
// 注册模块
MP_REGISTER_MODULE(MP_QSTR_example, example_user_module, MODULE_EXAMPLE_ENABLED);
2. 配置MicroPython编译环境
2.1 添加新模块到工程
将.c文件放入MicroPython源代码的合适位置,例如ports/stm32/user_modules/目录。
2.2 修改编译配置
在ports/stm32/mpconfigport.h中添加:
// 启用自定义模块
#define MODULE_EXAMPLE_ENABLED (1)
// 声明外部模块
extern const struct _mp_obj_module_t example_user_module;
2.3 修改Makefile
在相应端口的Makefile中添加你的模块源文件:
SRC_USERMOD += user_modules/example_module.c
3. 编译并烧写固件
# 在端口目录中执行(例如 ports/stm32)
make clean
make
使用你的设备特定方法烧写新固件。
4. 在MicroPython中使用模块
import example
# 使用加法函数
result = example.add(10, 20)
print(f"10 + 20 = {result}") # 输出: 10 + 20 = 30
# 获取字符串
text = example.get_string()
print(text) # 输出: Hello from C module!
# 错误处理示例
try:
example.add("str", 20)
except TypeError as e:
print(f"Caught error: {e}") # 输出: Caught error: arguments must be integers
深入封装:添加C结构到MicroPython对象
// 添加自定义对象类型示例
typedef struct _example_custom_obj_t {
mp_obj_base_t base; // 基础对象
int value; // 自定义数据
} example_custom_obj_t;
// 创建新对象
STATIC mp_obj_t example_make_custom(mp_obj_t val_obj) {
example_custom_obj_t *o = m_new_obj(example_custom_obj_t);
o->base.type = &example_custom_type;
o->value = mp_obj_get_int(val_obj);
return MP_OBJ_FROM_PTR(o);
}
// 成员函数:增加值
STATIC mp_obj_t custom_increase(mp_obj_t self_in) {
example_custom_obj_t *self = MP_OBJ_TO_PTR(self_in);
self->value++;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(custom_increase_obj, custom_increase);
// 成员函数:获取值
STATIC mp_obj_t custom_get_value(mp_obj_t self_in) {
example_custom_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_int(self->value);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(custom_get_value_obj, custom_get_value);
// 自定义对象方法表
STATIC const mp_rom_map_elem_t custom_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_increase), MP_ROM_PTR(&custom_increase_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_value), MP_ROM_PTR(&custom_get_value_obj) },
};
STATIC MP_DEFINE_CONST_DICT(custom_locals_dict, custom_locals_dict_table);
// 自定义对象类型定义
const mp_obj_type_t example_custom_type = {
{ &mp_type_type },
.name = MP_QSTR_Custom,
.locals_dict = (mp_obj_dict_t *)&custom_locals_dict,
};
// 在模块中添加构造函数
STATIC const mp_rom_map_elem_t example_module_globals_table[] = {
// ... 其他项目 ...
{ MP_ROM_QSTR(MP_QSTR_Custom), MP_ROM_PTR(&example_make_custom) },
// ... 其他项目 ...
};
错误处理最佳实践
- 使用
mp_raise_TypeError验证参数类型
- 使用
mp_raise_ValueError处理无效值
- 使用
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ...)处理系统错误
参考资料
- MicroPython官方文档: Adding a new module
- MicroPython源码示例:
ports/stm32/user_modules
- Python/C API转换: MicroPython object API
注意:具体编译步骤可能因目标硬件平台(ESP32, STM32, Raspberry Pi Pico等)而异,请参考对应平台的端口说明。