品味树莓派:GPIO Zero库进阶使用

目的

GPIO Zero库在传统的GPIO使用基础上还提供了很多的进阶功能,本文将对其中的一些内容进行摘录说明。

进阶功能

Source/Values模式

GPIO Zero库提供了一种Source/Values的使用模式,有点类似于某些些上位机界面开发时用的
Binding,为的是降低代码的耦合度,减少程序员的工作量。
举个例子,如果你要通过Button来控制LED,当Button按下时点亮LED,按钮松开时熄灭LED。传统情况下你的代码大概是下面这个样子的:

from gpiozero import Button, LED
from signal import pause

led = LED(17)
button = Button(2)

button.when_pressed = lambda : led.on()
button.when_released = lambda : led.off()

pause()

通过GPIO Zero库的Source/Values模式,你的代码就可以是下面那样的了:

from gpiozero import Button, LED
from signal import pause

led = LED(17)
button = Button(2)

led.source = button # 关联button和led,当button活动时(被按下时)led活动(点亮)

pause()

可以看到用上Source/Values模式后大大简化了代码,不需要用代码检测数据源变化再做出响应,这一切都会在底层自动完成。这个例子中Button的状态是Values,实际使用中我们可以用各种东西当作Values,比如下面例子:
在这里插入图片描述
上图中通过CPU温度来调节LED亮度。
默认情况下CPUTemperature类将0 ~ 100摄氏度映射成0 ~ 1的值,实际使用时可以手动调整温度区间,比如使用 temp = CPUTemperature(min_temp=40, max_temp=90) 会将40 ~ 90摄氏度映射成0 ~ 1的值。

前面例子中数据都是来自库中类的对象,其实我们也可以用自己的可迭代数据作为Values:

from gpiozero import LED
from signal import pause

data = [1, 0, 1, 0, 1, 0, 1, 0, 1, 0]

led = LED(17)
led.source_delay = 1 # 设置数据驱动刷新速度为1秒一次(默认为0.01秒)
led.source = data

pause()

下面例子是使用迭代器作为Values:

from gpiozero import LED
from random import randint
from signal import pause

def rand():
    while True:
        yield randint(0, 1)

led = LED(17)
led.source = rand()

pause()

上面例子都是一个值来驱动一个对象,我们也可以用多个值来驱动多个对象:

from gpiozero import LED, Button
from gpiozero.tools import all_values, any_values
from signal import pause

led1 = LED(2)
led2 = LED(4)
btn1 = Button(20)
btn2 = Button(21)

led1.source = all_values(btn1, btn2) # 两个按钮都按下时点亮led1
led2.source = any_values(btn1, btn2) # 任意按钮都按下时点亮led2

pause()

更多内容可以参考:https://gpiozero.readthedocs.io/en/stable/source_values.html

Device Source Tools

这一章节的内容是用来配合上一章节Source/Values使用的,上一章节说了Source/Values关系绑定前可以做各种处理,GPIO Zero库中提供了很多工具用来方便的做出这些处理。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
GPIO Zero库中提供的工具蛮多,每一个都写了例程,可以参考下面连链接:
https://gpiozero.readthedocs.io/en/stable/api_tools.html

高级设备类库

GPIO Zero库对于IO口的管理控制上有很多方便的功能,这章节就介绍下其中的 LEDBoardButtonBoard 两项功能。
在前面文章介绍LED、PWMLED、Button的时候都是单个的进行声明、控制与应答的,在GPIO Zero库中我们除了单个控制外还可以整组的控制,主要由下面两个类实现相关功能:

  • class gpiozero.LEDBoard(*pins, pwm=False, active_high=True, initial_value=False, pin_factory=None, **named_pins)
  • class gpiozero.ButtonBoard(*pins, pull_up=True, active_state=None, bounce_time=None, hold_time=1, hold_repeat=False, pin_factory=None, **named_pins)

观察上面的构造函数会发现它们和LED、PWMLED、Button的构造函数是很像的,如果你去查看类库可以发现不光是构造函数,其它的属性和方法等两者也是非常相似的,实际上两者的具体操作使用是差不多的。下面进行简单的演示:

from gpiozero import LEDBoard
from time import sleep

leds = LEDBoard(2, 3, 4, 17) # GPIO2 3 4 17上分别接了LED

def printandsleep():
    print('{} {} {} {}'.format(leds[0].value, leds[1].value, leds[2].value, leds[3].value))
    sleep(2)

leds.on() # 点亮所有LED
printandsleep()

