问题描述
还在为 K230 的硬件功能调用发愁?想让传感器、外设轻松接入 MicroPython 生态?
这波干货请收好 —— 从零开始的接口封装指南来啦!跟着操作,你也能把自定义硬件功能打包成简洁的 MicroPython 接口,让代码像这样清爽:
import your_module
dev = your_module.init()
dev.read_data()
一、 硬件准备
- a. PC
- b. K230 开发板
二、 软件准备
- a. Ubuntu20.04 的虚拟机或Linux
- b. 参考 k230 SDK 手册拉取Canmv K230 源码: https://www.kendryte.com/k230_canmv/zh/main/zh/userguide/how_to_build.html
三、软件框架

四、用一个例子告诉你怎么添加
在 canmv/port/ 下创建新的文件夹 mymodules ,存放自己定义的模块 .C 文件
1.添加 mymod.c 创建自己的基本模块
// 添加实现micropython模块的必要头文件
#include"py/obj.h"
#include"py/runtime.h"
// 定义 printHelloWorld 函数,用于打印 "Hello World! -- [name]"
STATIC mp_obj_t printHelloWorld(mp_obj_t name){
// 使用 mp_printf 打印字符串,并获取传入的 name 参数的字符串值
mp_printf(&mp_plat_print, "Hello World! -- %s\n", mp_obj_str_get_str(name));
// 返回 mp_const_none 表示没有返回值
return mp_const_none;
}
// 定义 printHelloWorld 函数为 MicroPython 的一个函数对象,接受 1 个参数
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mymodules_printHelloWorld_obj, printHelloWorld);
// 定义 addNumbers 函数,用于对传入的多个数字进行求和
STATIC mp_obj_t addNumbers(size_t n_args, const mp_obj_t *args){
int result = 0;
// 遍历所有传入的参数并进行求和
for (size_t i = 0; i < n_args; i++) {
result += mp_obj_get_int(args[i]);
}
// 返回求和结果,作为 MicroPython 的整数对象
return mp_obj_new_int(result);
}
// 定义 addNumbers 函数为 MicroPython 的一个函数对象,接受 2 到 4 个参数
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mymodules_addNumbers_obj, 2, 4, addNumbers);
// 定义模块的全局变量表,包含模块名、方法和类等
STATIC const mp_rom_map_elem_t mymodules_module_globals_table[] = {
// 定义模块名 -- mymodules
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mymodules) },
// 绑定方法 sayHi 到 printHelloWorld 函数对象
{ MP_ROM_QSTR(MP_QSTR_sayHi), MP_ROM_PTR(&mymodules_printHelloWorld_obj) },
// 绑定方法 add 到 addNumbers 函数对象
{ MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&mymodules_addNumbers_obj) },
};
// 定义 mymodules_globals_table 为一个常量字典,包含模块的全局变量表
STATIC MP_DEFINE_CONST_DICT(mymodules_globals_table, mymodules_module_globals_table);
// 定义 mp_module_mymodules 对象,表示整个模块
const mp_obj_module_t mp_module_mymodules = {
.base = { &mp_type_module }, // 设置模块的基础类型为 mp_type_module
.globals = (mp_obj_dict_t*)&mymodules_globals_table, // 设置模块的全局变量表
};
// 注册模块到 MicroPython 模块系统中,模块名为 mymodules
MP_REGISTER_MODULE(MP_QSTR_mymodules, mp_module_mymodules);
2. 在 canmv/port/Makefile 中添加 mymodules 文件夹的编译

3. 最后在 SDK 根目录执行 make canmv 重新编译 canmv模块
将编译得到的 output/canmv/micropython 替换掉 sd 卡内的 sdcard/micropython 文件重新开机即可完成 micropython 更新。
五、运行
成功添加 mymodules 模块。

