品味樹莓派: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庫

下面是目前可選用的庫:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章