leds.off() # 熄灭所有LED
printandsleep()

leds.on(0) # 点亮第一个LED(GPIO2),同leds[0].on()
printandsleep()

leds[-1].on() # 点亮最后一个LED(GPIO17),同leds.on(-1),这里也等同于leds.on(3)
printandsleep()

leds.on(1, 2) # 点亮第2、3个LED(GPIO3、GPIO4)
printandsleep()

for led in leds[2:]:  # 选择第3、4个LED(GPIO4、GPIO17)
    led.off()
printandsleep()

for led in leds[::2]: #从0开始步进为2选择LED,这里相当于第0、2个
    led.toggle() # 翻转LED
printandsleep()

在这里插入图片描述
上面是基础的LED操作,下面再演示下PWMLED和Button的操作:

from gpiozero import LEDBoard, ButtonBoard
from time import sleep
from signal import pause

leds = LEDBoard(pwm=True, led0=2, led1=3) # GPIO2 3上分别接了LED, 相当于leds = LEDBoard(2, 3, pwm=true)

leds.led0.pulse() # 使led0以呼吸灯方式闪烁
leds.led1.value = 0.5 # 以50%占空比点亮led1
print('{} {}'.format(leds.led0.value, leds.led1.value))
sleep(3)

btns = ButtonBoard(17, 27) # GPIO17 27上分别接了Button
leds.source = btns.values # 该行将led0与第一个button绑定(GPIO17)、将led1与第二个button绑定(GPIO27)
pause()

上面代码中先接了两个LED,用PWM方式进行了控制,然后声明了两个Button,将LED和Button以上面的Source/Values方式进行绑定,分别按下按钮,LED分别会有响应。

这个章节可以说的内容其实挺多,但是其中很多东西都是基于具体的某个电路或成品的电路模块来设计的,这里就不进一步展开了,更多内容可以参考下面链接:
https://gpiozero.readthedocs.io/en/stable/recipes_advanced.html
https://gpiozero.readthedocs.io/en/stable/api_boards.html

异常

GPIO Zero库中设计了对相关操作异常的反馈,可以使用 try...except... 语句进行捕获处理:
在这里插入图片描述
GPIO Zero库定义了哪些异常可以参考下面链接:
https://gpiozero.readthedocs.io/en/stable/api_exc.html

Internal Devices

GPIO Zero库中提供了几个Internal Devices,用于获取树莓派的一些信息,下面分别列举进行简单说明:

  • TimeOfDay
    class gpiozero.TimeOfDay(start_time, end_time, *, utc=True, pin_factory=None)
    用来标示一天中某一时间段处于活动状态,start_time和end_time分别表示设备激活起始与结束时间,utc True表示使用UTC时间、False表示使用本地时间。
    TimeOfDay对象有value属性,其值为True表示处于start_time和end_time时间之间。

  • PingServer
    class gpiozero.PingServer(host, *, pin_factory=None)
    ping host,如果能ping通则其value属性为True。

  • CPUTemperature
    class gpiozero.CPUTemperature(sensor_file='/sys/class/thermal/thermal_zone0/temp', *, min_temp=0.0, max_temp=100.0, threshold=80.0, pin_factory=None)
    获取CPU温度、对温度进行数值映射、设置报警阈值。

  • LoadAverage
    class gpiozero.LoadAverage(load_average_file='/proc/loadavg', *, min_load_average=0.0, max_load_average=1.0, threshold=0.8, minutes=5, pin_factory=None)
    设置将CPU平均负载映射为某一只区间,同时设置阈值,value值高于阈值时以活动表示。

  • DiskUsage
    class gpiozero.DiskUsage(filesystem='/', *, threshold=90.0, pin_factory=None)
    设置阈值,当磁盘空间使用率超过该值时以活动表示。

下面是简单的测试例子:

from gpiozero import TimeOfDay, PingServer, CPUTemperature, LoadAverage, DiskUsage
from datetime import time

am = TimeOfDay(time(10), time(11), utc=False)
pm = TimeOfDay(time(20), time(21), utc=False)
print('TimeOfDay 10~11h: {}'.format(am.value))
print('TimeOfDay 20~21h: {}'.format(pm.value))

google = PingServer('google.com')
baudu = PingServer('baidu.com')
print('Ping google: {}'.format(google.value))
print('Ping baudu: {}'.format(baudu.value))

temp = CPUTemperature()
print('CPU temperature: {}C'.format(temp.temperature))
print('CPU temperature value: {}'.format(temp.value))

