CodeZine(コードジン)

特集ページ一覧

C#でラズパイのGPIOを操作しよう~LEDを点灯させる

C#ではじめるラズパイIoTプログラミング 第2回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2019/09/25 11:00

目次

LED制御プロジェクトの作成

 では、この仮想ファイルシステムを使う方法で、LEDを点灯させるプロジェクトを作成してみましょう。

新しいプロジェクトの作成

 まずはVisual Studioで、新しいプロジェクトを作成します。プロジェクトのテンプレートは、コンソールアプリ(.NET Core)を選択します。

コンソールアプリ(.NET Core)を選択する
コンソールアプリ(.NET Core)を選択する

 プロジェクトの構成は、プロジェクト名をVirtualFile、ソリューション名をPieCore、としました。またプロジェクトの場所は、前回解説したsambaを利用して、Raspberry Piの共有フォルダを直接指定しています。つまりプロジェクトファイルは、Raspberry Pi上に作成されることになります。なお、PCのローカルフォルダに作成した場合は、アプリケーションの実行時に、プロジェクトフォルダをRaspberry Piにコピーします。

プロジェクトの構成
プロジェクトの構成

 共有フォルダを指定してプロジェクトを作成すると、セキュリティ警告が表示される場合があります。今回は、自分で作成するプロジェクトであり問題ないので、そのままOKをクリックします。

セキュリティ警告
セキュリティ警告

プロジェクトの設定

 プロジェクトが作成されたら、次に、CPU(ソリューション プラットフォーム)の設定を行います。メニューから、構成マネージャーを選択します。

構成マネージャーの選択
構成マネージャーの選択

 ダイアログが表示されるので、アクティブ ソリューション プラットフォーム欄のところから新規作成を選びます。

アクティブ ソリューション プラットフォームの新規作成
アクティブ ソリューション プラットフォームの新規作成

 新しいソリューション プラットフォームの設定画面が表示されたら、最初の入力欄のところを、linux-armに変更して、OKをクリックします。

新しいソリューション プラットフォーム
新しいソリューション プラットフォーム

 構成マネージャーを閉じると、CPU(ソリューション プラットフォーム)が変更されます。これで、Raspberry Pi用のアプリケーションが作成できます。

linux-armに変更される
linux-armに変更される

クラスの作成

 プロジェクトの準備ができましたので、Program.csにコードを追加していきましょう。先ほどの仮想ファイルシステムでの手順を、そのままクラスにしてみます。

[リスト1]Program.csの一部
// 仮想ファイルによるGPIO操作クラス
class Gpio
{
    // 仮想ファイルの起点パス
    private const string BasePath = "/sys/class/gpio/";

    // 使用するGPIOピンの初期設定(3)
    public void Init(int pin)
    {
        // pinの初期化
        if (!Directory.Exists($"{BasePath}gpio{pin}"))
        {
            using var sw = new StreamWriter($"{BasePath}export");
            sw.Write(pin); // (1)
        }

        // ディレクトリの生成確認(2)
        while (!Directory.Exists($"{BasePath}gpio{pin}"))
        {
            Thread.Sleep(10);
        }
    }
    ~略~
}

 Initメソッドでは、使用するGPIOピンの初期設定を行います(3)。/sys/class/gpio/gpio番号のディレクトリが存在しないとき、StreamWriterクラスを使って、仮想ファイルの/sys/class/gpio/exportにGPIOの番号を書き込んでいます(1)。番号を書き込んですぐには、/sys/class/gpio/gpio番号のディレクトリが作成されないので、作成されるまで待ちます(2)。

 なお、ここでは、C#8.0の機能である、using変数宣言を使っています。 usingステートメントでは、スコープを示す{}が必要でしたが、using変数では、usingの有効範囲は、using変数のスコープと同じになります。

GPIOピンの設定

 次に、GPIOピンの出力・入力の設定と、値を設定するメソッドを追加します。

[リスト2]Program.csの一部
// GPIOの値(4)
public enum Value { OFF = 0, ON = 1 }

