Raspberry Pi 5でGPIOするPythonコード

Seeed K.K.の松岡です。
Raspberry PiでGPIOやI2Cなどハードウェア制御するときにはpigpioを使っています。pigpioは、わたしがよく使うインターフェイス(GPIO, PWM, I2C, SPI, UART)の全てに対応しています。長いこと使っていますが困ったことは(1回を除いて)ありません。完全に頼り切っています。
しかしながら、新しいラズパイ、Raspberry Pi 5ではpigpioが使えません😢。ハードウェアが大きく変わっているので使えるようにするには大変ですわね...
そんなわけで、Raspberry Pi 5でGPIO, PWM, I2C, SPI, UARTするPythonコードを調べてまとめました。

デジタル入力

import gpiozero
import time

pin = gpiozero.DigitalInputDevice(pin=27, pull_up=True)
try:
    while True:
        print(pin.value)
        time.sleep(1)
finally:
    pin.close()
  • Raspberry Pi公式のドキュメントがgpiozeroだったので、gpiozeroで。
  • Raspberry Pi OSに標準でインストールされていました。
  • InputDeviceとDigitalInputDeviceのどちらを使うか迷うところ。下記デジタル出力と同じ階層のDigitalInputDeviceに。
  • pull_up=Trueするとactive_state=Falseになる。
  • お試し回路は、GPIO17にタクトスイッチを接続して、スイッチを押すとGNDに繋がるように。

デジタル出力

import gpiozero
import time

pin = gpiozero.DigitalOutputDevice(pin=17)
try:
    while True:
        pin.on()
        time.sleep(0.2)
        pin.off()
        time.sleep(0.8)
finally:
    pin.close()
  • Raspberry Pi公式のドキュメントがgpiozeroだったので、gpiozeroで。
  • Raspberry Pi OSに標準でインストールされていました。
  • OutputDeviceとDigitalOutputDeviceのどちらを使うか迷うところ。PWM出力と同じ階層のほうが使い分けが分かりやすいと思うのでDigitalOutputDeviceに。
  • お試し回路は、GPIO17にLEDと抵抗を接続して、GPIO27をHIGH出力するとLEDが点灯するように。

PWM出力

import gpiozero
import time

pin = gpiozero.PWMOutputDevice(pin=17, frequency=1000)
try:
    while True:
        values = [0.0, 0.1, 0.5, 1.0, 0.5, 0.1]
        for value in values:
            pin.value = value
            time.sleep(1)
finally:
    pin.close()
  • Raspberry Pi公式のドキュメントがgpiozeroだったので、gpiozeroで。
  • Raspberry Pi OSに標準でインストールされていました。
  • お試し回路は、上記のデジタル出力と同じです。GPIO17にLEDと抵抗を接続して、GPIO27をHIGH出力するとLEDが点灯するように。

I2C

import smbus2
import time

bus = smbus2.SMBus(1)
try:
    # Set configuration
    write = smbus2.i2c_msg.write(0x48, [0x03, 0x80])
    bus.i2c_rdwr(write)
    while True:
        # Read temperature value
        write = smbus2.i2c_msg.write(0x48, [0x00])
        read = smbus2.i2c_msg.read(0x48, 2)
        bus.i2c_rdwr(write, read)
        print((read.buf[0][0] * 256 + read.buf[1][0]) / 128)
        time.sleep(1)
finally:
    bus.close()
  • smbusかsmbus2。smbus2はRaspberry Pi OSに標準でインストールされているので、smbus2で。
  • 事前にI2C有効化を忘れずに。
  • i2c_rdwrが使いやすい。書き込みメッセージと読み込みメッセージを同時に指定すると、リピートスタートコンディションで通信する👍。
  • 読み込んだデータはbufで参照できる。1バイトずつのbytesの配列(!)なので、1バイト目はbuf[0][0]、2バイト目はbuf[1][0]。(もっとスマートな取り方、無いかなぁ。)
  • お試し回路は、GPIO2(SDA)とGPIO3(SCL)に温度センサーADT7410を接続して、I2Cで温度を測定できるように。

Raspberry Pi 4で問題のあるクロックストレッチの振る舞いをRaspberry Pi 5で確認しましたが、きちんと動作していました👍👍。(SHT31使用)

import smbus2  # I2C
import time

# I2C - SHT31
# https://github.com/kplindegaard/smbus2
import smbus2
import time

bus = smbus2.SMBus(1)
try:
    write = smbus2.i2c_msg.write(0x45, [0x2C, 0x10])
    read = smbus2.i2c_msg.read(0x45, 6)
    bus.i2c_rdwr(write, read)
finally:
    bus.close()

SPI

import spidev
import time

bus = spidev.SpiDev()
try:
    bus.open(0, 0)
    bus.mode = 0
    bus.max_speed_hz = 1_000_000
    while True:
        read = bus.xfer([0b0110_1000, 0])
        print(read[0] * 256 + read[1])
        time.sleep(1)
finally:
    bus.close()
  • Spidevで。
  • Raspberry Pi OSに標準でインストールされていました。
  • 事前にSPI有効化を忘れずに。
  • お試し回路は、GPIO8(CE0)とGPIO9(MISO)、GPIO10(MOSI)、GPIO11(SCLK)にADコンバーターMCP3002を接続して、SPIで電圧を測定できるように。

UART

import serial
import time

uart = serial.Serial('/dev/ttyAMA0', 9600, timeout=0.5)
try:
    while True:
        uart.write(b'\x22\x00\x00\x22')
        read = uart.read(4)
        distance = int.from_bytes(read[1:3], byteorder='big')
        print(distance)
        time.sleep(1)
finally:
    uart.close()
  • pySerialで。
  • Raspberry Pi OSに標準でインストールされていました。
  • あいかわらずややこしいUARTコンフィグレーションsudo raspi-configで3 -> I5 -> No -> Yesを選択すればOK。
  • お試し回路は、GPIO14(TXD)とGPIO15(RXD)に超音波センサーURM37を接続して、UARTで距離を測定できるように。

参考リンク

変更履歴

日付 変更者 変更内容
2024/4/20 松岡 作成