la = LoadAverage()
print('LoadAverage {}'.format(la.is_active))
print('LoadAverage {}'.format(la.value))

disk = DiskUsage()
print('DiskUsage {}'.format(disk.is_active))
print('DiskUsage {}'.format(disk.value))

在这里插入图片描述
这一节介绍的很多内容其实就算不依赖GPIO Zero库提供的这些工具我们也有别的方法可以获取,不过使用上面的工具最大的好处是直接可以在Source/Values模式中作为Values使用。更多详细说明可以参考下面链接:
https://gpiozero.readthedocs.io/en/stable/api_internal.html

Pin Factory

GPIO Zero库对很多GPIO相关功能进行了封装,但它自己并不实现GPIO口底层的操作,而是借由一些现有的库来实现,Pin Factory就是用来连接上层和底层库的。
在这里插入图片描述
默认情况下大部分GPIO Zero库功能都是由RPi.GPIO库来实现的,你也可以通过Pin Factory来更改所使用的库,更改的方式很多,比如在终端中通过命令更改:

# 修改默认库为native
export GPIOZERO_PIN_FACTORY=native

你也可以在python代码中更改:

from gpiozero.pins.native import NativeFactory
from gpiozero import Device, LED

Device.pin_factory = NativeFactory() # 使用native库

led1 = LED(16) # 这里的LED就用了native库

或者也可以用下面方式设置:

from gpiozero.pins.native import NativeFactory
from gpiozero import LED

my_factory = NativeFactory()

led1 = LED(16, pin_factory=my_factory) # 这里的LED就用了native库

下面是目前可选用的库:

NameFactory classPin class
rpigpiogpiozero.pins.rpigpio.RPiGPIOFactorygpiozero.pins.rpigpio.RPiGPIOPin
rpiogpiozero.pins.rpio.RPIOFactorygpiozero.pins.rpio.RPIOPin
pigpiogpiozero.pins.pigpio.PiGPIOFactorygpiozero.pins.pigpio.PiGPIOPin
nativegpiozero.pins.native.NativeFactorygpiozero.pins.native.NativePin

除上面外其实还有一个库 Mock - gpiozero.pins.mock.MockFactory 这个库是个虚拟的库,主要用于没有树莓派的时候开发测试使用。

Pin Factory这个功能主要是为了提供更多可能和个性化选择,另外在远程控制GPIO的时候也需要用到这个功能。 更详细说明可以参考下面链接:
https://gpiozero.readthedocs.io/en/stable/api_pins.html

总结

上文介绍的GPIO Zero库的一些特性更加贴近用户和上位机软件开发者,确实的可以带来很多便利性。GPIO Zero库进阶使用功能非常多,本文无法一一进行介绍,更多内容可以参考下面官方文档:
https://gpiozero.readthedocs.io/en/stable/index.html

/usr/local/lib/python3.8/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from rpigpio: No module named 'RPi' warnings.warn( /usr/local/lib/python3.8/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from lgpio: No module named 'lgpio' warnings.warn( /usr/local/lib/python3.8/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from rpio: No module named 'RPIO' warnings.warn( /usr/local/lib/python3.8/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from pigpio: No module named 'pigpio' warnings.warn( /usr/local/lib/python3.8/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from native: unable to locate Pi revision in /proc/device-tree or /proc/cpuinfo warnings.warn( Traceback (most recent call last): File "fan.py", line 3, in <module> fan=OutputDevice(pin=121) File "/usr/local/lib/python3.8/dist-packages/gpiozero/devices.py", line 108, in __call__ self = super(GPIOMeta, cls).__call__(*args, **kwargs) File "/usr/local/lib/python3.8/dist-packages/gpiozero/output_devices.py", line 83, in __init__ super(OutputDevice, self).__init__(pin, pin_factory=pin_factory) File "/usr/local/lib/python3.8/dist-packages/gpiozero/mixins.py", line 85, in __init__ super(SourceMixin, self).__init__(*args, **kwargs) File "/usr/local/lib/python3.8/dist-packages/gpiozero/devices.py", line 540, in __init__ super(GPIODevice, self).__init__(**kwargs) File "/usr/local/lib/python3.8/dist-packages/gpiozero/devices.py", line 250, in __init__ Device.pin_factory = Device._default_pin_factory() File "/usr/local/lib/python3.8/dist-packages/gpiozero/devices.py", line 291, in _default_pin_factory raise BadPinFactory('Unable to load any default pin factory!') gpiozero.exc.BadPinFactory: Unable to load any default pin factory!
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Naisu Xu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值