课程导入

在上一节课程中,我们学习了使用数字信号来控制 LED 灯(开关控制),在本节课程中,我们将要学习使用另一种信号来控制设备:模拟信号。

知识锦囊

模拟信号

模拟信号是指用连续变化的物理量表示的电信息,其信号的幅度、频率会随时间的变化进行连续变化。在日常生活中,我们将光照、湿度、温度等物理量数据使用传感器进行测量,获取其一段时间内的数值变化,并用电信号来模拟它的数值变化。例如声音信号,声音被麦克风等传感器接收并转换成电信号时,电压的高低直接反映了音量的大小,声音的频率(音调)直接转化为了电信号的频率,这就是模拟信号中“模拟”二字的含义。

当然,模拟信号也有输入和输出的区别,但与数字信号不同的是输入的模拟信号并不能像数字信号那样直接被 Pico 使用。

ADC

Pico 作为一种微控制器,和其他的微控制器一样,它的芯片内部是由成千上万个晶体管组成的,这些晶体管只能在两种状态间切换:打开(1)或者关闭(0)—-就像数字信号一样,这使得 Pico 能够直接对数字信号进行处理。而对于并不是由0和1构成的模拟信号来说, Pico 要想真正的理解它们,就必须将模拟信号转化为能被 Pico 理解的数字信号,而执行这一操作的电子元器件我们将其称为“模拟数字转换器(ADC , Analog to Digital Converter)”。在 Pico 上,就有这一电子元器件来帮助 Pico 理解输入的模拟信号。

Pico 上共有三个可被我们使用的 ADC 通道,它们分别位于引脚 GP26, GP27, 和 GP28。当你将 Pico 插接到拓展板上时,这些引脚将被接入到拓展板的 A0,A1 和 A2 模拟接口,所以当我们使用一些需要占用 ADC 通道返回模拟信号的传感器时,只能将它们插接到拓展板的 A0,A1 或 A2 接口。
页面_11.png
在本节课程中,我们就先使用能向 Pico 稳定输入模拟信号的旋转电位计来帮助大家理解模拟信号的输入。

旋转电位计

从定义上来讲,旋转式电位是指能通过旋转电位器上的调节旋钮来改变阻值的电位器,这种调节电阻的方法可以有效的减小电位器的体积,从而使其能够被应用于众多商品级的电子产品中。所以,旋转电位计虽然听起来很陌生,但在生活中我们肯定见过使用旋转电位器制作的产品,例如音响上的音量调节旋钮,各种工业设备控制台上的旋钮等。那么旋转电位计的工作原理是怎样的呢?
下图为普通旋转电位计的内部结构图:
pico插图_画板 1 副本 4.png

当你旋转旋钮时,与旋钮相连的滑动端会随旋转在电阻体上滑动。随着滑动的进行,A-B 的电阻体长度和 B-C 的电阻体长度都会发生改变,进而使阻值也发生改变,最终改变其输出电压。
利用旋转电位计我们可以很方便的向 Pico 输入不同数值的模拟信号,但要利用输入的模拟信号完成项目,我们还需要学习如何运用比较运算符来对它们进行处理。

运算符

运算符是用于在程序的各类表达式中执行代码运算的符号,而操作数则是运算符的作用对象。例如:2 > 3,其中操作数是2和3,而运算符则是“>”。根据功能的不同,运算符也可分为许多种类,例如算数运算符,比较运算符等,在本节课程中,我们先来了解一下比较运算符和逻辑运算符。

比较运算符
比较运算符,也称关系运算符,用于对常量、变量或表达式的结果进行大小比较。如果进行比较的关系式成立,则返回 True(真),反之则返回 False(假)。
其实在前几节课的项目中,你已经在各个条件判断语句中见过它们的身影,例如在上一节课利用按键开关控制LED灯亮灭的程序中,我们就使用了比较运算符 == 来判断按键开关返回值是否为1:

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

下面我将列出 Python 中所有的比较运算符以及它们的用法,当a = 1,b = 2时:

运算符 描述 实例
== 等于 - 比较对象是否相等 (a == b) 返回 False
!= 不等于 - 比较两个对象是否不相等 (a != b) 返回 true
> 大于 - 返回x是否大于y (a > b) 返回 False
< 小于 - 返回x是否小于y (a < b) 返回 true
>= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False
<= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 true

逻辑运算符
逻辑运算符可以将两个或多个简单的语句串联起来,形成更为复杂的语句。我们常在各类条件判断语句中使用它们。
常见的逻辑运算符有:

运算符 逻辑表达式 描述
and x and y 布尔”与” - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。
or x or y 布尔”或” - 如果 x 是非 0,它返回 x 的值,否则它返回 y 的计算值。
not not x 布尔”非” - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。

实践操作

接下来我们就来尝试利用旋转电位计向 Pico 输入模拟信号,来控制 LED 灯。但在这之前,我们需要先了解旋转电位计返回模拟信号的范围值。

