由Micro+Python两个部分组成;Micro代表微小,Python是编程语言,两者合起来的字面意思就是微型的Python。实际上MicroPython就是用于嵌入式系统上的Python。Python是一种脚本语言,是一款非常容易使用的脚本语言,语法简介、使用简单、功能强大、容易扩展。有非常多的库可以使用。网络功能和计算功能也很强。方便的和其他语言配合使用。完全开源,受到原来越多的开发者青睐。不过由于受到硬件成本、运行性能、开发习惯等原因。没有在通用嵌入式方面得到太多应用。所以MicroPython应运而生。
由英国剑桥大学的教授Damien Georage(达米安乔治)发明的。随着半导体技术和制造工艺的快速发展,芯片的升级换代速度也越来越快,芯片的功能、内部的存储器容量和资源不断增加,而成本却在不断降低。特别是随着像ST公司和乐鑫公司高性价比的芯片和方案应用越来越多,这就给Python在低端嵌入式系统上的使用带来了可能。
1)MicroPython并没有带来一种全新的编程语言;
2)为嵌入式开发带来了一种新的编程方式和思维,让大家可以将重点放在应用层的开发上。
3)MicroPython的特点是简单易用、移植性好、程序容易维护。
一个MicroPython系统的典型结构所示,它由微控制器(系统底层)硬件、MicroPython固件和用户程序三大部分组成。
图2.1 MicroPython系统的典型结构
REPL是Read-Evaluate-Print Loop(读取-计算-输出循环)的缩写。在MagicBox Project屏蔽了REPL交互编程功能,而采用了文本编程。
MicroPython可以在多种嵌入式硬件平台上运行,目前已经有STM32、ESP8266/ESP32、CC3200、dsPIC33、MK20DX256、nRF51/nRF52、MSP432等多个平台。公司MagicBox基于STM32F4 DISCOVERY开发板开发。
图3.1 STM32F4 DISCOVERY开发板
官方micropython代码托管在github上micropython。
优点:无需自己编译micropython的代码
缺点:可扩展性有限,某些底层功能单纯使用python接口无法完成
优点:大大增加可扩展性,满足开发需求
缺点:需要修改micropython的代码
打开test.c,输入以下内容,来实现一个简单的模块添加
#include "stdint.h"
#include "stdio.h"
#include "py/obj.h"
#include "py/runtime.h"
//定义的test全局字典,之后我们添加type和function就要添加在这里
STATIC const mp_rom_map_elem_t test_globals_table[] = {
{MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_test)}, //这个对应python层面的__name__ 属性
};
//这个可以认为是把test_globals_table注册到 mp_module_test.globals里面去
STATIC MP_DEFINE_CONST_DICT(mp_module_test_globals, test_globals_table);
//这个是定义一个module类型
const mp_obj_module_t mp_module_test = {
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mp_module_test_globals,
};
mp_rom_map_elem_t test_globals_table[]
MP_DEFINE_CONST_DICT(mp_module_test_globals, test_globals_table)
mp_obj_module_t mp_module_test
打开Makefile找到如下脚本的地方,按照格式添加test.c就可以了:
SRC_C = \
main.c \
uart.c \
…………
test.c\
$(SRC_MOD)
找到MICROPY_PORT_BUILTIN_MODULES 定义的地方按照格式添加我们定义的module
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_test; //这个是我们添加的,需要声明一下应用外部的struct
#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_test), (mp_obj_t)&mp_module_test }, \ //这个是我们添加的test
.syntax unified
.cpu cortex-m4
.thumb
.section .text.Reset_Handler
.global Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Save the first argument to pass through to stm32_main */
mov r4, r0
/* Load the stack pointer */
ldr sp, =_estack
/* Initialise the data section */
ldr r1, =_sidata
ldr r2, =_sdata
ldr r3, =_edata
b .data_copy_entry
.data_copy_loop:
ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
str r0, [r2], #4
.data_copy_entry:
cmp r2, r3
bcc .data_copy_loop
/* Zero out the BSS section */
movs r0, #0
ldr r1, =_sbss
ldr r2, =_ebss
b .bss_zero_entry
.bss_zero_loop:
str r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
.bss_zero_entry:
cmp r1, r2
bcc .bss_zero_loop
/* Initialise the system and jump to the main code */
bl SystemInit
mov r0, r4
b stm32_main
.size Reset_Handler, .-Reset_Handler
C的函数入口是stm32_main
1)开启指令、数据等的Cache
2)中断、时钟配置
3)MicroPython的线程配置
4)LED、Switch、Machine库、RTC、UART0、I2C0、SDCard、LWIP(如果有的话)、GC(垃圾回收)、定时
器、CAN、USB(默认枚举成VCP + U盘)
5)运行内部 flash 文件系统或者外置 SD 卡文件系统中的 boot.py
6)运行内部 flash 文件系统或者外置 SD 卡文件系统中的 main.py
7)当 boot.py 和 main.py 运行结束后,进入到 REPL 模式。在该模式下,我们在PC中可以通过串口与MicroPython
实现命令行的交互
#if MICROPY_HW_ENABLE_STORAGE
static char fresh_boot_py[] =
"# boot.py -- run on boot-up\r\n"
"# can run arbitrary Python, but best to keep it minimal\r\n"
"\r\n"
"import machine\r\n"
"import pyb\r\n"
"import _thread\r\n"
"import mb\r\n"
"def thread_entry():\r\n"
" while True:\r\n"
" res = mb.ReadCH375Data()\r\n"
" if not res:\r\n"
" _thread.exit()\r\n"
"pyb.UART(2).init(115200, bits=8, parity=None, stop=1)\r\n"
"_thread.start_new_thread(thread_entry, ())\r\n"
"#pyb.main('main.py') # main script to run after this one\r\n"
#if MICROPY_HW_ENABLE_USB
"#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device\r\n"
"#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse\r\n"
#endif
;
res = f_stat(&vfs_fat->fatfs, fresh_boot_py, &fno);
if (res != FR_OK) {
// doesn't exist, create fresh file
f_open(&vfs_fat->fatfs, &fp, fresh_boot_py, FA_WRITE | FA_CREATE_ALWAYS);
f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
f_close(&fp);
}
const char *boot_py = "System/boot.py";
mp_import_stat_t stat = mp_import_stat(boot_py);
if (stat == MP_IMPORT_STAT_FILE) {
int ret = pyexec_file(boot_py);
PrintInfo("pyexec boot file result: %d", ret);
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
if (!ret) {
flash_error(4);
}
}
1)《MicroPython入门指南》
2)《MicroPython开发环境搭建及移植使用分析》
3)《MicroPython补充说明》