跳到主要内容

从RPi.GPIO移植

如果您熟悉 RPi.GPIO 库,就会习惯于编写处理引脚和引脚状态的代码。在本文档的示例中,您会发现我们通常使用的是 LED 和 Button,而不是输入引脚和输出引脚。

GPIO Zero 提供了代表设备的类,因此,与其说有一个引脚编号并告诉它高电平,不如说有一个 LED 并告诉它亮起来;与其说有一个引脚编号并询问它是高电平还是低电平,不如说有一个按钮并询问它是否按下。此外,GPIO Zero 没有模板代码,只需导入需要的部分即可。

GPIO Zero 提供了许多设备类,每个类都有专门针对该设备的特定方法和属性。例如,HC-SR04 距离传感器的功能可在 DistanceSensor 类中找到。

除了特定的设备类,我们还提供基类 InputDeviceOutputDevice。这些类与 RPi.GPIO 中对应类的一个主要区别是,它们是类而不是函数,这意味着您需要初始化一个类,并提供其引脚编号,但之后您再也不需要使用该引脚编号,因为它已被对象存储。

GPIO Zero 最初只是 RPi.GPIO 的顶层,但后来我们增加了对其他各种底层引脚库的支持。RPi.GPIO 目前是默认使用的引脚库。如需了解更多信息,请参阅 更改引脚工厂

输出设备

RPi.GPIO 中打开 LED:

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(2, GPIO.OUT)

GPIO.output(2, GPIO.HIGH)

在 GPIO Zero 中打开 LED:

from gpiozero import LED

led = LED(2)

led.on()

LED 类还通过 blink() 方法支持线程闪烁。

OutputDevice 是输出设备的基类,其使用方式与 RPi.GPIO 中的输出设备类似。

请查看支持的 输出设备 的完整列表。其他输出设备也有类似的属性和方法名称。基类的命名有共性,如 OutputDevice.is_active,在设备类中有别名,如 LED.is_lit

输入设备

RPi.GPIO 中读取按下的按钮:

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)

if not GPIO.input(4):
print("button is pressed")

在 GPIO Zero 中读取按下的按钮:

from gpiozero import Button

btn = Button(4)

if btn.is_pressed:
print("button is pressed")

请注意,在 RPi.GPIO 示例中,按钮的设置选项是 GPIO.PUD_UP,意思是 "上拉",因此当按钮未按下时,引脚为高电平。当按钮被按下时,引脚变为低电平,因此需要否定条件(if not)。如果按钮配置为下拉,则逻辑相反,条件将变为 if GPIO.input(4)

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(4, GPIO.IN, GPIO.PUD_DOWN)

if GPIO.input(4):
print("button is pressed")

在 GPIO Zero 中,按钮的默认配置是上拉,但可以在初始化时进行配置,其余代码保持不变:

from gpiozero import Button

btn = Button(4, pull_up=False)

if btn.is_pressed:
print("button is pressed")

RPi.GPIO 还支持阻塞边缘检测。

在 RPi.GPIO 中等待上拉按钮被按下:

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)

GPIO.wait_for_edge(4, GPIO.FALLING):
print("button was pressed")

GPIO Zero 中的等效值:

from gpiozero import Button

btn = Button(4)

btn.wait_for_press()
print("button was pressed")

同样,如果按钮被下拉,逻辑就会颠倒。我们不再等待下降沿,而是等待上升沿:

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)

GPIO.wait_for_edge(4, GPIO.FALLING):
print("button was pressed")

同样,在 GPIO Zero 中,唯一的区别在于初始化:

from gpiozero import Button

btn = Button(4, pull_up=False)

btn.wait_for_press()
print("button was pressed")

RPi.GPIO 具有线程回调功能。您需要创建一个函数(必须包含一个参数),并将其与引脚编号和边缘方向一起传递给 add_event_detect

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

def pressed(pin):
print("button was pressed")

def released(pin):
print("button was released")

GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)

GPIO.add_event_detect(4, GPIO.FALLING, pressed)
GPIO.add_event_detect(4, GPIO.RISING, released)

在 GPIO Zero 中,通过分配 when_pressedwhen_released 属性,可以为这些操作设置回调:

from gpiozero import Button

def pressed():
print("button was pressed")

def released():
print("button was released")

btn = Button(4)

btn.when_pressed = pressed
btn.when_released = released

此外,还提供了 when_held,其中 "hold" 的时间长度是可配置的。

回调函数不需要任何参数,但如果需要参数,则会传入按钮对象,以便确定是哪个按钮调用了函数。

InputDevice 是输入设备的基类,其使用方式与 RPi.GPIO 中的输入设备类似。

查看 输入设备 的完整列表。其他输入设备也有类似的属性和方法名称。基类中的命名存在共性,如 InputDevice.is_active,在设备类中有别名,如 Button.is_pressedLightSensor.light_detected

复合设备、电路板和附件

