C语言开发MicroPython模块(添加module)

2023-11-10

  MicroPython添加模块框架模式相对简单,只需要按照定义好的固定框架就可以添加模块(module)。

一、向固件里面添加module

1.1、编写mymodule.c文件

  在ports/esp32文件夹下新建一个文件mymodule.c ,文件内输入如下内容:

#include "stdint.h"
#include "stdio.h"
#include "py/obj.h"
#include "py/runtime.h"

STATIC mp_obj_t mp_my_test_function(mp_obj_t myms)
 {
     uint32_t Myms = mp_obj_get_int(myms);
     vTaskDelay(Myms / portTICK_PERIOD_MS);
 	return mp_const_none;
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(My_mp_my_test_function, mp_my_test_function);

STATIC const mp_rom_map_elem_t modnormal_globals_table[] = {
    {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_my_test_module)},   
    {MP_OBJ_NEW_QSTR(MP_QSTR_mytestfunction), MP_ROM_PTR(&My_mp_my_test_function)}, 
    {MP_OBJ_NEW_QSTR(MP_QSTR_test), MP_ROM_PTR(&modnormal_test_type)},

};

STATIC MP_DEFINE_CONST_DICT(mp_module_modnormal_globals, modnormal_globals_table);   
const mp_obj_module_t mp_module_my_test_mod = {
    .base = {&mp_type_module},    
    .globals = (mp_obj_dict_t *)&mp_module_modnormal_globals,
};

  文件mymodule.c 内创建了一个mp_module_my_test_mod的模块,它包含了一个funtion和一个type,type定义在其他文件内。

1.2、注册module

  我们要把我们定义的module注册到micropython中去,这个是在mpconfigport.h文件中修改,找到MICROPY_PORT_BUILTIN_MODULES 定义的地方按照格式添加我们定义的module:

// extra built in modules to add to the list of known ones
extern const struct _mp_obj_module_t esp_module;
extern const struct _mp_obj_module_t esp32_module;
extern const struct _mp_obj_module_t utime_module;
extern const struct _mp_obj_module_t uos_module;
extern const struct _mp_obj_module_t mp_module_usocket;
extern const struct _mp_obj_module_t mp_module_machine;
extern const struct _mp_obj_module_t mp_module_network;
extern const struct _mp_obj_module_t mp_module_onewire;
extern const struct _mp_obj_module_t mp_module_my_test_mod;//声明模块
#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 }, \
    { MP_OBJ_NEW_QSTR(MP_QSTR_my_test_module), (mp_obj_t)&mp_module_my_test_mod }, \

  这里就添加两行代码,第一行是应用外部定义的结构体时要先有声明。第二个需要解释一下,MP_QSTR_my_test_module这个名字要改成自定义的,MP_QSTR_这个一定要保留,后面的my_test_module就是在python中显示的module名字。
  然后再修改一下Makefile文件,将mymodule.c编译进去就可以了。

二、向固件里面添加module的原理

  在文章C语言开发MicroPython模块(模块框架)里面已经介绍了,编译进内核的模块(module)有四种类型,MicroPython将它们组成四个不同的模块集合,并且定义了不同的名字。

2.1、模块集合

  以我们编写的和硬件平台密切相关的 module集合mp_builtin_module_map为例,在objmodule.c文件内有

MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);

  其中mp_builtin_module_map就是这个被编译进内核的模块集合的名字,mp_builtin_module_table是存储模块的结构体数组。  MP_DEFINE_CONST_MAP的定义在obj.h文件内,内容如下:

#define MP_DEFINE_CONST_MAP(map_name, table_name) \
    const mp_map_t map_name = { \
        .all_keys_are_qstrs = 1, \
        .is_fixed = 1, \
        .is_ordered = 1, \
        .used = MP_ARRAY_SIZE(table_name), \
        .alloc = MP_ARRAY_SIZE(table_name), \
        .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \
    }

  宏定义MP_DEFINE_CONST_MAP就是定义了一个结构体,这个结构体的内容为mp_map_t

// TODO maybe have a truncated mp_map_t for fixed tables, since alloc=used
// put alloc last in the structure, so the truncated version does not need it
// this would save 1 ROM word for all ROM objects that have a locals_dict
// would also need a trucated dict structure

typedef struct _mp_map_t {
    size_t all_keys_are_qstrs : 1;
    size_t is_fixed : 1;    // a fixed array that can't be modified; must also be ordered
    size_t is_ordered : 1;  // an ordered array
    size_t used : (8 * sizeof(size_t) - 3);
    size_t alloc;
    mp_map_elem_t *table;
} mp_map_t;

  MP_ARRAY_SIZE的定义为:

