SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

.NET nanoFrameworkとESP32でIoTプログラミング

C#でIoTプログラミング! .NET nanoFrameworkを用いたプログラムとESP32でLEDを光らせよう!

.NET nanoFrameworkとESP32でIoTプログラミング 第2回

LEDのオンオフを切り替える、スイッチ回路とイベント処理とは?

 次に、タクトスイッチを回路に追加し、スイッチのオンオフで、LEDの点灯と消灯を切り替えるようにしてみましょう。

スイッチの接続

 次の図のように、GPIO23とGNDの間に、スイッチを接続します。タクトスイッチを押せば、GPIO23にGNDがつながるということです。

LEDとスイッチの接続図
LEDとスイッチの接続図

プルアップ、プルダウン

 LEDを点灯させるために、GPIOを出力モードに設定しましたが、スイッチの判定では、GPIOのモードを、入力モードの「プルアップ」という設定にします。

 GPIOなどの端子を利用する場合、通常、電源かGNDにつながる回路にします。電源に接続する回路をプルアップ、GNDに接続する回路をプルダウンと呼びます。ESP32では、内部的にプルアップ、プルダウンの接続ができ、ソフトウェアで切り替えることができます。

内部プルアップ/プルダウン回路のイメージ
内部プルアップ/プルダウン回路のイメージ

 ここではスイッチをプルアップ回路に接続しますので、スイッチがオフのときは、内部的に電源に接続された状態となり、GPIOがHighレベルになります。スイッチをオンにすると、GNDに接続されて、GPIOはLowレベルになります。

 コードは、次のように書き換えます。

Program.csの一部
public static void Main()
{
    using var controller = new GpioController(); 

    // GPIO22番の初期化、設定
    var led = controller.OpenPin(22); 
    led.SetPinMode(PinMode.Output);
    led.Write(PinValue.Low);

    // GPIO23番の初期化、設定
    var sw = controller.OpenPin(23); 
    sw.SetPinMode(PinMode.InputPullUp);                         //(1)
    
    // チャタリング防止
    sw.DebounceTimeout = TimeSpan.FromMilliseconds(20);         //(2)

    // イベント処理(3)
    sw.ValueChanged += (object _, PinValueChangedEventArgs e) =>
    {
        Debug.WriteLine("ValueChanged: " + e.ChangeType);
        if (e.ChangeType == PinEventTypes.Falling)
        {
            // GPIOの値の反転
            led.Toggle();       //(4)
        }
    };
    Thread.Sleep(Timeout.Infinite);
}

 GPIO23番のモードを、プルアップ(PinMode.InputPullUp)にします(1)。

チャタリング

 タクトスイッチのような機械式のスイッチは、チャタリングと呼ばれる現象が発生します。チャタリングとは、機械的なスイッチの接点が接触する瞬間に、オンとオフが高速に繰り返される現象です。スイッチの接点は、肉眼ではわからないものの、接触する際に何度もバウンドする動きになります。この間(数十ミリ秒以下)、スイッチはオンとオフを繰り返します。そして最終的には安定した状態になります。

 チャタリングでのオンとオフを検知してしまうと、スイッチを一度押しただけで何度も押したような結果となりますので、チャタリングを回避する必要があります。回避方法には、ハードウェアまたはソフトウェアでの方法がありますが、ソフトウェアで対処するほうが手軽です。GpioPinクラスクラスのDebounceTimeoutプロパティを設定すると、値に変化があった後、設定した時間の間は、値が変わっても無視するようになります。つまりチャタリングが発生している間は、値の変化を検知しないということです。ここでは、DebounceTimeoutを20ミリ秒としました。

イベント処理

 スイッチのオンオフでGPIOの値が変化するようになりました。では、その変化を検出するにはどうすればよいでしょうか。

 値の変化の検出には、いくつかのアプローチが考えられますが、一般的には次のようになるでしょう。

ポーリング処理

 GPIOの状態を、一定の間隔でループして参照する方法です。ループのなかで、値に変化があったら対応する処理を行います。ループ内にスリープ処理が必要となるため、変換の検出から、対応する処理を行うまでタイムラグが発生する場合があります。また、ずっと処理が実行されるため、CPUリソースを消費することにもなります。

ハードウェア割り込み処理

 ポーリング処理はソフトウェア的な手法ですが、「割り込み」はハードウェア的な手法になります。マイコンでの「割り込み」とは、何らかの信号により、実行しているプログラムを一時中断し、他のプログラムを割り込んで実行させることをいいます。ESP32では、GPIOの値の変化で、ハードウェア的に割り込みを発生させることができます。

割り込み処理のイメージ
割り込み処理のイメージ

 .NET nanoFrameworkでは、このハードウェア割り込み処理を、C#で簡単に使えるようになっています。具体的には、GPIOの値が変化した場合、C#のイベント(ValueChangedイベント)が発生するようになっていて、そのイベントハンドラを定義することができるのです。

 今回のコードでは、GpioPinクラスのValueChangedイベントに、イベントハンドラとしてラムダ式を定義しています(3)。GPIOの状態が変化したときに、このラムダ式が実行されることになります。

 GPIOの状態は、PinValueChangedEventArgsオブジェクトとして渡されますので、そのChangeTypeプロパティで、スイッチが押されたか、離されたかを判断します。PinEventTypes.Falling(値としては2)は、GPIOの値が、HighからLowに変化したときで、PinEventTypes.Rising(おなじく1)は、LowからHighに変化したことを示します。

 したがってここでのハンドラの処理は、スイッチが押されて、HighからLowに変化(PinEventTypes.Falling)したときに、LEDのピンの値を反転させる(4)、ということになります。

 コードを実行してみましょう。タクトスイッチを押すたびに、LEDが点いたり消えたりするはずです。

LED点灯
LED点灯

  またその際、デバッグ出力に、PinValueChangedEventArgsオブジェクトのChangeTypeプロパティが表示されます。

実行結果
実行結果

コールバック関数を利用した書き方

 じつは、.NET nanoFrameworkでは、ValueChangedイベントを利用する以外に、コールバック関数を利用した書き方もできます。前述のイベント処理のところを、GpioControllerクラスのRegisterCallbackForPinValueChangedEventメソッドに変更します。このメソッドの引数は、ピン番号、PinEventTypes、コールバック関数です。PinEventTypesが指定できますので、特定のPinEventTypesで処理を行う場合は、こちらの書き方のほうがすっきりした形になります。

// コールバック関数の登録
controller.RegisterCallbackForPinValueChangedEvent(
    23,                                             // ピン番号
    PinEventTypes.Falling,                          // イベント種類
    (object _, PinValueChangedEventArgs _) =>       // コールバック関数
    {
        // GPIOの値の反転
        led.Toggle();
    }
);

最後に

 今回は、LEDの点灯とスイッチの処理について解説しました。次回は、ESP32に備わるタッチセンサーを使ったプログラムを作成する予定です。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
.NET nanoFrameworkとESP32でIoTプログラミング連載記事一覧

もっと読む

この記事の著者

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

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

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

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/18836 2024/01/22 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー