micropython源代码分析,micropython开发环境
http://bbs.eeworld.com.cn/thread-488408-1-1.html
一介绍
微型计算机编程语言运行在微控制器上的Python。遵守麻省理工学院(麻省理工学院)协议。由剑桥大学的理论物理学家badxz设计。
微型计算机编程语言的软件特点:
Python 3语法。
完整的计算机编程语言词法分析器,解析器,编译器,虚拟机和运行时。
包含命令行接口,可离线运行。
计算机编程语言字节码由内置虚拟机编译运行。
有效的内部存储算法,能带来高效的内存利用率。整数变量存储在内存堆中,而不是栈中。
使用计算机编程语言装饰者特性,函数可以被编译成原生机器码,虽然这一特性会带来大约2倍的内存消耗,但也使大蟒有更快的执行速度。
函数编译可设置使用底层整数代替大蟒内建对象作为数字使用。有些代码的运行效率可以媲美c的效率,并且可以被大蟒直接调用,适合做时间紧迫性,运算复杂度高的应用。
通过内联汇编功能,应用可以完全接入底层运行时,内联汇编器也可以像普通的大蟒函数一样调用。
基于简单和快速标记的内存垃圾回收算法,运行周期少于四毫秒,许多函数都可以避免使用栈内存段,因此也不需要垃圾回收功能。
二源码分析
微丝体实现了基本的大蟒的词法分析器,解析器,编译器,虚拟机和运行时。在开源代码库上获得代码:
https://github.com/micropython/micropython
解压之后目录大概如下:
主要目录的解释也可在根目录的README.md中找到。
本文以STM32 MicroPython为例。目前微丝体可运行于类操作系统系统,图16,手臂等平台。
首先,需要了解计算机编程语言的运行机制,可以参考:http://tech.uc.cn/?p=1932年年。
然后,micropython-master\py目录下个人认为是最核心的发动机,也就是微丝体的实现,C语言实现的大蟒的解析器,运行时,虚拟机组建。
最后我们来看STM32是如何实现计算机编程语言编程与控制的:
源码图中绿色注释的部分是STM32 MicroPython的主要代码,STM32(以下简称MCU)主函数位于stmhal/main.c,MCU启动后进入主要的函数,那么我们看主要的函数里干了什么事情:
int main(void) {
//TODO禁用边界扫描
//堆栈限制应该小于实际的堆栈大小,所以我们有机会
//从限制命中中恢复。(限制以字节为单位。)
MP _ stack _ ctrl _ init();
MP _ stack _ set _ limit((char *)_ ram _ end-(char *)_ heap _ end-1024);
/* STM32F4xx HAL库初始化:
-配置闪存预取、指令和数据缓存
-配置系统时钟每一毫秒产生一次中断
-将嵌套中断向量控制器组优先级设置为四
-全局MSP(微控制器支持包)初始化
*/
HAL _ Init();
//将系统时钟设置为卫生与安全执行委员会
system clock _ Config();
…
端口初始化、LED初始化、交换机初始化、标清卡初始化
…
//GC初始化
gc_init(_heap_start,heap _ end);
//微Python初始化
MP _ init();
mp_obj_list_init(mp_sys_path,0);
mp_obj_list_append(mp_sys_path,mp _ obj _新_ QSTR(QSTR议员));//当前目录(或脚本的基本目录)
mp_obj_list_append(mp_sys_path,mp _ obj _新_ QSTR(议员_ QSTR _ _斜杠_ flash));
mp_obj_list_append(mp_sys_path,mp _ obj _新_ QSTR(议员_ QSTR _ _斜杠_ flash _斜杠_ lib));
mp_obj_list_init(mp_sys_argv,0);
//将指向已安装设备的指针清零
memset(MP _ STATE _ PORT(fs _ user _ mount),0,sizeof(MP _ STATE _ PORT(fs _ user _ mount));
//初始化低级子系统。这里我们需要一些非常基本的东西,比如
//清空内存并重置任何子系统。在此之后
//我们可以运行计算机编程语言脚本(比如boot.py),但是任何可配置的东西
//必须在boot.py运行后设置by boot.py .
readline _ init 0();
pin _ init 0();
ext int _ init 0();
timer _ init 0();
UART _ init 0();
//定义MICROPY _硬件_UART_REPL为PYB UART _ 6并定义
//如果您想要一个
//硬件通用非同步收发传输器(Universal Asynchronous Receiver/Transmitter)和虚拟串口上的取代
#如果已定义(MICROPY_HW_UART_REPL)
{
mp_obj_t args[2]={
MP _ OBJ新_小_INT(MICROPY_HW_UART_REPL)
MP _ OBJ新_小_ INT(MICROPY _ HW _ UART _ REPL _波特),
};
MP _ STATE _ PORT(pyb _ stdio _ UART)=pyb _ UART _ type。make _ new((MP _ obj _ t)pyb _ UART _ type,MP_ARRAY_SIZE(args),0,args);
}
#否则
MP _ STATE _ PORT(pyb _ stdio _ UART)=NULL;
#endif
I2C _初始化0();
软复位退出:
}
在主要的函数中大概是初始化微程序控制器的时钟,初始化各个外设,然后调用大蟒的垃圾回收器gc_init(),初始化大蟒对象列表,相当于启动了大蟒的虚拟机(本人暂时对大蟒的实现机制理解有限)。后面紧接着启动了大蟒的REPL,绑定到uart6,这也就允许你通过串口来执行大蟒代码了。
启动之后单片机底层的操作通过micropython-master \ STM Hal \ Hal \ F4目录下的硬件抽象层(硬件抽象层的缩写)驱动来完成,那么在串口敲下的命令又是如何调用底层的驱动的呢?
三内建对象集成
拿简单的数(字)-模(拟)转换器来说,与之相关的文件为micropython-master\stmhal\下的dac.h、dac.c、dac.x文件声明并定义了微丝体板数(字)模(拟)转换器类的方法与属性,通过目标文件千瓦或MP_DEFINE_CONST_FUN_OBJ等注册给微丝体的内建对象。比如下面的函数:pyb_dac_write()函数调用STM32的HAL lib实现硬件的操作,通过下院议员将此函数注册为pyb _ dac _写入_对象
///\方法写入(值)
///直接访问数(字)模(拟)转换器输出(目前仅8位)。
静态MP _ obj _ t pyb _ DAC _ write(MP _ obj _ t self _ in,mp_obj_t val) {
pyb _ dac _ obj _ t * self=self _ in
如果(自我状态!=DAC_STATE_WRITE_SINGLE) {
DAC_ChannelConfTypeDef配置;
配置100 .发援会_触发器=DAC _触发器_无;
配置DAC _ out buffer=DAC _ output buffer _ DISABLE;
HAL _ DAC _ config通道(DAC _ Handle,config,self-DAC _ channel);
自状态=DAC _状态_写_单
}
//数模转换器输出在硬件级始终是12位,我们提供支持
//对于多位"分辨率",只需移动输入值。
HAL_DAC_SetValue(DAC_Handle,self-dac_channel,DAC_ALIGN_12B_R,
mp_obj_get_int(val) (12位自身);
HAL_DAC_Start(DAC_Handle,自DAC _ channel);
返回mp _常量_无
}
静态MP _ DEFINE _ CONST _ FUN _ OBJ _ 2(pyb _ DAC _ write _ obj,pyb _ DAC _ write);
最后将所有的方法注册给微丝体
静态常数MP _ map _ elem _ t pyb _ DAC _ locals _ dict _ table[]={
//实例方法
{ MP _ OBJ _新QSTR(MP _ QSTR _初始化),(mp_obj_t)pyb_dac_init_obj }
{ MP _ OBJ _新_ QSTR(QSTR议员)写),(MP _ obj _ t)pyb _ DAC _写_obj },
#如果已定义(lmdxz6)
{ MP _ OBJ _新_ QSTR(QSTR议员)噪音),(MP _ obj _ t)pyb _ DAC _噪音_obj },
{ MP _ OBJ _新_ QSTR(QSTR议员)三角),(MP _ obj _ t)pyb _ DAC _三角_obj },
{ MP _ OBJ _新_ QSTR(QSTR议员)写_定时),(MP _ obj _ t)pyb _ DAC _写_定时_obj },
#endif
//类常量
{ MP _ OBJ _新_ QSTR(QSTR议员)正常),MP _ OBJ _新_小_ INT(DMA _正常)},
{ MP _ OBJ _新_ QSTR(QSTR议员)循环),MP _ OBJ _新_小_ INT(DMA _循环)},
};
静态MP _ DEFINE _ CONST _ DICT(pyb _ DAC _ locals _ DICT,pyb _ DAC _ locals _ DICT _ table);
const MP _ obj _ type _ t pyb _ DAC _ type={
{ mp_type_type }。name=MP_QSTR_DAC。make_new=pyb_dac_make_new。locals _ dict=(MP _ obj _ t)pyb _ DAC _ locals _ dict,
};
该结构体在dac.h中声明为外部变量:
extern const MP _ obj _ type _ t pyb _ DAC _ type;
然后在stmhal/modpyb.c中包含了dac.h,并将pyb_dac_type声明为大蟒的对象:
#if MICROPY_HW_ENABLE_DAC
{ MP _ OBJ _新QSTR(MP_QSTR_DAC),(mp_obj_t)pyb_dac_type },
#endif
因此如果想添加内建的对象或方法应该遵循如下的步骤与原则:
建立国会议员对象:
const MP _ obj _ type _ t pyb _ led _ type={
{ mp_type_type }。name=MP_QSTR_LED,///name。print=led_obj_print,///重载的打印方法。make_new=led_obj_make_new,///构造函数。locals _ dict=(MP _ obj _ t)led _ locals _ dict,///该对象所拥有的方法字典
};建立方法字典led_locals_dict:实现方法
实现上图中画横线的方法以及第一步中的重载的打印方法,构造方法等。将国会议员对象pyb_led_type添加到modpyb.c中的pyb_module_globals_table[]全局大蟒对象表里:
{ MP _ OBJ _新QSTR(MP_QSTR_DAC),(mp_obj_t)pyb_dac_type }
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。