[Toc]
# 第11章 micro:bit
今天,墨博士向小墨介绍了一种开发板:micro:bit,这是一种可以使用Python直接操作的硬件。在本章中,墨博士就向小墨展示了Python操作micro:bit的方法,并做出了几个小应用,一起来看看吧。
## 11.1 micro:bit是什么
墨博士:小墨,你来看这是什么东西?
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.1.jpg)
图11.1 micro:bit
小墨:这个……,没见过。
墨博士:这个东西叫micro:bit,是一款由英国广播电视公司(BBC)推出的专为青少年编程教育设计的微型电脑开发板。我看很不错,就入手了一个,正好咱们可以一块玩玩。
小墨:这个micro:bit能做什么呀?
墨博士:你可别小看它。它虽然很小,但集成了种类丰富的电子模块:5x5的LED显示屏,两颗可编程按键,加速度计,电子罗盘,温度光线传感器等。
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.2.png)
图11.2 micro:bit电子模块介绍
小墨:这么强大呢!
墨博士:除了自身集成的电子模块外,它还能外接很多电子元件,让你轻松完成如电子游戏、遥控小车、音乐播放、可穿戴设备等场景下的开发。
小墨:厉害厉害!那这个东西到底怎么玩呢?
## 11.2 micro:bit在线开发平台
墨博士:micro:bit的常用开发方式有两种。一种是使用MakeCode,这是微软为micro:bit提供的在线编程平台,如下图11.3所示。
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.2.png)
图11.3 MakeCode在线编程平台
它最大的特点是提供了图形化的编程方式,让新手也能很快上手制作出一些好玩的程序来。
另一种方式是使用PythonEditor,这也是一个在线编程平台,如图11.4所示。
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.4.png)
图11.4 PythonEditor在线编程平台
从PythonEditor的名字就可以看出,这个编程平台其实就相当于一个Python的编辑器,也就是说它使用Python作为开发语言。这是它与MakeCode最大的区别。
**注意**:严格来说PythonEditor使用MicroPython而不是Python作为开发语言,而MicroPython可以看做是Python语言应用在硬件领域的特殊版。
> 墨博士提醒:你可能需要使用最新版的谷歌浏览器chrome来访问PythonEditor。
小墨:我们今天用哪种方式呢?
墨博士:你已经学习了很多Python的知识,可以直接选择第二种方式了,代码的方式也比图形化的方式更灵活、更强大。
小墨:好,正好练练手。不过我们编写的程序如何运行到micro:bit上去呢?
墨博士:首先通过usb线将micro:bit连接到你的电脑上,此时电脑中多了个MICROBIT的盘符。如图11.5所示。
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.5.png)
图11.5 micro:bit连接上电脑后,就跟插了一个U盘一样
然后你看PythonEditor的左上角有个download按钮,它的作用是将你编写好的代码转成micro:bit能识别的格式并下载下来。下载好后把下载的文件直接拷贝到MICROBIT磁盘中,这样你写的程序就自动运行起来了。
小墨:哦,那如果我写了好多个程序呢?
墨博士:当新的程序被拷贝到MICROBIT磁盘后,micro:bit就开始运行新的程序了,这个过程就相当于新程序把老程序给覆盖了,也即同一时刻只能运行一个程序。
好了,我们实际来操作一下,看看这个平台的使用。
## 11.3 micro:bit的使用
老规矩,我们还是从micro:bit的Hello World说起。
### 11.3.1 Hello World
在PythonEditor中编写如下代码:
```
from microbit import *
display.scroll("Hello, World!")
```
第1句表示将microbit中的所有内容全部导入。这个microbit就是MicroPython中自带的操作micro:bit的库。
第2句的表示在显示器上滚动显示字符串“Hello,World!”。
编写好代码后可以在右侧输入框中输入一个名称,比如我这里写成hello,如图11.6所示。
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.6.png)
图11.6 在PythonEditor中编写代码并保存为hello
这个名称将作为你下载或保存的文件的名称。
点击download按钮,就会下载一个hello.hex文件,将此文件拷贝到MICROBIT磁盘中,就可以在micro:bit上看到程序的运行结果了。
除了scroll外,另外一个常用来显示字符的方法是show():
```
display.show("Hello, World!")
```
它和scroll的区别是scroll是滚动显示“Hello, World!”的每个字符,而show是逐个显示“Hello, World!”中的每个字符。
> 动动手:动手实际操作比较下scroll和show的区别。
### 11.3.2 内置图案
除了字符外,还可以显示一些小图案在屏幕上。MicroPython内置了很多小图案,比如:
```
from microbit import *
display.show(Image.HAPPY)
```
就用于在屏幕上显示一个笑脸。运行结果如图11.7所示。
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.7.png)
图11.7 笑脸显示在micro:bit的显示器上
其他常用内置小图案有:
```
# 内置图案
Image.HEART
Image.HEART_SMALL
Image.HAPPY
Image.SMILE
Image.SAD
Image.CONFUSED
Image.ANGRY
Image.ASLEEP
Image.SURPRISED
Image.SILLY
Image.FABULOUS
Image.MEH
Image.YES
Image.NO
……
```
### 11.3.3 自定义图案
小墨:博士,除了能显示这些内置的图案外,我们自己能控制屏幕上的这25个LED灯吗?如果可以的话我们就能自己画一些图案出来了。
墨博士:你想画什么呢?
小墨:我想画一辆坦克,或者一挺冲锋枪。
墨博士:自定义图案,使用类似如下代码:
```
from microbit import *
my_img = Image("00900:00900:09990:09990:09990")
display.show(my_img)
```
my_img就是我们自定义的图案了。这里的“00900:00900:09990:09990:09990”就对应25个LED灯,每五个一组,一共分五组。每个LED对应的数字可以取0~9中的任意一个,表示LED的亮度。数字越大表示越亮,数字为0表示灯是暗的。
上述的“00900:00900:09990:09990:09990”其实就是一个坦克的图案,如图11.8所示。
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.8.png)
图11.8 自定义坦克图案
> 动动手:请帮助小墨显示一挺机枪的图案出来。
### 11.3.4 动画
墨博士:小墨,你听说过逐帧动画吗?
小墨:听墨哥哥说过。据他所说,有些动画片就是一帧一帧画出来的。
墨博士:如果我们在micro:bit的显示屏上交替显示两种图片,也就变成了逐帧动画了:
```
from microbit import *
my_img_0 = Image("00900:09990:00900:09090:90009")
my_img_1 = Image("00900:09990:00900:00900:00900")
img_list = [my_img_0, my_img_1]
display.show(img_list, delay=500, loop=True)
```
你来运行一下,看看效果。
小墨:一个小人儿走路的动画!这个跟红绿灯路口人行道交通灯中的小人儿差不多。如图11.9和11.10所示
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.9.png)
图11.9 站立的小人儿
![](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE11.10.png)
图11.10 行走的小人
墨博士:来看看实现的过程:show()的第一个参数是两个图案组成的list;第二个参数delay=500表示两张图的替换间隔,单位是毫秒,一秒等于一千毫秒;第三个参数loop=True表示两张图一直交替显示,就相当于死循环。事实上,我们确实也可以使用死循环来制作这种动画效果。
比如我们来模拟一个萤火虫的发光过程:把这25个LED灯整体看做是一个萤火虫,然后让它逐渐从暗到亮,到最亮后再逐渐从亮到暗,如此反复。
分析一下:萤火虫从暗到亮,其实是LED灯对应的数字由“00000:00000:00000:00000:00000”变成“11111:11111:11111:11111:11111”、“22222:22222:22222:22222:22222”,然后再逐渐变成“99999:99999:99999:99999:99999”的过程。萤火虫从亮变暗的过程反之。我们可以先定义一个函数,用于产生这些数字:
```
def get_image(n):
result = ''
for i in range(5):
for j in range(5):
result += str(n)
result += ':'
return result[0:len(result)-1]
```
这里的参数n就是LED灯的亮度,可以打印测试一下:
```
print(get_image(1))
```
输出结果为:
```
11111:11111:11111:11111:11111
```
来分析一下这段代码,它使用了双重for循环来生成数据,程序的运行流程为:
```
# 外层循环开始第一轮循环
# 内层循环开始第一轮循环,产生了5个相同的数字并且拼接在一起
# 此时内层循环第一轮循环结束
# 将产生的5个数字后面拼接上一个冒号
# 此时结束外层循环的第一轮
# 开始外层循环的第二轮循环
# …… 后面过程省略
# 外层循环的第5轮结束。
```
双重for循环结束,我们会得到类似“11111:11111:11111:11111:11111:”的字符串,也就是最后面多了个冒号。
把这个冒号去掉方法很多,但最简单的是使用切片操作符。切片操作符用于取list或tuple中的部分元素,比如:
```
list_name = ['墨小小', '墨小妹', '墨大元', '墨当归', '墨鱼儿']
print(list_name[0:2])
```
输出结果为:
```
['墨小小', '墨小妹']
```
这里的list_name[0:2]就是对list_name的切片操作。[0:2]表示从下标为0的元素开始切,切到下标为2的元素为止,但是**不包括**下标为2的元素。也即切出来了第1个和第2个元素,所以输出结果是墨小小和墨小妹。
小墨:这个就像墨妈妈切黄瓜,我只吃头不吃把儿,她就把黄瓜头切给我。
墨博士:跟切黄瓜差不多,指定开始和结束位置就行了。如果是想从头开始切,第一个数可以不写。比如list_name[:2]一样可以得到墨小小和墨妹妹。而如果我想从某个下标开始一直切到最后,则后面一个数可以不写。比如list_name[3:]就表示从下标为3的元素开始切到最后,得到的结果是墨当归和墨鱼儿。
小墨:切片的规则还真是灵活呀,指定头和尾的下标,如果从头开始就头部坐标不指定,如果切到最后就最后下标不指定。
墨博士:还有更强大的:Python中的list支持负下标。负下标是从-1开始的,倒数第一个元素的负下标是-1,倒数第二个元素的负下标是-2,以此类推。
小墨:这个前面曾说过,list_name[-1]会得到墨鱼儿、list_name[-2]就得到墨当归。
墨博士:是的。同样的,切片也可以使用负坐标。比如list_name[-3:-1]就表示从下标为-3的元素取到下标为-1的元素,不包括下标为-1的元素本身,得到墨大元和墨当归。list_name[-3:]则表示从下标为-3的元素开始取到最后,会得到墨大元、墨当归和墨鱼儿。
小墨:我知道了。list_name[:-3]就表示从开头取到下标为-3的墨大元,会得到墨小小和墨小妹,没错吧博士?
墨博士:没错。回到我们模拟萤火虫的程序,现在得到的字符串是“11111:11111:11111:11111:11111:”,如何把最后一个冒号去掉呢?
小墨:这个字符串长度是30,所以使用result[0:29]从0切到29就可以了。哦,原来这就是你写的result[0:len(result)-1]。我再想想……,还可以使用负下标切,从开始切到最后一位,用result[:-1]就可以了。
等等,博士,关于产生25个LED对应的数字的方式,我突然有个新思路:
```
def get_image(n):
result = ''
for i in range(1, 26):
result += str(n)
if i % 5 == 0:
result += ':'
return result[:-1]
```
你看,就不需要写两个for循环了。或者我可以直接拼接29次,省去切片的麻烦:
```
def get_image(n):
result = ''
for i in range(1, 30):
if i % 6 == 0:
result += ':'
else:
result += str(n)
return result
```
怎么样博士?我厉害吧?
墨博士:厉害!青出于蓝而胜于蓝,维护世界和平,哦不,人工智能的未来,就靠你们了。
回到我们的萤火虫程序,现在get_image()函数已经能生成LED对应的数字了。想让萤火虫能从暗到亮,可以使用循环生成0~9,然后调用get_image()方法得到对应的LED的数字,显示在显示屏上。
```
for i in range(10):
img = get_image(i)
display.show(Image(img))
sleep(200)
```
这里的sleep(200)和小人儿走路程序中的delay=500作用一样,表示暂停200毫秒,这样配合着循环我们就能看到萤火虫逐渐变亮的过程了。
然后再来写一个循环,产生9~0对应的数字并显示在显示屏上,就能让萤火虫由亮变暗了。
最后,在两个for循环外套一层死循环,就能让萤火虫一直不停的由暗变亮,由亮变暗了。完整代码如下:
```
from microbit import *
import random
def get_image(n):
result = ''
for i in range(1, 30):
if i % 6 == 0:
result += ':'
else:
result += str(n)
return result
while True:
for i in range(10):
img = get_image(i)
display.show(Image(img))
sleep(200)
for i in range(10):
img = get_image(9 - i)
display.show(Image(img))
sleep(200)
```
> 动动手:策划一个下雨的动画场景,并使用micro:bit模拟。
### 11.3.5 按钮
除了25个LED组成的显示屏外,micro:bit还提供了两个按钮可供我们编程控制。左边按钮称为A,右边按钮称为B。见图11.2所示。
现在我们来写个程序,完成下面功能:
当点击A键时,屏幕上一直快速的在动态变化显示0~9;
当点击B键时,动态变化停止,屏幕上固定显示一个0~9间的数字。
小墨:这个可以和墨妹妹一起玩,我们俩每人一次,最后看谁停住的数字大谁就赢了。
墨博士:不错的主意!另外,我们还可以让游戏能一直玩下去:
```
from microbit import *
import random
def get_image():
return str(random.randint(0,9))
while True:
if button_a.is_pressed():
while True:
my_img = get_image()
display.show(my_img)
if button_b.is_pressed():
break
```
这里的“get_image”用于随机获取字符串类型的0~9。“if button_a.is_pressed():”就表示如果按下了A键。在“if button_a.is_pressed():”后又跟了一个死循环,用于屏幕一直动态刷新,在此过程中如果按了B键,则内部死循环结束,屏幕上显示最终定格的数字。
## 11.4 本章小结
墨博士总结:关于micro:bit介绍到这里就结束了。你可以访问micro:bit的官网继续深入的了解和学习。另一方面,你看本章操作micro:bit的几个案例,用的都是很简单的Python基础知识,从这方面来说,你现在的Python水平已经能做出各种各样有趣的东西了。