Rev.2.0のもの。リビジョンにより多少違うらしいので要確認。 この写真は海外ショップで販売されているピン表示ガイド板。
GPIOの7とGNDは隣り合っているので、ここにスイッチを付けてみる。こんなスイッチが使える。 (写真クリックでメーカーサイトへ)
これを入力にしてプルアップにするにはシェルから次のように打ち込む。 (ピンを設定したり読んだりするためにはほかにもいろいろな方法がある)
echo 7 > /sys/class/gpio/export echo "in" > /sys/class/gpio/gpio7/direction echo "high" > /sys/class/gpio/gpio7/direction
Raspberry PiのGPIOはプルアップ、プルダウンを指定出来る。"high"はプルアップ、"low"とするとプルダウン。指定しないとプルアップもダウンもされず高インピーダンス入力になる。スイッチを付ける場合は、外部抵抗でプルアップなどしないといけない。 設定で、プルアップ、プルダウンを指定すると、スイッチ接続が簡単になる。プルアップされているならそのピンに付けたスイッチをGNDに、プルダウンなら電源に接続するだけでok。普通は、引き回しが簡単なGNDに接続することになるので、ここはプルアップが便利(GPIO入力は3.3vが最大なのでうっかり5vに接続して破壊する可能性もあるのでGND接続が良い)。 今回も、スイッチをGNDに接続したので、常時はプルアップ(high)にしておき、スイッチが押されるとlowになるようにする。
cat /sys/class/gpio/gpio7/value
をすると、ボタンを押さなければ1が、ボタンを押せば0が返ってくる。(rootじゃなくても実行出来る)
echo 7 > /sys/class/gpio/unexport
exportメソッドでは、ピンを排他的に使用するらしい。 なので、exportしたままだと、次に別のプロセスからこれを利用できなかったり、警告が出たりする。 ということで利用終わったら上記のようにunexportするとよいらしい(効果は未確認)。
このボタンを5秒間押し続けたらRasberry Piをシャットダウンさせるスクリプトは次のように書ける。 ( http://blog.livedoor.jp/victory7com/archives/32699844.html を参考にしました。これによると このスクリプトを/etc/rc.localの最後にsu -c /home/pi/shutdown-daemon.sh & と書いておけばシャットダウンスイッチとして使える )
#!/bin/sh GPIO=7 #使用するGPIOポート PUSHTIME=5 #押す秒数 #初期設定 echo "$GPIO" > /sys/class/gpio/export echo "in" > /sys/class/gpio/gpio$GPIO/direction echo "high" > /sys/class/gpio/gpio$GPIO/direction #5秒間押されるまで待つ cnt=0 while [ $cnt -lt $PUSHTIME ] ; do data=`cat /sys/class/gpio/gpio$GPIO/value` if [ "$data" -eq "0" ] ; then cnt=`expr $cnt + 1` else cnt=0 fi sleep 1 done #このあとシャットダウンするから不要かもしれないけど一応お行儀良く echo "$GPIO" > /sys/class/gpio/unexport #シャットダウンの実行 shutdown -hP now
一方、ピンを出力にするにはシェルから次のように打ち込む。
echo 7 > /sys/class/gpio/export echo "out" > /sys/class/gpio/gpio7/direction echo 7 > /sys/class/gpio/unexport
GPIOピンの先に抵抗とLEDを直列につなぎ、先をGNDに落とせば、GPIOピンのH/LでLEDが点滅する。 抵抗は330オームくらいか1kオームくらい。LEDによっては330オームは結構眩しいかも。
echo 1 > /sys/class/gpio/gpio7/value
をするとLEDが点灯する。echo 0をすれば消灯する。
上記のシャットダウンボタンは、フィードバックがなくて動いているかどうか確認できない。 そこで、こんな
LED内蔵押しボタンスイッチ(写真クリックで秋月電子へ)を買ってきて、シャットダウンカウントダウンに点滅するようにしてみる。 これはスイッチとLEDのために4本の端子が付いている。 これをRaspberryのピンに刺すコネクタを作成する。
これを、GPIO 7→スイッチ→GNDと、また、GPIO 8→抵抗→LED→GNDのように接続する。 以下のようなスクリプトを常駐させておけば、シャットダウンできる。
#!/bin/sh BTN=7 #使用するGPIOポート LED=8 PUSHTIME=5 #押す秒数 #初期設定 echo "$BTN" > /sys/class/gpio/export echo "in" > /sys/class/gpio/gpio$BTN/direction echo "high" > /sys/class/gpio/gpio$BTN/direction echo "$LED" > /sys/class/gpio/export echo "out" > /sys/class/gpio/gpio$LED/direction #5秒間押されるまで待つ cnt=0 while [ $cnt -lt $PUSHTIME ] ; do data=`cat /sys/class/gpio/gpio$BTN/value` if [ "$data" -eq "0" ] ; then cnt=`expr $cnt + 1` echo 1 > /sys/class/gpio/gpio$LED/value sleep 0.5 echo 0 > /sys/class/gpio/gpio$LED/value sleep 0.5 else cnt=0 sleep 1 fi done #このあとシャットダウンするから不要かもしれないけど一応お行儀良く echo "$BTN" > /sys/class/gpio/unexport echo "$LED" > /sys/class/gpio/unexport #シャットダウンの実行 shutdown -hP now
上記の方法は、たぶん仮想ファイル経由でデバイスドライバにアクセスしているようなもので、これを使えば、cだろうとjavaだろうとpythonだろうと、シェルコマンド呼ぶ関数で利用できてお手軽。でも、echo とcatコマンドで頑張らないといけないので、プログラミングには面倒だし凝った事ができない。
CやPythonなどのために、GPIOを呼ぶライブラリーも提供されている。 以下は、GPIO 8に抵抗とLEDを取り付け、これを点滅させる例。 最終的にGPIO.cleanupを呼びたいので、コントロールC押下あとで処理出来るようにtry文を使用している。
#!/usr/bin/python import RPi.GPIO as GPIO import time LED=8 GPIO.setmode(GPIO.BCM) GPIO.setup(LED, GPIO.OUT) print("Type control-c to stop.\n"); try: while True: GPIO.output(LED,1) time.sleep(1) GPIO.output(LED,0) time.sleep(1) except KeyboardInterrupt: GPIO.cleanup()
実は、出力に設定したGPIOピンても、その値を読む事ができる。これを利用すれば、上記の無限ループ部分は、
while True: GPIO.output(LED,(1-GPIO.input(LED))) time.sleep(1)
と簡素化できる。( 1-1=0, 1-0=1を使って1,0を反転させる手法)
以下は、GPIO 7とGNDに取り付けた押しボタンスイッチの状態を読む例。 GPIO.setupのpull_up_down引数でプルアップ/ダウンを指定出来る。
#!/usr/bin/python import RPi.GPIO as GPIO import time Switch=7 GPIO.setmode(GPIO.BCM) GPIO.setup(Switch, GPIO.IN, pull_up_down=GPIO.PUD_UP) print("Type control-c to stop.\n"); try: while True: print(GPIO.input(Switch)) time.sleep(1) except KeyboardInterrupt: GPIO.cleanup()
callback関数を設定しておく事で割り込み処理が可能である。 スイッチの状態などをポーリングして監視し続けなくても良いので、プログラミングが楽になる。 GPIO.FALLING, GPIO.RISING, GPIO.BOTHの指定で、1-->0, 0-->1, その両方のイベントでのコールバックを指定する。
#!/usr/bin/python import RPi.GPIO as GPIO import time Switch=7 def switch_callback(gpio_pin): print(gpio_pin) GPIO.setmode(GPIO.BCM) GPIO.setup(Switch, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.add_event_detect(Switch, GPIO.FALLING) GPIO.add_event_callback(Switch, switch_callback) print("Type control-c to stop.\n"); try: while True: time.sleep(1) except KeyboardInterrupt: GPIO.cleanup()
上で示した機械的なスイッチを取り付けただけだとチャッタリングのために指定したイベント以外の変化でも呼び出されることがある。上記のプログラムで以下のような対策をとれば多少は緩和される筈。 このcallback関数では、イベントにより呼びだされた後、チャッタリングが収まるまで30ms待って、もう一度チェックして間違って呼ばれたようならなにもしないで終了する。
def switch_callback(gpio_pin): time.sleep(0.03) if GPIO.input(gpio_pin) != 0: return print(gpio_pin)