折腾MicroPython过程中记录的笔记。涉及资源、工具、文档等。

MicroPython概述

MicroPython是Python3(Python 3.4)的精简高效实现,包括Python标准库的一小部分(此外,MicroPython还包括访问硬件的”machine”等模块),可在微控制器和受限环境中运行。

MicroPython包括了REPL,列表解析,生成器,异常处理等高级功能,适合运行在只有256k的代码空间和16k的RAM的芯片上。

MicroPython尽可能与普通Python(CPython)兼容,方便你轻松将代码从桌面环境移植到微控制器或嵌入式系统。

历史

MicroPython最初由澳大利亚程序员兼物理学家Damien George 在2013年Kickstarter众筹活动之后创建. 最初的的Kickstart活动通过pyboard微控制器发布了MicroPython.

但MicroPython支持许多基于ARM的体系结构的芯片。MicroPython已经可以运行在Arduino,ESP8266,ESP32…(具体参考MicroPython downloads )。2016年,MicroPython的一个分支运行在的BBC microbit上。

开放性

MicroPython使用C99(C语言的官方标准第二版)编写,源码在这儿,MicroPython内核非常开放,采用 MIT 协议.

可以自由使用和或者修改MicroPython: 个人使用、教育和商业产品…

pyboard的的硬件部分开放在这里:micropython/pyboard

pyboard

我目前手中的这块板子是 PYBv1.1

引脚图如下:

技术参数

  • STM32F405RG微控制器
  • 168 MHz Cortex M4 CPU,带硬件浮点
  • 1024KiB闪存ROM和192KiB RAM
  • 微型USB连接器,用于电源和串行通信
  • Micro SD卡插槽,支持标准和高容量SD卡
  • 3轴加速度计 (MMA7660)
  • 可选电池备份的实时时钟
  • 有29个GPIO
  • 3x12位模数转换器,16引脚,4路模拟接地屏蔽
  • 2x12位数模转换器,可在引脚X5和X6上使用
  • 1个复位和1个用户开关
  • 4个led灯(红,绿,黄、蓝)
  • 板载3.3V LDO稳压器,能够提供高达250mA的输入电压范围3.6V至16V
  • ROM中的DFU引导加载程序,便于升级固件

此外值得一提的特性:

  • 支持多种架构(x86, x86-64, ARM, ARM Thumb, Xtensa)
  • 快速的启动速度(运行到boot.py只需要150毫秒,PYBv1.1以168MHz运行)
  • 通过_thread支持多线程

烧写系统

参考: Pyboard Firmware Update

按以下步骤进行(我在mac下进行,linux下基本一致,windows用户参考On Windows - Using STM DfuSe):

  • 将DFU pin 与 3.3V pin用杜邦线连在一起

  • 安装dfu-util
    • mac下是: brew install dfu-util
  • 列出设备
    • sudo dfu-util -l
    • 备份旧系统(可选): sudo dfu-util --alt 0 --upload pyboard-original.dat -s:524288
  • 下载MicroPython固件:MicroPython downloads
  • 开始烧录: sudo dfu-util --alt 0 -D pybv11-thread-20171220-v1.9.3-207-ga1d85d61.dfu
  • 完成

你也可以使用pydfu.py来进行烧录

开始编程

有多种方式可以在pyboard中运行代码,分别是:

  • 脚本运行
  • REPL

下边分别论述:

脚本运行

我们在pyboard上运行硬件的hello world:点亮led灯

  • 用USB数据线将pyboard连到电脑里,pyboard将以U盘模式挂载到电脑上(PYBFLASH)
  • 进入PYBFLASH,编辑main.py,内容为

    1
    2
    3
    
    import pyb
    red_led = pyb.LED(1) 
    red_led.on()
  • 正常弹出pyboard(否则内容会丢失),按下reset按钮(RST)按下,即可点亮红灯

更多的教材参考:MicroPython tutorial for the pyboard

PYBFLASH目录下有个boot.py文件,该文件是启动引导脚本,默认加载main.py

通过修改该文件,你还可以选择pyboard的挂载模式,诸如将其挂载为鼠标,有兴趣的同学可以点开这个文件,里边有相应注释。更多细节可以参考:Making the pyboard act as a USB mouse。当你想把pyboard从鼠标模式改回来时,需要使用安全模式:boot-modes

badusb

下边我们来做些邪恶的事情,不知道badusb是什么的同学,请绕路不要学坏

修改boot.py

1
2
3
import machine
import pyb
pyb.usb_mode('VCP+HID')

修改main.py

下边这个例子中,我们使用体感来控制鼠标

1
2
3
4
5
6
7
8
9
import pyb

switch = pyb.Switch()
accel = pyb.Accel()
hid = pyb.USB_HID()

while not switch():
    hid.send((0, accel.x(), accel.y(), 0))
    pyb.delay(20)

下边这个例子中,按下USR按钮,输入hello

修改boot.py

1
2
3
import machine
import pyb
pyb.usb_mode('CDC+HID',hid=pyb.hid_keyboard)

