课程导入

在上一节课程中,我们讲解了循环结构,并在实践操作中利用循环结构实现了能让 LED 灯不断闪烁的 Blink 项目。而在现实应用层面,我们不可能在每次需要打开和关闭 LED 灯时,都对它进行一次编程。更多的时候我们还是使用一些外部的硬件设备来控制它的亮灭——例如最简单的按键开关。在本节课中,我们就将学习如何利用按键开关来控制 LED 灯的状态。

知识锦囊

不管是实现利用按键开关控制 LED 灯亮灭,还是使用 Pico 控制其他各类电子模块,其关键都在于信号的传递,而在电子电路中,从表现形式上我们一般将信号分为两类:数字信号和模拟信号。

数字信号

简单来说,数字信号就是以0、1这样的二进制形式表示的信号,之所以采用二进制的形式表示信号, 其根本原因是在电路中往往只存在两种状态,即电路的通与断。

对于 Pico 而言,其众多的引脚中拥有许多可以进行输入和输出数字信号的引脚,在使用这些引脚传输数字信号时,我们只需要根据需求的不同,来将其配置为不同类型的引脚即可。其实在上一节课程中,我们已经进行了很多次数字引脚的配置与使用,例如:

  1. mport machine
  2. LED = machine.Pin(16,machine.Pin.OUT)
  3. LED.value(1)

该程序就已经将引脚 16 设置为了输出模式,并向该引脚写入了一个高电平来点亮 LED 灯。

选择结构

在前面的课程里,我们已经学习过三种基本程序结构中的顺序结构和循环结构,还有一种为选择结构。选择结构就是根据给定的条件进行判断,根据判断的结果来执行相应的操作。比如判断今天是否下雨,如果下雨则带伞,如果不下雨,则不带伞。在 Python 中,可以使用 “if….else” 语句进行条件判断,包含以下三种句式:

if 语句:

这是最简单的条件判断,如果表达式为真,则执行代码块,如果表达式不成立,则什么都不执行。例如判断是否下雨,下雨则带伞,并未对不下雨的状态做任何动作。

  1. if 表达式:
  2. 代码块

if……else 语句:

如果表达式为真,则执行代码块1,如果表达式不成立,则执行代码块2。例如判断是否下雨,下雨则带伞,没有下雨则不带伞。

  1. if 表达式:
  2. 代码块 1
  3. else:
  4. 代码块 2

if……elif……else 语句:

该语句用于多种条件判断,Python 会从上到下逐个判断表达式是否成立,一旦遇到某个成立的表达式,就执行后面紧跟的代码块;此时,剩下的代码就不再执行了,不管后面的表达式是否成立。如果所有的表达式都不成立,就执行 else 后面的代码块。

  1. if 表达式 1
  2. 代码块 1
  3. elif 表达式 2
  4. 代码块 2
  5. elif 表达式 3
  6. 代码块 3
  7. ...//其它elif语句
  8. else
  9. 代码块 n

实践操作

接下来,让我们回到项目中实践刚才所学知识。在第一个项目中,我们先来看看如何使用按键开关简单控制 LED 灯的亮灭。

项目一:按键控制LED灯亮灭

在该项目中,我们通过按键开关来实现简单的 LED 灯亮灭,当按下按键时, LED 灯亮起,当松开按键时, LED 灯熄灭。

硬件连接

在该项目中,我们所需要使用的硬件有:

  • 树莓派 Pico
  • 树莓派 Pico 拓展板
  • Grove - LED 灯
  • Grove - 按键开关

Grove - 按键开关是一个简单的按键开关,当按键被按下时,它的返回值为1,当按键没有被按下时,返回值为0。
同样插接好 Pico 和拓展板,并使用 Grove 数据线将按键开关连接到 D16 接口,将 LED 灯连接到 D18 接口。
页面_4.png

编写程序

在程序的开头我们需要导入 machine 库,并利用库中的 Pin 模块来为两个电子模块设置引脚。

  1. import machine
  2. BUTTON = machine.Pin(16,machine.Pin.IN)
  3. LED = machine.Pin(18,machine.Pin.OUT)

与之前的程序不同的是,首先我们在引入库中模块时,我们除了需要使用 Pin.OUT 来将18号引脚设置为输出引脚,也同时需要使用 Pin.IN 来将18号引脚设置为输入引脚,以接收按键开关返回的数据。

设置完引脚后,我们需要使用以下代码获取按键开关返回的数值:

  1. val = BUTTON.value()

