micropython源代码分析,micropython开发环境

  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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: