micropython中文文档,micropython中文入门指南
1、Python代码和C代码字符关联
本节将介绍Python字符与C字符的关系(如模块名、类名、变量名、函数名等。)模块扩展过程中。ADC类名字符用于说明以下关联过程:c字符ADC
STATIC const MP _ ROM _ map _ elem _ t driver _ locals _ dict _ table[]={ { MP _ OBJ _新_QSTR(MP_QSTR___name__),MP_ROM_QSTR(MP_QSTR_driver)},{ MP _ OBJ _新_QSTR(MP_QSTR_ADC),MP_ROM_PTR(driver_adc_type)},……};Python代码字符ADC
从驱动程序导入ADC
字符关联方法
执行脚本命令:(脚本路径:components/py _ engine/engine/gen HDR/gen _ qstr . py)
Gen _ qstr.pyadc生成唯一的字符映射关系:
QDEF (MP _ QSTR _ ADC,(constbyte *) X63 X03 ADC )将结果存储在文件components/py _ engine/adapter/Haas/gen HDR/qstrdefs . generated . h中,从而完成字符的映射。在代码执行期间,python引擎传递QSTRDEFs。
2、Python
代码调用
C
代码
Python引擎运行时会寻找宏定义MICROPY_PORT_BUILTIN_MODULES,并以此作为组件扩展的入口。netmgr_module和driver_module是上面定义的扩展模块的名称。
代码:components/py _ engine/adapter/Haas/mpconfigport . h
# define micropy _ port _ builtin _ modules { MP _ rom _ qstr(MP _ qstr _ netmgr),MP _ rom _ ptr (netmgr _ module)}, {MP _ rom _ qstr (MP _ qstr _ driver),MP _ rom _ ptr Python应用程序可以通过import netmgr导入net mgr模块,通过import ADC from driver从模块驱动程序导入ADC类,调用此模块/类提供的函数。
3、C
代码调用
Python
代码
在嵌入式开发中,大多数外设接口(如定时器、UART、GPIO等)的事件通知。)是通过回调函数实现的。有些模块的状态通知也是通过回调实现的,比如网络状态变化的通知功能。常规的基于C-voice的开发,ISR(中断回调函数)工作在系统进程/线程的上下文中,回调通知机制易于控制。但是Python应用工作在Python虚拟机进程的上下文中,中断回调函数发生在C底层进程的上下文中。C进程和Python虚拟机进程是相互隔离的,C语言直接调用Python代码的路径是不可行的。
图1 C和Python ISR处理
MicroPython提供了两种实现C底层进程与Python虚拟机进程通信的方式,实现了C语言通知Python应用层的功能。接下来,本节以定时器模块为例,详细分析两种回调机制的原理,以方便开发者将自己的模块扩展到MicroPython系统中,共同丰富和发展Python light应用生态。
首先,创建并初始化ISR线程虚拟化环境,使ISR线程获得与Python虚拟机进程相同的上下文。
//1获取并保存当前虚拟机线程状态void * old _ state=MP _ thread _ Get _ state();//2分配并设置ISR线程的状态信息mp _ state _ thread _ t tsmp _线程_集合_状态(ts);//3初始化ISR新虚拟机线程的堆栈指针,1表示ts信息mp_stack_set_top(ts 1)需要包含在后面的指针扫描中;//4根据ISR线程的堆栈大小设置新线程的虚拟机堆栈大小。堆栈大小取决于ISR线程堆栈,该值会//在不同的模块中发生变化。(痛点1)MP _ stack _ set _ limit(1024);//5将当前虚拟机线程的局部和全局状态信息传递给新建线程中的MP _ locales _ set(MP _ locales _ get());MP _ globals _ set(MP _ globals _ get());//6禁止虚拟机线程调度,防止虚拟机切换到其他MicroPython线程MP _ sched _ lock();//7掩码内存分配GC _ lock();//8执行MicroPython APIs回调完成C底层到Python应用层的回调(痛点2)MP _ call _ function _ 1 _ protected(callback,MP _ obj _ from _ ptr(arg));//9启用内存分配GC _ unlock();//10启用虚拟机线程调度MP _ sched _ unlock();//11将虚拟机线程状态恢复到第一步保存的状态MP _ thread _ set _ state(old _ state);用C语言的ISR调用Python线程的回调函数需要11个步骤,有两个痛点:
Step 4需要评估ISR线程的堆栈大小来设置新线程虚拟环境的堆栈,这个不好评估。第八步:根据ISR回调参数的个数确定函数调用。当回调参数较多时,需要将多个参数转换成字典变量进行回调。目前MicroPython提供了两个变量的回调函数定义如下:MP _ obj _ t MP _ call _ function _ 1 _ protected(MP _ obj _ t fun,MP _ obj _ t arg);MP _ obj _ t MP _ call _ fun _ 2 _ protected(MP _ obj _ t fun,mp_obj_t arg1,MP _ obj _ t arg 2);可以看出,上述方法虽然可以实现从ISR到Python应用层的回调,但是需要11个步骤才能完成,而且新线程的堆栈大小也不好评估。还能有别的机制吗?MicroPython提供了第二种回调机制:Looper-Handler模式。在这种模式下,ISR线程将Python应用层回调函数的句柄注入虚拟机环境,并通知Python主线程,由Python主线程查询并调用回调函数,因此不需要创建新的虚拟线程。
MicroPython Looper-Handler模式提供了mp_sched_schedule函数,它允许ISR将回调函数注册到虚拟机环境中。Python主线程解析执行脚本代码时,会检查虚拟机调度状态,然后决定是否需要执行回调函数。是以下mp_sched_schedule函数的实现:
bool MICROPY _ WRAP _ MP _ SCHED _ SCHED _ SCHEDULE(MP _ SCHED _ SCHEDULE)(MP _ obj _ t函数,MP _ obj _ t arg){ MP _ uint _ t ATOMIC _ state=MICROPY _ BEGIN _ ATOMIC _ SECTION();bool ret//1检查调度队列是否满,只有当队列未满时,回调函数if(!MP _ SCHED _ FULL(){ if(MP _ state _ VM(SCHED _ state)==MP _ SCHED _ IDLE){/2设置调度状态,方便虚拟机主线程后续查询执行MP _ state _ VM(SCHED _ state)=MP _ SCHED _ pending;} //3增加调度队列的索引,注入回调函数uint 8 _ tiput=idx _ mask(MP _ state _ VM(sched _ idx)MP _ state _ VM(sched _ len));MP_STATE_VM(sched_queue)[iput]。func=函数;MP_STATE_VM(sched_queue)[iput]。arg=arg//4回调注入成功,返回true ret=true} else {//5调度队列已满,返回false ret=false} MICROPY _ END _ ATOMIC _ SECTION(ATOMIC _ state);返回ret} MicroPython通过预编译参数MICROPY_SCHEDULER_DEPTH设置调度队列的深度,默认为4。
//调度程序中的最大项数# IFN def MICROPY _ SCHEDULER _ DEPTH # define MICROPY _ SCHEDULER _ DEPTH(4)# endif HaaS轻应用封装了微支付_事件_投票_挂钩宏定义,在REPL(交互式解释器)模式或其他情形下需要立刻执行回调函数的时候调用该宏,以触发虚拟机线程调用mp _句柄_挂起(真),完成对mp _句柄_挂起_尾部函数的调用,最终实现对注入到调度队列函数的回调。这个宏定义的代码实现如下所示:
# define MICROPY _ EVENT _ POLL _ HOOK do { extern void MP _ handle _ pending(bool); MP _ handle _ pending(true); MICROPY _ PY _ u socket _ EVENTS _ HANDLER MP _ THREAD _ GIL _ EXIT(); MP _ THREAD _ GIL _ ENTER(); } while(0);//它的一个变体在伏特计中的挂起异常check void MP _ handle _ PENDING(bool raise _ exc){ if(MP _ STATE _ VM(SCHED _ STATE)==MP _ SCHED _ PENDING){//检查调度状态是否有被设定为MP_SCHED_PENDING状态MP _ uint _ t ATOMIC _ state=MICROPY _ BEGIN _ ATOMIC _ SECTION();//现在我们在原子部分,重新检查状态仍处于挂起状态10 . if(MP _ STATE _ VM(SCHED _ STATE)==MP _ SCHED _ PENDING){ MP _ obj _ t obj=MP _ STATE _ VM(MP _ PENDING _ exception);if (obj!=MP _ OBJ空){.} mp_handle_pending_tail(原子状态);//呼叫回调函数} else { MICROPY _ END _ ATOMIC _ SECTION(ATOMIC _ state);} }} 在莱克斯(词法分析器)模式下可以直接调用mp _句柄_挂起_尾部函数实现回调触发,本节不做详细的分析,mp_handle_pending_tai的代码实现如下所示。
//这个函数只能由mp_handle_pending,//或者该函数的伏特计内联版本调用,void MP _ handle _ pending _ tail(MP _ uint _ t atomic _ STATE){ MP _ STATE _ VM(SCHED _ STATE)=MP _ SCHED _ LOCKED;如果(!MP _ sched _ empty()){ MP _ sched _ item _ t item=MP _ STATE _ VM(sched _ queue)[MP _ STATE _ VM(sched _ idx)];MP _ STATE _ VM(sched _ idx)=IDX _掩码(MP _ STATE _ VM(sched _ idx)1);-MP _ STATE _ VM(sched _ len);MICROPY _ END _ ATOMIC _ SECTION(ATOMIC _ state);MP _ call _ function _ 1 _ protected(项目。功能,项目。arg);} else { MICROPY _ END _ ATOMIC _ SECTION(ATOMIC _ state);} MP _ sched _ unlock();} 从上面的介绍可以看出第二种方式仅需要调用一个函数即可实现回调函数的注入,对开发者来说很方便。下面贴出计时器模块中国际放射学会(国际放射学会)函数的示例代码供读者参考。
静态void driver _ timer _ ISR(void * self _ in){ driver _ timer _ obj _ t * self=(driver _ timer _ obj _ t *)self _ in;如果(自回调!=MP _ const _ none){ bool ret=MP _ sched _ sched(自回调,MP _ OBJ _ FROM _ PTR(self));if(ret==false){ printf([utility]:调度队列已满! r n );} }}
4、小结
哈斯团队通过组件扩展的方式将底层哈斯丰富的软硬件积木能力封装成计算机编程语言库,供计算机编程语言应用层代码直接使用,大大提高了计算机编程语言轻应用程序的产品化效率。
开发者支持
如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号。吉图布:https://github . com/阿里巴巴/AliOS-Things/tree/rel_3.3.0
吉蒂:https://gitee . com/organizations/a lios-things/projects
代码中国:https://代码中国。csdn。net/a lios-Things/a lios-Things/-/tree/rel _ 3。3 .0
更多技术与解决方案介绍,请访问哈斯官方网站https://haas.iot.aliyun.com。