C#なんぞ

C#に関するあれこれ。現在は「Raspberry PiをC#でプログラミング!」しようとしています!

Sense HATのLEDを順番に点灯する!

Sense HATのLEDを順番に点灯する!

Sense HATの一番上の行のLEDを順番に赤色で点灯させるアプリです。GUI付きで、GUIから開始と終了ができます。

前回書きましたように、Sense HATを扱うパッケージを利用しています。

csharpwhat.hatenablog.com

GitHubに、プロジェクトを置いてありますので、ご参考に!

github.com

実行の様子をYouTubeに置きました。

youtu.be

MainPage.xaml
<Page
    x:Class="L_Chika.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="10" VerticalAlignment="Center" >
        <Button x:Name="startButton" Content="Start" HorizontalAlignment="Center" Margin="10" Width="70" IsEnabled="False" Click="StartButton_Click" />
        <Button x:Name="stopButton" Content="Stop" HorizontalAlignment="Center" Margin="10" Width="70" IsEnabled="False" Click="StopButton_Click" />
        <Button Content="Exit" HorizontalAlignment="Center" Margin="10" Width="70" Click="ExitButton_Click" />
    </StackPanel>
</Page>
MainPage.xaml.cs
using Emmellsoft.IoT.Rpi.SenseHat;
using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace L_Chika
{
    public sealed partial class MainPage : Page
    {
        // Sense Hatを操作するためのインスタンス
        private ISenseHat senseHat;
        // Sense HatのLEDを操作するためのインスタンス
        private ISenseHatDisplay Display => senseHat.Display;

        // 停止の要求
        private AutoResetEvent stopRequest = new AutoResetEvent(false);
        //「停止している」状態
        private ManualResetEvent stopped = new ManualResetEvent(true);

        // コンストラクター
        public MainPage()
        {
            InitializeComponent();

            // UIスレッドで第2引数のラムダ式を実行する
            //(ここではUIスレッドである必要はない)
            IAsyncAction action = Dispatcher.RunAsync(
                Windows.UI.Core.CoreDispatcherPriority.Normal,
                async () =>
                {
                    // Sense Hatを操作するためのインスタンスを得る
                    senseHat = await SenseHatFactory.GetSenseHat();
                    if (senseHat == null) return;

                    // すべてのLEDを消す
                    Display.Clear();
                    Display.Update();
                    //「Start」ボタンを有効にする
                    startButton.IsEnabled = true;
                });
        }

        // 点灯時間
        private const int ON_TIME = 150;
        // 消灯時間
        private const int OFF_TIME = 50;
        // LEDの数
        private const int NUM_OF_COLUMN = 8;

        //「Start」ボタンのClickイベントのイベントハンドラー
        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            // ボタンの有効/無効を設定する
            startButton.IsEnabled = false;
            stopButton.IsEnabled = true;
            //「停止していない」状態にする
            stopped.Reset();

            // UIスレッドで第2引数のラムダ式を実行する
            //(ここではUIスレッドである必要はない)
            IAsyncAction action = Dispatcher.RunAsync(
                Windows.UI.Core.CoreDispatcherPriority.Normal,
                async () =>
                {
                    int column = 0;
                    // 停止を要求されていない間、ループする
                    while (!stopRequest.WaitOne(0))
                    {
                        // LEDを点灯する
                        Display.Screen[column, 0] = Colors.Red;
                        Display.Update();
                        // 時間待ち。停止を要求されればループを脱出する
                        if (await Task.Run(() => stopRequest.WaitOne(ON_TIME))) break;

                        // LEDを消灯する
                        Display.Screen[column, 0] = Colors.Black;
                        Display.Update();
                        // 時間待ち。停止を要求されればループを脱出する
                        if (await Task.Run(() => stopRequest.WaitOne(OFF_TIME))) break;

                        // 次のLEDへ移動する
                        column = (column + 1) % NUM_OF_COLUMN;
                    }

                    // すべてのLEDを消す
                    Display.Clear();
                    Display.Update();

                    // ボタンの有効/無効を設定する
                    startButton.IsEnabled = true;
                    stopButton.IsEnabled = false;
                    //「停止した」状態にする
                    stopped.Set();
                });
        }

        //「Stop」ボタンのClickイベントのイベントハンドラー
        private void StopButton_Click(object sender, RoutedEventArgs e)
        {
            // 停止を要求する
            stopRequest.Set();
        }

        //「Exit」ボタンのClickイベントのイベントハンドラー
        private async void ExitButton_Click(object sender, RoutedEventArgs e)
        {
            // まず停止する(「Stop」ボタンを押したときと同じ処理)
            StopButton_Click(this, new RoutedEventArgs());
            //「停止した」状態になるのを待つ
            await Task.Run(() => stopped.WaitOne());

            // 終了する
            App.Current.Exit();
        }
    }
}