项目一:查看旋转电位计返回值

项目实现将旋转电位计返回的模拟值显示在交互区。

硬件连接

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

  • 树莓派 Pico
  • 树莓派 Pico 拓展板
  • Grove - 旋转电位计

插接好 Pico 和拓展板,将旋转电位计连接到 A0 接口。
页面_6.png

编写程序

首先,在程序的开头导入我们所需要的函数,machine 库中的 ADC 函数和 utime 中的 sleep() 函数:

from machine import ADC
from utime import sleep

利用我们上节课所学的 from…import 来导入函数可以使我们的程序更加简洁。

接着设置引脚,利用 ADC 函数设置引脚非常简单,我们可以直接这样编写:

ROTARY_ANGLE_SENSOR = ADC(0)

ADC(0) 表示将拓展板上的 A0 接口设置为 ADC 引脚,ADC(1) 和 ADC(2) 则表示将 A1 和 A2 接口设置为 ADC 引脚。

接着设置一个循环,使用 read_u16() 读取引脚的返回值,并打印出来即可,完整程序如下:

from machine import ADC
from utime import sleep

ROTARY_ANGLE_SENSOR = ADC(0)  

while True:
    print(ROTARY_ANGLE_SENSOR.read_u16())
    sleep(1)

image.png
使用 USB 数据线将 Pico 连接到电脑,点击运行按钮将程序保存到任意位置,在交互区你就能看到旋转电位计返回的模拟值了。
image.png

转动旋转电位计可以发现数值会随着旋钮的转动发生改变,并且始终保持在 0-65535 范围内。但不管你如何旋转旋钮,其返回值都不会等于0。这是因为旋转电位计的最大阻值有限,就算将旋钮开关的阻值调到最大,也无法将电压降为0。

为什么是65535?
在程序中我们使用了 read_u16() 来读取引脚返回的模拟值,其中 u16 表示我们读取的模拟值是一个最高16位的无符号二进制整数,而16位二进制整数的最大值为1111111111111111,转化为十进制后等于65535。

项目二:旋转电位计控制LED灯亮灭

硬件连接

首先来尝试一个简单的程序,实现当旋转电位计旋转过中心点时,点亮 LED 灯。
在该项目中,我们所需要使用的硬件有:

  • Raspberry Pi Pico
  • Grove Shield for Pi Pico
  • Grove - LED Pack
  • Grove - Rotary Angle Sensor

插接好 Pico 和拓展板,使用 Grove 数据线将 LED 灯连接到 D16 接口,将旋转电位计连接到 A1 接口。
page1.png

编写程序

同样在程序的一开始先导入需要使用到 machine 库中的函数,并定义引脚:

from machine import ADC,Pin
from time import sleep

LED = Pin(16,Pin.OUT)
ROTARY_ANGLE_SENSOR = ADC(1)

接着使用 if 语句进行条件判断,当旋转电位计的返回值大于30000时,点亮 LED 灯,否则 LED 灯熄灭:

from machine import ADC,Pin
from time import sleep

LED = Pin(16,Pin.OUT)
ROTARY_ANGLE_SENSOR = ADC(1)  
while True:
    print(ROTARY_ANGLE_SENSOR.read_u16())
    if ROTARY_ANGLE_SENSOR.read_u16() > 30000:
        LED.value(1)
        sleep(1)
    else:
        LED.value(0)
        sleep(1)

image.png
在 if 语句中,我们使用了比较运算符“>”来比较从旋转电位计读取到的模拟值与30000之间的大小关系。
image.png
旋转电位计控制LED灯亮灭1.mp4
你可以一边改变if语句中所使用的比较运算符,一边测试程序的实际运行效果。值得注意的是,当我们在该程序中使用“==”来书写表达式时,很难实现想要的效果。这是因为由于模拟值的取值范围较大,当我们在旋转旋钮时,很难将其转动到某一特定的数值上使表达式成立。

除了使用比较运算符完成单一的表达式语句,我们还可以使用逻辑运算符串联两个独立的语句,从而控制 LED 灯只在某一特定数值区间内亮起:

from machine import ADC,Pin
from time import sleep

LED = Pin(16,Pin.OUT)
ROTARY_ANGLE_SENSOR = ADC(1)  
while True:
    print(ROTARY_ANGLE_SENSOR.read_u16())
    if ROTARY_ANGLE_SENSOR.read_u16() > 20000 and ROTARY_ANGLE_SENSOR.read_u16() < 40000:
        LED.value(1)
        sleep(1)
    else:
        LED.value(0)
        sleep(1)

image.png
旋转电位计控制LED灯亮灭2.mp4
image.png

思维拓展

使用 LED 灯和旋转电位计,探索更多样的运算符用法,比如当旋转电位计的读数大于30000时, LED 灯灭,否则 LED 灯亮,也可以尝试使用逻辑运算符 or ,也可以将项目二的 and 运算符改成 or ,会有什么效果呢?