在该行代码中,我们使用value()函数来读取按键开关的返回值,如果你还记得,我们在之前的程序中也使用过value()函数来为LED灯写入值。
其用法的区别是,当在value()函数括号内写入数值时,它会向引脚输出该数值,例如:

  1. LED.value(1)

而当括号内没有数值时,它会读取该引脚的输入值。
最后我们使用条件语句 if ,来进行条件判断,当按键开关被按下时,返回值为1, LED 灯亮起,反之 LED 灯熄灭:

  1. while True:
  2. val = BUTTON.value()
  3. if val == 1:
  4. LED.value(1)
  5. else:
  6. LED.value(0)

完整示例程序如下:

  1. import machine
  2. BUTTON = machine.Pin(16,machine.Pin.IN)
  3. LED = machine.Pin(18,machine.Pin.OUT)
  4. while True:
  5. val = BUTTON.value()
  6. if val == 1:
  7. LED.value(1)
  8. else:
  9. LED.value(0)

image.png
使用 USB 数据线将 Pico 连接到电脑,点击运行按钮将程序保存到任意位置,按下按键开关,你就能看到程序的实际运行效果。
按键控制LED灯亮灭.mp4
image.png

项目二:按键台灯

通过观察项目一程序的实现效果,可以发现 LED 灯只有在按键开关处于被按下的状态时才会亮起,当我们松开手指,LED 灯会马上熄灭。这和我们生活中常见的按一下打开,再按一下关闭的按键灯并不相同。接下来,我们就来实现这个效果。

编写程序

首先导入需要用到的 machine 库和 utim e库,并为按键开关与 LED 灯配置引脚。

  1. import machine
  2. import utime
  3. BUTTON = machine.Pin(16,machine.Pin.IN)
  4. LED = machine.Pin(18,machine.Pin.OUT)

刚才的程序之所以没有实现我们想要的效果,是因为我们直接使用了按键开关返回的值来控制 LED 灯,而按键开关只有在被按下时才会返回1,当它被松开时会返回0。
因此我们不能直接使用按键开关来进行控制,而是需要创建一个变量,通过这个变量来间接控制 LED 灯亮灭

所以我们需要在程序中先新建一个变量,并将它的初始值设置为0:

  1. val = 0

再在 while True 中编写程序,每当按键开关被按下时,就让该变量的值增加1:

  1. while True:
  2. if BUTTON.value() == 1:
  3. val = val+1
  4. sleep(1)

我们只需要该变量的值在0和1之间进行切换,所以当该变量的值被增加到2时,就让它重新归0。在这里,我们可以使用 elif 在一个 if 语句中添加额外的判断条件:

  1. while True:
  2. if BUTTON.value() == 1:
  3. val = val+1
  4. sleep(1)
  5. elif val == 2:
  6. val = 0
  7. sleep(1)

这样我们设置的变量 val 的值就能在每次按下按钮时,在0和1间进行切换了,最后使用该变量来完成对 LED 灯的控制即可,完整程序如下:

  1. import machine
  2. import utime
  3. BUTTON = machine.Pin(16,machine.Pin.IN)
  4. LED = machine.Pin(18,machine.Pin.OUT)
  5. val = 0
  6. while True:
  7. if BUTTON.value() == 1:
  8. val = val+1
  9. utime.sleep(1)
  10. elif val == 2:
  11. val = 0
  12. utime.sleep(1)
  13. LED.value(val)

image.png
按键台灯.mp4

思维拓展

当你编写该程序时,你会发现自己在每一次引用库中的函数时都需要在前面标注函数被引用自 machine 库,程序编写起来相对繁琐:

  1. import machine
  2. import utime
  3. BUTTON = machine.Pin(16,machine.Pin.IN)
  4. LED = machine.Pin(18,machine.Pin.OUT)
  5. utime.sleep(1)

在这里我们可以用一种更为简洁的写法来编写程序:

  1. from machine import Pin
  2. from utime import sleep
  3. BUTTON = Pin(16,Pin.IN)
  4. PWM_LED = PWM(Pin(18))
  5. sleep(1)

与 import 导入一整个库不同,from…import 只导入了库中的一些函数。当我们使用 from…import 导入包所要使用函数的类后,因为我们在导入时已经声明了该函数来自哪个库中,所以在后面的程序中我们可以直接使用该函数,无需再一次声明该函数来自哪个库中。