西川和久の不定期コラム
「Raspberry Pi3 Model B」で遊んでみよう!Part2
~GPIO入門1。ポートのオン/オフとステータス取得編
2016年6月20日 06:00
前回のPart1は「Raspberry Pi3 Model B」の簡単な紹介だったが、今回Part2はいよいよRaspberry Pi特有のGPIOをコントロールする。そう言う筆者もここから先は未知の世界。いろいろ調べながらの執筆となった。まずは基本。ポートをオン/オフし、LEDをピカピカさせてみたい。
GPIOの仕様
GPIOとは“General Purpose Input/Output”の略であり、前回、「GPIO×26 3.3V/16mA、UART、I2C、SPI、I2S、PWM、5V、3.3V/50mAで構成」と書いたが具体的なピンアサインが分からないと何もできない。公式サイトによると、以下の図の通り。
これによると赤色の5Vが2つ、橙色の3.3Vが2つ、黒色のGNDが8つ。そしてGPIOが上に12、下に14配置されている。またGPIOのそれぞれは複数の機能を割り当て可能で、今回は一番単純な操作のみを行なう。さらにに複雑な操作はPart3か4で扱う予定だ。
なおGPIOはモデルによって26ピンと40ピンがあり、「Raspberry Pi3 Model B」は40ピン構成だ。互換性を保つため40ピン中1~26ピンまでは、26ピンモデルと同じ仕様になっている。
gpioコマンドを使ってコントロール
一般的にWindowsでもLinuxでもハードウェアをコントロールするには、デバイスドライバを用意しなければならない。とは言え、ここからプログラミングが必要となるとハードルが高過ぎるため、今回インストールした「RASPBIAN」には、予め複数方法が用意されている。その1つが「gpio」コマンドだ。このコマンド1つで、GPIOの設定やステータスを得ることができる。
手始めに、本当にソフトウェア的にGPIOをコントロールできるのか、公式サイトに見習って(笑)、LEDのオン/オフに挑戦する。回路は簡単!ピン12/GPIO18へLEDを接続、適当な抵抗を繋ぎ、ピン39/GNDへ落とす。これで準備は完了だ。
まず、“gpio readall”でGPIOのステータスを表示してみると以下のようになった。
中央のPhysicalが実際のピンアサイン(BCMはGPIO番号、wPiはWiringPiと呼ばれるC言語のライブラリ用)なので、先の図を眺めつつ、何がどうなっているのか1つずつ追うのが理解の早道だろう。
なお、GPIOの初期値は全てMode INになっており、V=1の部分はプルアップ(電源へ抵抗で釣る)、V=0の部分はプルダウン(GNDへ抵抗で落とす)の処理が内部的に行なわれ、オープン(ハイ・インピーダンス)になっているポートはないようだ。各GPIOのプルアップ/ダウンはプログラマブルで変更できる。
gpioコマンドで特定のポートをコントロールするには、
1)ポート番号を指定してINかOUTを設定
2)ポート番号を指定してreadかwrite
の手順を踏む必要がある。またポート番号は“物理的なピン番号”か“GPIO番号”を指定可能だ。
まず、ポートを出力用に設定する。コマンドは以下の通り。
モードがOUTになったがV=0なのでLEDは消灯。LEDを点灯するにはV=1にする。コマンドは以下通り。
LEDを消灯するには
とすればよい。いかがだろうか? gpioコマンドを使えば、LEDのオン/オフ程度は非常に簡単に行えることがお分かり頂けたと思う。
応用例としてPHPを使って、一定間隔LEDが点灯/消灯を繰り返すプログラムを書いてみた(2秒ずつオン/オフを5回)。
逆にGPIOのステータスを読み込むには、該当ポートをプルアップにして、GNDとショートさせた方が回路的に楽なので、ポートを入力モードに切り替えてから、
として、GPIO18をプルアップにする。そしてそのままステータスを読み込むと、
スイッチか何かでGPIO18とGNDをショートすると(プルアップしているため、ショートすると電流が流れるものの、KΩ単位の抵抗で釣っているので微々たるもの。問題ない)、
となる。パラレル出力の簡単なセンサーであれば、同様の手法で値を取得可能だ。センサーからのデータさえ得られれば、後はプログラムでその内容を処理すればいい。
Phytonを使ってコントロール
「RASPBIAN」には“RPi.GPIO”と呼ばれるPhytonのパッケージも用意されている。先にあげた“WiringPi”はC言語用でコンパイルが必要になるが、こちらはPHP同様、スクリプト言語なので即実行でき手軽だ。
またgpioコマンドはコマンドレベルの操作となり、PHPなどではsystem()を使わなければならず美しくないが、こちらはファンクションで操作でき、美しく書くことができる。
“RPi.GPIO”パッケージの詳細はこちらを参考にして欲しい。LEDをオン/オフする程度であれば、
setmode() モード設定
setup() セットアップ
output() アウトプット
cleanup() 後片付け
この4つのファンクションを使えばいい。具体的なコードは以下の通り(LEDを5秒点灯して消灯する)。
これを例えばled.pyファイルに保存して、chmod +x led.pyで実行可能にした後、
で作動する。更に複数のGPIOへLEDを接続した場合、18と書いてダイレクトに指定している部分を配列とし、
と、このように書けば、配列の中で指定したポート全てが一度で設定可能だ。ポートを読み取るのは(別名GPIO、GPIO番号で操作の場合)、
となる。
いずれにしても先のPHPでsystem()を使うより、よりプログラムらしくなるのがお分かり頂けただろうか。
このほかGPIOの操作は、「ファイルシステムを使う方法」や、少し触れた「C言語のライブラリ“WiringPi”を使う方法」もあるので、興味のある人はインターネットで検索して欲しい。
余談になるが、(正確には違うが)1bitのポート単位で(簡単とは言え)プログラミングするのは何十年ぶりか!?の勢いだ(笑)。
筆者はもともとハードウェアからコンピュータを始めた世代で、一番初めに作ったのはオール手配線(笑)のMotorola MC6802を搭載したワンボードマイコン。当時高校生だったが、高価なNECの「TK-80」は買えずお年玉を握りしめてパーツを購入、自作した。
その後、仕事でMSXのゲームを作ったり、Z80のワンボードを設計して外部機器をコントロールするなど、直接ポートを叩くプログラムが主だった記憶がある。当時、開発環境はCP/M80。C言語を使ったROM化も割と早い時期から実戦に投入した(確かWhitesmith C)。今回久々にポート叩いて「そう言えば……」と思い出した次第だ。
Part2はGPIOを使う基本中の基本でポートをオン/オフし、LEDを点灯/消灯してみた。コントロール方法も複数あり、得意もしくは簡単なものから試すのがいいだろう。次回Part3は、もう少し実用的(?)なGPIOのコントロールを行ってみたい。