有些设备需要连接多个引脚,例如距离传感器、LED 组合或 HAT。有些 GPIO Zero 设备在一个对象中包含多个设备连接,如 RGBLED、LEDBoardDistanceSensorMotorRobot

使用 RPi.GPIO,您将有一个输出引脚用于触发,一个输入引脚用于回音。您将为回音计时并计算距离。使用 GPIO Zero,您只需创建一个 DistanceSensor 对象,指定触发器和回声引脚,然后读取 DistanceSensor.distance 属性,该属性会在类的实现过程中自动计算距离。

电机()Motor) 类控制两个输出引脚,用于驱动电机前进或后退。机器人(Robot) 类控制四个输出引脚(两个电机)的正确组合,以驱动机器人前进或后退以及左右转动。

LEDBoard 类可接受任意数量的引脚,每个引脚控制一个 LED。生成的 LEDBoard 对象可用于一起控制所有 LED(全部打开/全部关闭),或按索引单独控制。此外,还可以对该对象进行迭代,按顺序打开 LED。请参阅 高阶用法 中的相关示例(包括切片)。

PWM(脉宽调制)

这两个库都支持对任何引脚进行软件 PWM 控制。根据所使用的引脚库,GPIO Zero 也可以支持硬件 PWM(使用 RPIOPinPiGPIOPin)。

使用 PWM 的一个简单例子是控制 LED 的亮度。

RPi.GPIO

import RPi.GPIO as GPIO
from time import sleep

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(2, GPIO.OUT)
pwm = GPIO.PWM(2, 100)
pwm.start(0)

for dc in range(101):
pwm.changeDutyCycle(dc)
sleep(0.01)

在 GPIO Zero 中:

from gpiozero import PWMLED
from time import sleep

led = PWMLED(2)

for b in range(101):
led.value = b / 100.0
sleep(0.01)

PWMLED 有一个 blink() 方法,其使用方法与 LEDblink() 方法相同,但其 PWM 功能允许提供 淡入(fade_in) 和 淡出(fade_out) 选项。此外,pulse() 方法还提供了一种让 LED 重复淡入淡出的巧妙方法。

其他设备也可以使用 PWM,如电机(用于变速)和伺服。有关信息,请参阅电机(Motor)、伺服(Servo)和角伺服(AngularServo)类。电机和机器人默认使用 PWM,但可以在初始化时使用 pwm=False 将其禁用。如果没有 PWM,则无法使用伺服电机。包含 LED 的设备默认不使用 PWM,但可以指定 pwm=True,设备中的任何 LED 对象都将初始化为 PWMLED 对象。

清理

引脚状态清理在 RPi.GPIO 中是显式的,通过 GPIO.cleanup() 手动完成,但在 GPIO Zero 中,脚本结束时会自动对使用的每个引脚进行清理。手动清理可通过使用设备上的 close() 方法进行。

请注意,只有在脚本正常终止时才会进行清理。如果脚本因程序错误而退出,则不会执行清理。为确保在出现异常后执行清理,必须对异常进行处理,例如

from gpiozero import Button

btn = Button(4)

while True:
try:
if btn.is_pressed:
print("Pressed")
except KeyboardInterrupt:
print("Ending program")

请阅读相关常见问题: 与 GPIO.cleanup() 对应的 gpiozero 是什么?

Pi信息

RPi.GPIO 提供有关您正在使用的 Pi 的信息。GPIO Zero 中的对应函数是 pi_info()

>>> from gpiozero import pi_info
>>> pi = pi_info()
>>> pi
PiBoardInfo(revision='a02082', model='3B', pcb_revision='1.2', released='2016Q1', soc='BCM2837', manufacturer='Sony', memory=1024, storage='MicroSD', usb=4, ethernet=1, wifi=True, bluetooth=True, csi=1, dsi=1, headers=..., board=...)
>>> pi.soc
'BCM2837'
>>> pi.wifi
True

进一步了解 PiBoardInfo 提供的功能。

更多

GPIO Zero 提供的不仅仅是 GPIO 设备支持,还包括对 SPI设备 的一些支持,包括一系列模数转换器。

它还提供了与其他 GPIO 设备兼容但与 GPIO 引脚无关的设备类,如 CPUTemperatureTimeOfDayPingServerLoadAverage

GPIO Zero 支持多个引脚库。默认情况下使用 RPi.GPIO 控制引脚,但也可以选择使用其他库,如支持网络控制 GPIO 的 pigpio。更多信息,请参阅 更改引脚工厂配置远程GPIO

使用 Mock引脚 可以在 PC 上运行 GPIO Zero,用于远程 GPIO 和测试目的。

该库的另一个功能是以逻辑方式配置连接在一起的设备,例如,在一行中可以说 LED 和按钮 "配对",即按下按钮会打开 LED。请参阅 源与值 中的相关内容。

常见问题

请注意以下常见问题,它们可能会让过于熟悉 RPi.GPIO 的用户不知所措:


中文翻译版以英文版相同知识授权方式共享:BSD-3-Clause。交流 Q群:498908352