目的
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口的管理控制上有很多方便的功能,这章节就介绍下其中的 LEDBoard 和 ButtonBoard 两项功能。
在前面文章介绍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库
下面是目前可选用的库:
Name | Factory class | Pin class |
---|---|---|
rpigpio | gpiozero.pins.rpigpio.RPiGPIOFactory | gpiozero.pins.rpigpio.RPiGPIOPin |
rpio | gpiozero.pins.rpio.RPIOFactory | gpiozero.pins.rpio.RPIOPin |
pigpio | gpiozero.pins.pigpio.PiGPIOFactory | gpiozero.pins.pigpio.PiGPIOPin |
native | gpiozero.pins.native.NativeFactory | gpiozero.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