六、对mymod.c 文件的说明
1.包含必要的头文件
#include"py/obj.h"
#include"py/runtime.h"
这两个头文件是 MicroPython C API 的核心:
- py/obj.h:定义了 MicroPython 对象系统的基础结构
- py/runtime.h:提供了运行时功能,如内存管理、解释器状态等
2. 定义C函数
STATIC mp_obj_t printHelloWorld(mp_obj_t name){
mp_printf(&mp_plat_print, "Hello World! -- %s\n", mp_obj_str_get_str(name));
return mp_const_none;
}
STATIC mp_obj_t addNumbers(size_t n_args, const mp_obj_t *args){
int result = 0;
for (size_t i = 0; i < n_args; i++) {
result += mp_obj_get_int(args[i]);
}
return mp_obj_new_int(result);
}
这里定义了两个C函数:
a. printHelloWorld:实现 HelloWorld + 输入字符串的打印输出
-
mp_obj_t :返回类型为通用对象指针(所有 MicroPython C 函数都使用mp_obj_t类型)
-
mp_obj_str_get_str() : 将 Python 对象 (mp_obj_t) 转换为 C 字符串 (char*)类型
-
return mp_const_none; :表示无返回值或返回值为空值
b. addNumbers :多个参数输入的函数相加,返回结果
-
n_args:传入的参数数量
-
*args:参数对象数组,按顺序存储传入的参数
-
mp_obj_get_int() :将 Python 对象 (mp_obj_t) 类型转换为 C 整型
-
mp_obj_new_int() :将 C 整型转换为 Python 对象 (mp_obj_t) 类型
3. 注册C函数对象
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mymodules_printHelloWorld_obj, printHelloWorld);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mymodules_addNumbers_obj, 2, 4, addNumbers);
a. MP_DEFINE_CONST_FUN_OBJ_1 :宏定义,用于注册带 1 个参数的函数
- 第二个参数:关联的 C 函数名
- 第一个参数:生成的函数对象名称
b. MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN :宏定义,用于注册参数数量可变的函数
- 第四个参数:关联的 C 函数名
- 第一个参数:生成的函数对象名称
- 第二个参数:最小参数数量
- 第三个参数:最大参数数量
c. 其他注册函数定义:(参数定义与 MP_DEFINE_CONST_FUN_OBJ_1 一致)
- MP_DEFINE_CONST_FUN_OBJ_0 :注册带 0 个参数输入的函数
- MP_DEFINE_CONST_FUN_OBJ_2 :注册带 2 个参数输入的函数
- MP_DEFINE_CONST_FUN_OBJ_3 :注册带 3 个参数输入的函数
4. 定义全局变量表
STATIC const mp_rom_map_elem_t mymodules_module_globals_table[] = {
// 定义模块名 -- mymodules
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mymodules) },
// 绑定方法sayHi
{ MP_ROM_QSTR(MP_QSTR_sayHi), MP_ROM_PTR(&mymodules_printHelloWorld_obj) },
// 绑定方法add
{ MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&mymodules_addNumbers_obj) },
};
a. 定义全局变量表:mymodules_module_globals_table
b. 模块元信息:
- MP_QSTR_mymodules :表示模块的实际名称为 mymodules,决定import时的标识符
- MP_QSTR___name__ :固定 QSTR,表示 Python 模块的name属性
c. 函数绑定机制: - 参数:C 函数对象(步骤3定义)的指针
- MP_ROM_PTR(&mymodules_printHelloWorld_obj) :定义与前面方法对应的 C 函数对象的指针
- 参数:MP_QSTR_ + "方法名称"
- MP_ROM_QSTR(MP_QSTR_sayHi) :定义Python 中调用的方法名称 (sayHi)
通过绑定,在 Python 中使用相应方法即调用对应的 C 实现:
(mymodules.sayHi → mymodules_printHelloWorld_obj → printHelloWorld )
(mymodules.add → mymodules_addNumbers_obj → addNumbers )
5. 定义模块全局字典,将全局变量表封装为一个常量字典对象
// 定义模块的全局变量表,包含模块名、方法和类等
STATIC MP_DEFINE_CONST_DICT(mymodules_globals_table, mymodules_module_globals_table);
a. 第一个参数:生成的字典对象名 -- my_modules_globals_tabel ,将作为模块的全局命名空间
b. 第二个参数:全局变量表(步骤4定义) -- mymodules_module_globals_table
6. 定义模块对象
const mp_obj_module_t mp_module_mymodules = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mymodules_globals_table,
};
模块对象定义
- 创建 mp_obj_module_t类型的模块对象mp_module_mymodules
- .base字段设置为模块类型的基类
- .globals字段指向定义的全局变量字典
7.注册模块
MP_REGISTER_MODULE(MP_QSTR_mymodules, mp_module_mymodules);
MP_REGISTER_MODULE :
- 第一个参数:模块的 QSTR 名称(步骤4定义)
- 第二个参数:模块对象(步骤6定义)