学习资料来自Get started with MicroPython on Raspberry Pi Pico

所需材料

  • 树莓派Pico
  • 一块面包板
  • 一个绿色LED,一个黄色(或琥珀色)LED,一个红色LED
  • 三个330Ω的电阻
  • 一个压电式蜂鸣器
  • 公对公跳线若干

简单信号灯

连接电路

与之前一样,使LED跨国中心缝,并组装电阻,如下图所示:

dda62e9702c2b229aae4e3621be57f5e.png

实物图(效果图):

dcb6460e444fe40b40d9529867c7c74e.jpg

一定要牢记LED需要一个限流的电阻。如果忘了连接电阻,最好的结果是LED烧坏并停止工作,最坏的结果是Pico损坏。

代码实现

首先,还是导入所需模块

1
2
import machine
import utime

定义每一个LED

1
2
3
led_red = machine.Pin(15, machine.Pin.OUT)
led_amber = machine.Pin(14, machine.Pin.OUT)
led_green = machine.Pin(13, machine.Pin.OUT)

真正的信号灯不会停掉,所以要实现无限循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
while True:
led_red.value(1)
utime.sleep(5)
led_amber.value(1)
utime.sleep(2)
led_red.value(0)
led_amber.value(0)
led_green.value(1)
utime.sleep(5)
led_green.value(0)
led_amber.value(1)
utime.sleep(5)
led_amber.value(0)

“海鹦”式路口信号灯

项目设计

真正的信号灯并不是只为车辆服务的,它们也需要保护行人。在英国,最常见的信号灯被称为pedestrian-operated user-friendly intelligent crossings或puffin crossings。

为使之成为“海鹦”式路口信号灯,我们还需要一个开关(以使行人能告知信号灯以便安全地穿过马路)和一个蜂鸣器(以便使行人能知道他们该合适穿过马路)

连接电路

5f0e9bed567ff265700bc513c8aa63be.png

代码实现

拆解分析

定义按钮与蜂鸣器

1
2
button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN)
buzzer = machine.Pin(12, machine.Pin.OUT)

对于基本的信号灯,这足够了。但如果要实现“海鹦”式,那么我们需要记录按钮是否被摁下,同时不打断信号灯亮的进程。为实现这一点,我们需要再导入一个库_thread

1
import _thread

在开始另一个线程之前,我们需要使新线程能像主线程传递信息。为实现这一点,我们可以是用全局变量。

buzzer =这一行下面,添加

1
2
global button_pressed
button_pressed = False

上面的代码将button_pressed设置为全局变量,并设定默认值为False——也就是说程序开始时按钮尚未被按下。

下一步就是定义新线程

1
2
3
4
5
6
def button_reader_thread():
global button_pressed
while True:
if button.value() == 1:
button_pressed = True
utime.sleep(0.01)

第一行我们给新的线程定义了一个形象的名字。

第二行让Micro Python知道我们即将改变全局变量button_pressed的值。如果没有这一行,我们就无法改变该全局变量的值。

接着,我们又开始了一个循环。

下一行,我们检查button_value()是否等于1。当按钮被按下时,值为1;未被按下时,值为0。只有button_value()1时,我们才把button_pressed设置为True,以便让程序后面知道该按钮被按下了。

随后,用utime.sleep(0.01)让程序停下非常短的时间,以免循环运行地太快了。

注意到在此线程中,按钮被释放我们并没有把button_pressed重设为False,原因如下:在一个信号灯周期中,行人随时可以按下按钮,但只有信号灯变红和能够安全通过时才能起作用。新线程所要做的就是在按钮摁下时改变变量,当行人安全通过路口后我们的主线程会将其重设为False

仅仅定义一个线程并不会直接让它运行,要想开始一个线程,我们需要告知_thread库。

在我们定义的线程后再加一行,并删去自动生成的缩进:

1
_thread.start_new_thread(button_reader_thread, ())

找到主循环,并在while True那一行下面添加

1
2
3
4
5
6
7
8
9
if button_pressed == True:
led_red.value(1)
for i in range(10):
buzzer.value(1)
utime.sleep(0.2)
buzzer.value(0)
utime.sleep(0.2)
global button_pressed
button_pressed = False

这一部分代码用于检查全局变量button_pressed的值以确定按钮是否被按下。如果确被按下,那么使红灯亮并使蜂鸣器响十次的那部分代码就会开始运行。

完整代码

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
import machine
import utime
import _thread

led_red = machine.Pin(15, machine.Pin.OUT)
led_amber = machine.Pin(14, machine.Pin.OUT)

led_green = machine.Pin(13, machine.Pin.OUT)
button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN)
buzzer = machine.Pin(12, machine.Pin.OUT)

global button_pressed
button_pressed = False

def button_reader_thread():
global button_pressed
while True:
if button.value() == 1:
button_pressed = True
utime.sleep(0.01)
_thread.start_new_thread(button_reader_thread, ())

while True:
if button_pressed == True:
led_red.value(1)
for i in range(10):
buzzer.value(1)
utime.sleep(0.2)
buzzer.value(0)
utime.sleep(0.2)
global button_pressed
button_pressed = False
led_red.value(1)
utime.sleep(5)
led_amber.value(1)
utime.sleep(2)
led_red.value(0)
led_amber.value(0)
led_green.value(1)
utime.sleep(5)
led_green.value(0)
led_amber.value(1)
utime.sleep(5)
led_amber.value(0)