GPIOコールバック処理

RPi.GPIOはルート権限が必要なため、CGIで使うには不便なのでWiringPiを試してみたが、それ以外の用途でならapt-getで簡単にインストールできるし、有用性は高い。

現在進行形で開発中のパッケージなので、バージョンが上がると関数が追加されたり無くなったりと変化が大きく注意が必要ではあるが、Raspberry PiでGPIO入出力を行う場合はこちらが標準になるのだろう。

ただし、RPi.GPIOのプロジェクトページにも書いてある通りPythonはガベージコレクションが発生した場合に遅延が生じる可能性があり、そもそもリアルタイム性をあまり考慮しないLinuxカーネル下で動作するので、クリチカルなタイミングを必要とする処理には向かないことを覚えておく必要がある。
そういう用途にはArduinoの出番だ。

RPi.GPIOの最新バージョンは0.5.0aで、入力ポートの変化によるコールバック処理が追加されている。これは入力ポートが変化した時に定義したコールバック関数を呼び出す機能で、別スレッドで処理されるから用途によっては便利。

GPIOポート17(11番ピン)に押しボタンスイッチをつなぎ、押した時に+3.3Vに通電するようにする。間違えて+5Vに通電してしまうとRaspberry Piが壊れる可能性があるので注意。以前スイッチをつないだときはプルダウン抵抗で押していない時はGNDになるようにしたが、今回は内蔵のプルアップ/プルダウン機能を試すので何もつながない。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import RPi.GPIO as GPIO
import time

def event_callback1():
    print 'event_callback1'

if __name__ == "__main__":
    print 'GPIO Version',GPIO.VERSION
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # GPIO17 Pin11
    GPIO.add_event_detect(17, GPIO.RISING)
    GPIO.add_event_callback(17, event_callback1)
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print '\nbreak'
        GPIO.cleanup()

プログラムを走らせてボタンを押すと、押した時だけコールバック関数が呼び出される。押した時ではなく離した時に呼び出したい場合は、GPIO.add_event_detectでGPIO.FALLING、両方で呼び出したい場合はGPIO.BOTHを指定すれば良い。

ここまでは良いのだが、スイッチを増やしてそれぞれにコールバック処理を行いたい場合は上手く行かない。以下のようにGPIO22にスイッチを追加して同じようにコールバック関数を定義しても、全く呼び出されないのだ。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import RPi.GPIO as GPIO
import time

def event_callback1():
    print 'event_callback1'
def event_callback2():
    print 'event_callback2'

if __name__ == "__main__":
    print 'GPIO Version',GPIO.VERSION
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # GPIO17 Pin11
    GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # GPIO22 Pin15
    GPIO.add_event_detect(17, GPIO.RISING)
    GPIO.add_event_detect(22, GPIO.RISING)
    GPIO.add_event_callback(17, event_callback1)
    GPIO.add_event_callback(22, event_callback2)
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print '\nbreak'
        GPIO.cleanup()

どうやらRPi.GPIOのコールバック処理用スレッドは、ひとつのポートに対してだけしか有効ではないらしい。その代わりGPIO.add_event_callbackを複数回呼び出してひとつのポートに対して複数のコールバック処理を定義することはできる。
でもこれはあまり意味がないような気がする。ひとつにまとめてしまえば良いわけだし。何か意味があるのだろうか?

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中