以前、下記の記事にてGPIOを操作してLEDを点灯/消灯させました。
しかし、この時は「gpio」コマンドを使うことでLEDの制御を行いました。これだと人間がスイッチ操作しているのと変わりありませんよね。
ということで今回は、GPIOを操作するプログラムを作成し、それによってLEDの点灯/消灯させます。なお、LED駆動回路は上記の関連記事で作成したものを使います。
GPIOを操作するプログラム
では早速ですが、GPIOを操作するCソースを見てもらいましょう。こちらです。
#include <stdlib.h>
int main(void)
{
system("gpio -g mode 17 out");
system("gpio -g write 17 1");
return 0;
}
…嘘です。ごめんなさい。実際にこれでもGPIO操作できますが、こんなプログラムを書いたら怒られること必至。
簡単に説明すると、system関数というのはシェルコマンドをプログラム上から実行できる関数です。そして、それを使ってgpioコマンドを実行しているだけなのです。だったらシェルスクリプトを作った方が良く、C言語などを使う意味も無いというものでしょう。
というわけで、このコードはマネしないように(汗)
GPIO sysfsによるGPIO操作するコード
では気を取り直して、C言語でGPIOを操作するプログラムを紹介します。
まず、プログラム上からGPIOを操作する方法は多数あります。ぶっちゃけどれでも良いのですが、Raspberry Pi OS(つまりLinux)のもっとも基本的な方法「GPIO sysfs」を使ったGPIO操作を紹介します。
「GPIO sysfs」はLinuxが用意しているGPIO操作用のファイルシステムで、このファイルに情報を書き込むことによってGPIOを操作することができます。Linuxの思想としてデバイスであろうとなんであろうとファイルとして扱うというものがあり、それを体現しているものですね。
では実際にコードを見ていきましょう。手動でGPIOを操作したとき同様、GPIO17を操作するためのコードになっています。
(コードをシンプルにするため、エラー処理などは省いています)
#include <fcntl.h>
#include <unistd.h>
int main(void){
int fd;
/* GPIO17の操作ファイル生成 */
fd = open("/sys/class/gpio/export", O_RDWR);
write(fd, "17", 2);
close(fd);
sleep(1);
/* GPIO17を出力に変更 */
fd = open("/sys/class/gpio/gpio17/direction", O_RDWR);
write(fd, "out", 3);
close(fd);
/* GPIO17の出力をON */
fd = open("/sys/class/gpio/gpio17/value", O_RDWR);
write(fd, "1", 1);
close(fd);
sleep(2);
/* GPIO17の操作ファイル削除 */
fd = open("/sys/class/gpio/unexport", O_RDWR);
write(fd, "17", 2);
close(fd);
return(0);
}
このコードは大きく分けて4つの処理で構成されています。
- GPIO17の操作用ファイル生成
- GPIO17の入出力設定
- GPIO17の出力値設定
- GPIO17の操作用ファイル削除
GPIO17の操作ファイル生成
fd = open("/sys/class/gpio/export", O_RDWR);
write(fd, "17", 2);
close(fd);
sleep(1);
"/sys/class/gpio/export"はGPIO sysfsが公開しているファイルであり、こちらに操作したいGPIOの番号を書き込むと、その番号のGPIOを操作するためのファイルを生成してくれます。
というわけで、まずは"/sys/class/gpio/export"というファイルを"open"して、そのファイルに対して今回操作したいGPIO17の番号である"17"を書き込み、ファイルを"close"しています。
なお、最後のsleepはファイルが生成されるのを待つために入れています。
GPIO17の入出力設定
fd = open("/sys/class/gpio/gpio17/direction", O_RDWR);
write(fd, "out", 3);
close(fd);
ここでは「GPIO17の操作ファイル生成」によって生成された"/sys/class/gpio/gpio17/direction"を使っています。このファイルはGPIOの入出力を設定するファイルであり、"in"を書き込むと「入力設定」、"out"を書き込むと「出力設定」に設定できます。
ファイルのopen/write/closeは「GPIO17の操作ファイル生成」とまったく同じ流れであり、書き込むファイルと値が変わっているだけです。また、今回はLEDを操作したいので、"out"を書き込んで出力設定にしています。
GPIO17の出力値設定
fd = open("/sys/class/gpio/gpio17/value", O_RDWR);
write(fd, "1", 1);
close(fd);
sleep(2);
ここは入出力設定の時とほとんど一緒で、書き込む対象が"value"に変わっただけです。
"/sys/class/gpio/gpio17/value"は、名前からも分かるとおりGPIO17の値を読み書きするファイルで、出力の場合は"0"を書き込めばLO出力、"1"を書き込めばHI出力になります。
今回の回路ではHIを出力することで点灯させることができるので、"1"を書き込んでいます。また、最後のsleepは2秒間LEDを点灯させるために入れています。
GPIO17の操作ファイル削除
/* GPIO17の操作ファイル削除 */
fd = open("/sys/class/gpio/unexport", O_RDWR);
write(fd, "17", 2);
close(fd);
最後はこれまで使ってきたGPIO17の操作用ファイルを削除する処理になります。後始末ってやつですね。
"/sys/class/gpio/unexport"はGPIO sysfsが公開しているファイルであり、このファイルに操作していたGPIOの番号を書き込むと、その番号のGPIO操作用ファイルを削除してくれます。
削除と言ってもまた"export"に番号を書き込めば操作用ファイルが生成され、同じようにGPIO操作できるので安心してくださいね。
コードの動作確認
では実際にコードを動かしてみましょう。まずラズパイのターミナルを開いて、冒頭で紹介したソースコード"test_gpio.c"をラズパイ上に作成します。そして、"test_gpio.c"があるディレクトリで下記コマンドを実行します。
gcc test_gpio.c
これはC言語のコンパイルを実行するコマンドで、"test_gpio.c"の中身をコンピューターが理解できる形に翻訳してくれます。
実行すると"a.out"というファイルが生成されますが、これが実行体というものでコンピューターが理解できるように翻訳されたファイルそのものになります。
あとはこの"a.out"を下記コマンドで実行すると、LEDが点灯するはずです。
./a.out
実際にターミナルを打って動かしている様子がこちら。
まとめ
実際にコードを見てみると、ラズパイのGPIO操作はとても簡単です。また、今回はC言語で実装しましたが、他の言語でも同様にファイル操作することで簡単にGPIOを操作できますよ。
コメント
コメント一覧 (2件)
8行目の「GPIO17の操作ファイル生成」と25行目の「GPIO17の操作ファイル削除」のopenですが、フラグが「O_RDWR」だとopenの戻り値が-1となりエラーになりました。
フラグを「O_WRONLY」とすることで、戻り値が正の値になり、エラーにならなくなりました。
yamao様
コメントありがとうございます。
「O_WRONLY」でopenできて、「O_RDWR」だとopenできなかったということは、ファイルは存在しているということですね。
となると、ファイルの権限(パーミッション)が怪しいかな。
ユーザ及びファイルの権限によって、アクセスできないケースがありそうですね。
有益な情報ありがとうございます。