// get the number of elements in a fixed-size array
#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

  说明结构体的alloc是模块集合的指针合所占的长度,table是一个指针,这个指针指向了mp_builtin_module_table这个结构体数组。在.table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \这行代码里面mp_rom_map_elem_t和mp_map_elem_t的定义为:

// Underlying map/hash table implementation (not dict object or map function)

typedef struct _mp_map_elem_t {
    mp_obj_t key;
    mp_obj_t value;
} mp_map_elem_t;

typedef struct _mp_rom_map_elem_t {
    mp_rom_obj_t key;
    mp_rom_obj_t value;
} mp_rom_map_elem_t;

  而mp_obj_t和mp_rom_obj_t的定义为:

typedef void *mp_obj_t;
typedef const void *mp_const_obj_t;
typedef mp_const_obj_t mp_rom_obj_t;

  所以名字为mp_builtin_module_map的这个模块集合在最终包含了一系列的指针,mp_builtin_module_table这个结构体数组内元素。而mp_builtin_module_table这个结构体数组内的元素则是一个一个的模块。

2.2、模块数组

  mp_builtin_module_table的定义如下:

/******************************************************************************/
// Global module table and related functions

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

    // extmod modules

#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

    // extra builtin modules as defined by a port
    MICROPY_PORT_BUILTIN_MODULES
};

  结构体mp_rom_map_elem_t的定义如下:

typedef struct _mp_rom_map_elem_t {
    mp_rom_obj_t key;
    mp_rom_obj_t value;
} mp_rom_map_elem_t;

  说明mp_builtin_module_table这个数组里面每个元素都必须是mp_rom_map_elem_t类型。当增加一个模块时,就往这个数组里面添加一个元素。下面以第一个数组元素进行分析:

2.2.1、MP_ROM_QSTR
{ MP_ROM_QSTR(MP_QSTR___main__), MP_ROM_PTR(&mp_module___main__) },

  MP_ROM_QSTR的定义为:

#define MP_ROM_QSTR(q) MP_OBJ_NEW_QSTR(q)

  而MP_OBJ_NEW_QSTR的定义为:

#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2))

  其中mp_uint_t的定义为

typedef unsigned int mp_uint_t; // must be pointer size

  mp_obj_t的定义为

typedef void *mp_obj_t;

  所以MP_ROM_QSTR(MP_QSTR___main__)的作用是将将MP_QSTR___main__强制转换为类型int,然后将结果值左移两位,在将二进制结果的值与2进行或操作,再将结果转换为无符号的指针类型。最终就变成了一个为_main__的无符号指针。

2.2.2、MP_ROM_PTR

  MP_ROM_PTR的 定义为:

#define MP_ROM_PTR(p) (p)

2.3、MICROPY_PORT_BUILTIN_MODULES

  MICROPY_PORT_BUILTIN_MODULES的定义在mpconfigport.h文件内为

#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 }, \

  MP_OBJ_NEW_QSTR的定义与MP_ROM_QSTR相同。
  以上就是将module添加进固件的指针指向的原理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言开发MicroPython模块(添加module) 的相关文章

随机推荐

  • 青藤首提“业安融合”理念,正式发布先进云安全方案CNAPP

    4月18日 青藤以 云时代 安全变了 为主题的2023年云安全高峰论坛在北京成功举办 会上 青藤首次提出 业安融合 理念 正式发布先进云安全方案CNAPP 中国全面进入云和数字化时代 当前 全球已进入数字经济时代 我国高度重视数字经济发展
  • Postgresql on conflict do update 设置当前值,原始值,当前值与原始值相加值

    Postgresql插入时主键冲突会报错 可采取冲突不做任何处理或者进行更新 俩种方式避免报错 更新时可以保存新值 保存新值与旧值表达式 更新时可以保存原来的值 ON CONFLICT date city DO NOTHING 或者 ON
  • JVM —堆内存区域的认识

    一个JVM只有一个堆 堆的大小是可以调节的 堆中存放的内容 当类加载器读取完类文件后 会把类 方法 常量 变量等存放在堆中 保存的是我们所有引用对象的真实对象 也就是真实引用对象的数据等 堆内存中的三个区域 新生区 老年区 永久区 堆中要进
  • 【Typescript】ts中的静态属性和静态方法

    Typescript中的静态属性和静态方法 在ts中使用静态属性和方法 需要有static关键字 且在静态方法里只能用静态属性 举两个栗子 在es5中 function Person this run1 function 实例方法 实例化后
  • 特征缩放(归一化处理)

    在我们面对多维特征问题的时候 我们要保证这些特征都具有相近的尺度 这将帮助梯度下降算法更快地收敛 以房价问题为例 假设我们使用两个特征 房屋的尺寸和房间的数量 尺寸的值为 0 2000平方英尺 而房间数量的值则是0 5 以两个参数分别为横纵
  • 带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪

    本教程介绍了使用 ESP32 摄像头网络服务器环境的 OpenCV js 和 OpenCV 工具 例如 我们将构建一个简单的 ESP32 摄像头网络服务器 其中包括对移动物体的颜色检测和跟踪 本教程绝不是对 OpenCV 可以提供给 ESP
  • 学乐高机器人还是学习少儿编程

    学乐高机器人还是学习少儿编程 对于很多的家长来说 孩子的学习一直都是他们非常关心和重视的一件事情 很多的家长在给孩子选择学习课程的时候 也是非常的耐心的 他们会给孩子选择一些能够有利于孩子成长的课程 就拿现在很多的家长想要孩子去学习机器人编
  • 生成树协议实验报告_“网络工程师培训”基础教程:OSPF协议及配置

    OSPF协议概述 OSPF 是 Open Shortest Path First 即 开放最短路由优先协议 的缩写 它是 IETF 组织开发的一个基于链路状态的自治系统内部路由协议 在IP 网络上 它通过收集和传递自治系统的链路状态来动态地
  • 牛客网Verilog刷题——VL54

    牛客网Verilog刷题 VL54 题目 答案 题目 实现一个深度为8 位宽为4bit的双端口RAM 数据全部初始化为0000 具有两组端口 分别用于读数据和写数据 读写操作可以同时进行 当读数据指示信号read en有效时 通过读地址信号
  • ffmpeg命令行map参数的使用

    介绍 理解 map参数的最好办法就是想像一下怎么去告诉ffmpeg你要从源文件中选择 拷贝哪个流到输出文件 输出文件的stream顺序取决于在命令行中 map的参数顺序 下面有一些例子 默认 默认操作 没有指定map参数 比如 ffmpeg
  • IR2104电机驱动

    目录 一 IR2104的引脚定义 二 IR2104的内部原理 三 半桥驱动原理分析 四 全桥驱动原理分析 五 电感电流回流路径的建立 六 自举电容容值的计算与自举二极管选型 七 mos管发热可能的问题 八 推荐阅读 一 IR2104的引脚定
  • R语言中如何进行PCA分析?利用ggplot和prcomp绘制基因表达量分析图

    学习笔记的主要内容是在R语言中利用ggplot2进行PCA分析和绘图 包括简单分析与操作流程 对比不同方式得到的结果差异 提供脚本代码供练习 PCA分析的原理 在处理基因差异表达数据时 有时候需要分析其中因素的影响最大 判断结果的关系 这个
  • InstructGPT:彻底改变人工智能驱动的语言模型

    目录 什么是InstructGPT 人工智能驱动的语言模型的演变 InstructGPT 模型与 GPT 3 相比如何 通过 OpenAI API 访问 InstructGPT 1 访问platform openai com并创建或登录您的
  • Linux中select poll和epoll的区别

    原文地址 http www cnblogs com bigwangdi p 3182958 html 在Linux Socket服务器短编程时 为了处理大量客户的连接请求 需要使用非阻塞I O和复用 select poll和epoll是Li
  • Node.js Modules 模块

    模块 https nodejs org docs v9 2 0 api modules html Node js has a simple module loading system In Node js files and modules
  • 美国移动网络运营商:是时候关闭 3G 了

    整理 祝涛 出品 CSDN ID CSDNnews 你的手机现在正使用什么样的网络服务呢 是4G还是5G呢 如果美国地区的用户依然停留在3G 他们可能需要在手机服务提供商关闭3G网络之前升级 以避免失去服务 美国联邦通信委员会 Federa
  • 华为OD机试 -扑克牌大小(C++ & Java & JS & Python)

    描述 扑克牌游戏大家应该都比较熟悉了 一副牌由54张组成 含3 A 2各4张 小王1张 大王1张 牌面从小到大用如下字符和字符串表示 其中 小写joker表示小王 大写JOKER表示大王 3 4 5 6 7 8 9 10 J Q K A 2
  • 联想Y9000X Opencore引导黑苹果Catalina10.15.6安装教程

    Y9000X 2020黑苹果安装教程 非商业用途 仅用于自己记录学习研究 Y9000X Opencore 安装双硬盘双系统教程 电脑配置 前期准备 安装流程 1 写入U盘镜像 2 更换EFI文件 3 磁盘分区 4 系统安装 5 将U盘中的E
  • [c++]opencv 鼠标响应函数传入外部参数(图像)问题

    参考博客 https blog csdn net my lord article details 53927865 https blog csdn net aiyueyueaoe article details 118192972 http
  • C语言开发MicroPython模块(添加module)

    MicroPython添加模块框架模式相对简单 只需要按照定义好的固定框架就可以添加模块 module 一 向固件里面添加module 1 1 编写mymodule c文件 在ports esp32文件夹下新建一个文件mymodule c