// outの設定(5)
public void SetOut(int pin)
{
    using var sw = new StreamWriter($"{BasePath}gpio{pin}/direction");
    sw.Write("out");
}
// inの設定(6)
public void SetIn(int pin)
{
    using var sw = new StreamWriter($"{BasePath}gpio{pin}/direction");
    sw.Write("in");
}
// 値の設定(7)
public void SetValue(int pin, Value val)
{
    using var sw = new StreamWriter($"{BasePath}gpio{pin}/value");
    sw.Write((int)val); //(8)
}

 SetOut/SetInメソッドでは、仮想ファイルの/sys/class/gpio/gpio番号/directionに、out、inの文字列を書き込みます(5)(6)。SetValuメソッドでは、/sys/class/gpio/gpio番号/valueに、引数で指定した値を書き込みます(7)。引数は、enum型として定義しています(4)。なお、仮想ファイルには、0または1の数値の文字列を書き込む必要があります。enum型でそのまま書き込むと、定数の文字列表現(例えばOFFなど)が書き込まれるので、ここでは(int)で数値型にキャストして、数値に変換しています(8)。

GPIOピンの参照

 次に、GPIOピンの参照です。

[リスト3]Program.csの一部
// 値の参照
public Value GetValue(int pin)
{
    string v = File.ReadAllText($"{BasePath}gpio{pin}/value");           //(9)
    return (Convert.ToInt32(v) == (int)Value.ON) ? Value.ON : Value.OFF; //(10)
}

 仮想ファイル/sys/class/gpio/gpio番号/valueの読み出しには、File.ReadAllTextメソッドを利用しています(9)。このメソッドは、ファイルのクローズ処理もメソッド内で完結しているので、シンプルなコードで記述できます。File.ReadAllTextメソッドで読み出した文字列は、いったん数値に変換してenum型の値と比較し、適合したenum型を返しています(10)。

GPIOピンの終了処理

 最後に、終了処理のTerminateメソッドを追加します。

[リスト4]Program.csの一部
// 使用したGPIOピンの終了処理
public void Terminate(int pin)
{
    if (Directory.Exists($"{BasePath}gpio{pin}"))
    {
        using var sw = new StreamWriter($"{BasePath}unexport");
        sw.Write(pin);
    }
}

 GPIOピンの初期設定と同様に、仮想ファイルの/sys/class/gpio/unexportに番号を書き込んでいます。

スイッチとLED点灯のコード

 クラスができたので、タクトスイッチが押されたら、LEDが点灯するコードを作成してみます。30秒間スイッチの判定を行い、30秒すぎたら終了します。

[リスト5]Program.csの一部
var gpio = new Gpio();

var p1 = 4;
var p2 = 15;

// GPIOの初期化
gpio.Init(p1);
gpio.Init(p2);

// GPIOのIN,OUT設定
gpio.SetOut(p1);
gpio.SetIn(p2);

// 30秒間処理を行う
for (int i=0; i<300; i++)
{
    // GPIO15がOFFになれば(スイッチが押されれば) (10)
    if (gpio.GetValue(p2) == Gpio.Value.OFF)
    {
        // LED点灯
        gpio.SetValue(p1, Gpio.Value.ON);
    }
    else
    {
        // LED消灯
        gpio.SetValue(p1, Gpio.Value.OFF);
    }
    Thread.Sleep(100);
}

// GPIOの終了処理
gpio.Terminate(p2);
gpio.Terminate(p1);

 ここでは、GPIO4番ピンをLED点灯用に出力としています。また、15番ピンをスイッチの判定のため入力に設定しています。スイッチの判定は、ぱっと見ると反対のように感じますが、GPIO15番ピンは、デフォルトでプルアップとして接続されています。そのため、GPIO15番の値は、初期状態でONになります。スイッチを押したときに、GNDに接続されるような回路とすると、スイッチを押せば、GPIO15番の値はOFFになります。

【注】プルアップ、プルダウン

 GPIOなどの電子回路の入出力端子は、通常、電源やGND(グランド)に接続するようにして、どこにも接続していない状態は、できるだけ避けるようにします。端子を、電源に接続する回路はプルアップ、GNDに接続する回路は、プルダウンと呼びます。

 Raspberry Piでは、内部的に、プルアップまたはプルダウンの接続になっています。また、プルアップ、プルダウンの接続は、ソフトウェアで切り替えることもできます。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:C#ではじめるラズパイIoTプログラミング

著者プロフィール

  • WINGSプロジェクト 高江 賢(タカエ ケン)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5