修改main.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import pyb
led = pyb.LED(1)
sw = pyb.Switch()
kb = pyb.USB_HID()
buf = bytearray(8)

PLAIN = 0x00
SHIFT = 0x02
kbmap = dict()
# part of second row example
kbmap['e'] = (0x08,PLAIN)
kbmap['h'] = (0x0B,PLAIN)
kbmap['l'] = (0x0F,PLAIN)
kbmap['o'] = (0x12,PLAIN)


def sendchr(char) :
    if not char in kbmap.keys() :
        print("Unknow char") ; return
    # key down
    buf[2], buf[0] = kbmap[char]
    kb.send(buf)
    pyb.delay(20) #注意 delay时间太短可能出问题
    # key up
    buf[2], buf[0] = 0x00, 0x00
    kb.send(buf)
    pyb.delay(20)

def sendstr(str) :
    for c in str : sendchr(c)

pyb.delay(1000)
led.toggle()
string = "hello"
sendstr(string)
pyb.delay(1000)
led.toggle()

'''
while 1 :
    if sw() :
        led.toggle()
        string = "hello"
        sendstr(string)
        # Wait for switch to be released
        led.toggle()
    pyb.delay(20)
'''

这样一来你可以干任何事:)

REPL

REPL(Read Evaluate Print Loop)提供了绝佳的学习和探索环境。Python用户对此应该深有感触

在Mac/Linux下我偏好使用串口调试工具picocom来连接硬件(更多的工具参考:Getting a MicroPython REPL prompt

通过/dev/tty.usb*识别出你的pyboard(通过观察pyboard插入前后的变化,多出的设备即为pyboard),我的pyboard地址为/dev/tty.usbmodem1412

执行: picocom /dev/tty.usbmodem1412 -b115200 即可进入REPL

注: picocom使用的是emacs的快捷键,退出为:Ctrl-a Ctrl-x

更多工具

以上两种方式在开发过程都有些缺陷。以main.py脚本运行的方式,每次需要编辑文件、弹出设备、点击重置。步骤太多

而在REPL中运行,又不放便保存代码,也不好写多行脚本(函数、类、循环),这一点上ptpython做的很好,可惜目前不能用于MicroPython。下边介绍一些方便调试的工具

ampy

ampy是Adafruit出品的一个工具,通过串口连接与MicroPython交互,提供许多实用的工具。允许你在命令行里操控MicroPython。诸如运行本机脚本,往MicroPython板子上传下载文件

安装:pip install adafruit-ampy

帮助: ampy --help

调试脚本(假设设备为/dev/tty.usbmodem1412): ampy --port /dev/tty.usbmodem1412 run /tmp/a.py

Jupyter MicroPython Kernel

使用jupyter来交互式地编程

错误提醒与处理

参考:Errors: flashing LEDs

  • 如果main.py文件中有语法错误,板子上会交替闪烁红灯和绿灯.如果四个灯同时闪烁,你需要恢复出厂设置
  • 恢复出厂设置(刷完固件之后的状态):Safe mode and factory reset

第三方模块

参考:Distribution packages, package management, and deploying applications

和python一样,你也可以方便地安装第三方模块包:micropython-lib

如果你的板子可以联网(8266的板子可以,pyboard也有networking版本),你可以直接使用upip来安装、管理第三方包。

如果你的板子不能联网(目前的pyboard默认不能联网),你可以使用交叉安装包(Cross-installing packages):现在本地安装包,然后挪到板子里(import路径下即可)。具体而言你会用到这条命令:micropython -m upip install -p install_dir micropython-pystone_lowmem, 之后你把install_dir拖到板子里即可

在mac下你可以通过brew install micropython安装micropython

import 模块

以超声波模块为例:micropython-hcsr04

在PYBFLASH目录下,拖入hcsr04.py,之后在便可使用它: import hcsr04

其他话题

中断(interrupts)

如果你想在pyboard中实现事件机制,可以使用硬件中断: The Switch, callbacks and interrupts

中断回调的函数,需要注意内存

1
2
3
4
def callback(line):
    print("hello", line)
# pyb.Pin("X17")是用户按钮
extint = pyb.ExtInt(pyb.Pin("X17"), pyb.ExtInt.IRQ_FALLING,pyb.Pin.PULL_UP, callback) 

多线程

如果你要用多线程(诸如模拟事件),你需要先烧录threading版本的固件,之后你就可以食用_thread模块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import _thread
import time


def myThread_A():
    print('thread A-')
    _thread.exit()


def myThread_B(time_):
    time.sleep(time_)
    print('thread B-')
    print('thread B- Sleep 5s')
    time.sleep(5)
    print('thread B-Wake up')
    _thread.exit()

def myThread_C(time_):
    time.sleep(time_)
    print('thread C-')
    _thread.exit()

_thread.start_new_thread(myThread_A, ())
_thread.start_new_thread(myThread_B, (2,))
_thread.start_new_thread(myThread_C, (3,))

while True:
    pass

优化

a cross-compiler and frozen bytecode, to have pre-compiled scripts that don’t take any RAM (except for any dynamic objects they create)

一些实用/有趣的项目

参考