Raspberry Pi 2 + Windows 10 IoT で Lチカチカ!
Raspberry Pi 2 を購入し、Windows IoT Core のインストールが成功した ので、次はなんか
センサーなんかをつないだりしてみたりしたいなぁと。
1.Raspberry Pi 2 用センサーキット購入
Raspberry Pi 2 用のセンサー詰め合わせみたいなのを購入してみた。2,000円程度とお値ごろ。
ハック ラズベリーパイ Raspberry Pi 電子工作入門キット。
届いた!
電子工作での、Hello World はどうやら Lチカとかいって、LEDをチカチカさせることらしい。
ということで、上記センサーキットの説明書的な位置づけのブログ、
を参照して、見た、、、が、いまひとつうまく動かない。。。
第9回「ラズベリーパイで電子工作!Lチカ…の前にLピカ!」 こちらのサイトが非常にわかりやすい。
root になったうえで、以下の例だと、GPIOの 25番ピン に接続して、リダイレクト先の gpio25/value に 1 を書き込むとLEDが点灯して、0を書き込むと消灯する。
# echo 25 > /sys/class/gpio/export # cd /sys/class/gpio/gpio25 # echo out > direction # echo 1 > value # echo 0 > value
上記サイトで例に出ている抵抗と同じものが、今回のセンサーキットには含まれていなかったので、値が近いものを探して利用する。
抵抗の帯の色で区別できるようになってるんですね。というか抵抗の意味もあまりわかりませんが。
ということで、Raspbian での動作確認は難なくクリア。いよいよ本命の Windows IoT で Lチカだ!
2. Windows IoT でLチカ!
2.1 Windows.Devices.Gpio
ということで、以下あたりにあるサンプルコードどおりにコーディングすればすぐチカチカするだろうと軽く考えていたところ、、、
Starter Pack for Windows 10 IoT Core on Raspberry Pi 2
まず、Windows.Devices.Gpio ネームスペースがどこにあるかわからない。。。
結構ググったり、トライアンドエラーのすえ、結局、参照設定から、Universal Windows 拡張、Windows IoT Extensions for UWP の中にあることが判明。
選択して、参照設定。
これで、Windows.Devices.Gpio が利用可能となる。
2.2 GPIO ピンが無効!
つぎに、上記のサイトを参考に、コーディングして、動かしてみるも、チカチカしないどころか、
Exception thrown: 'System.Runtime.InteropServices.COMException' in WinIoTSample01.exe WinRT information: Pin ' is not available. It is reserved by the system or in use for another function.
てな、例外が発生。Pin が Available じゃない?ぁ?システムで予約されている?
さっき、Rasbian からは、チカチカできてたじゃないですか。。。
うーん。なんか ピンのステータスを検査するメソッド的なものがあったので、全ピンの状態をデバッグに出力してみる!
for (int i = 0; i < gpio.PinCount; i++) { GpioOpenStatus openStatus = new GpioOpenStatus(); gpio.TryOpenPin(i, GpioSharingMode.Exclusive, out pin, out openStatus); Debug.WriteLine($"{i} is {openStatus.ToString()}"); }
ほう。なんかわからんけど、3番ピンはだめだけど、4番ピンは良さそうだ。
0 is PinUnavailable 1 is PinUnavailable 2 is PinUnavailable 3 is PinUnavailable 4 is PinOpened 5 is PinOpened 6 is PinOpened 7 is PinUnavailable 8 is PinUnavailable 9 is PinUnavailable 10 is PinUnavailable 11 is PinUnavailable 12 is PinOpened 13 is PinOpened 14 is PinUnavailable 15 is PinUnavailable 16 is PinOpened 17 is PinOpened 18 is PinOpened 19 is PinOpened 20 is PinOpened 21 is PinOpened 22 is PinOpened 23 is PinOpened 24 is PinOpened 25 is PinOpened 26 is PinOpened 27 is PinOpened 28 is PinUnavailable 29 is PinUnavailable 30 is PinUnavailable 31 is PinUnavailable 32 is PinUnavailable 33 is PinUnavailable 'WinIoTSample01.exe' (CoreCLR: CoreCLR_UWP_Domain): 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\89e222f8-bd1a-4cd5-b792-0d1321e00be7VS.Debug_ARM.piroto\Microsoft.ApplicationInsights.PersistenceChannel.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 34 is PinUnavailable 'WinIoTSample01.exe' (CoreCLR: CoreCLR_UWP_Domain): 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\89e222f8-bd1a-4cd5-b792-0d1321e00be7VS.Debug_ARM.piroto\System.Threading.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 35 is PinOpened 36 is PinUnavailable 37 is PinUnavailable 38 is PinUnavailable 'WinIoTSample01.exe' (CoreCLR: CoreCLR_UWP_Domain): 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\89e222f8-bd1a-4cd5-b792-0d1321e00be7VS.Debug_ARM.piroto\System.Private.Uri.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 39 is PinUnavailable 40 is PinUnavailable 41 is PinUnavailable 42 is PinUnavailable 43 is PinUnavailable 'WinIoTSample01.exe' (CoreCLR: CoreCLR_UWP_Domain): 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\89e222f8-bd1a-4cd5-b792-0d1321e00be7VS.Debug_ARM.piroto\System.Diagnostics.Tracing.dll' が読み込まれました。モジュールがシンボルなしでビルドされました。 44 is PinUnavailable 'WinIoTSample01.exe' (CoreCLR: CoreCLR_UWP_Domain): 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\89e222f8-bd1a-4cd5-b792-0d1321e00be7VS.Debug_ARM.piroto\System.Linq.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 45 is PinUnavailable 'WinIoTSample01.exe' (CoreCLR: CoreCLR_UWP_Domain): 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\89e222f8-bd1a-4cd5-b792-0d1321e00be7VS.Debug_ARM.piroto\System.Globalization.dll' が読み込まれました。モジュールがシンボルなしでビルドされました。 46 is PinUnavailable 'WinIoTSample01.exe' (CoreCLR: CoreCLR_UWP_Domain): 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\89e222f8-bd1a-4cd5-b792-0d1321e00be7VS.Debug_ARM.piroto\System.IO.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 47 is PinOpened 48 is PinUnavailable 49 is PinUnavailable 50 is PinUnavailable 51 is PinUnavailable 52 is PinUnavailable 53 is PinUnavailable
Raspberry Pi2 付属の GPIOカードで、4番ピンの位置を確認して、ケーブルを接続しなおす。
2.3 いざ Lチカ
まずは、PC上で起動して、GPIOがエラーになることを確認。OK
いよいよ、Raspberry Pi2 上の Windows IoT Core に Visual Studio 上からデプロイかまします。
“GPIO pin initialized correctly.” OK! OK!
LED は、消灯状態 OK! OK!
さて、おもむろに SWITCH ボタンをおして、、、画面上のステータスは、ONとなりました。さて、LEDは、、、
点灯しましたーーー。めでたしめでたし。
3.ソースコード
ここまでの、ソースコードは以下。
Windows 10 mobile も入手して、Universal Windows Platform も覚えたいと思ってたりしていて、以下の書籍のサンプルをコーディング中なので、基本的なMVVMのUIはそちらをお手本に、練習がてら作成。
実際に、Lチカさせるのに必要なコードは、MainPageContent クラスの、InitGpio() および、Switch() のみ。あとは、UI回りのためのコードです。
Models/MainPageContent.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WinIoTSample01.Commons; using Windows.Devices.Gpio; using System.Diagnostics; namespace WinIoTSample01.Models { class MainPageContent : BindableBase { private static MainPageContent instance = new MainPageContent(); public static MainPageContent Instance { get { return instance; } } private bool state; public bool State { get { return this.state; } set { this.SetProperty(ref this.state, value); } } private string gpioStatus; public string GpioStatus { get { return this.gpioStatus; } set { this.SetProperty(ref this.gpioStatus, value); } } private const int LED_PIN = 4; private GpioPin pin = null; private MainPageContent() { InitGpio(); } private void InitGpio() { this.State = false; var gpio = GpioController.GetDefault(); if (gpio == null) { this.GpioStatus = "There is no GPIO contoroller ont this device."; } //for (int i = 0; i < gpio.PinCount; i++) //{ // GpioOpenStatus openStatus = new GpioOpenStatus(); // gpio.TryOpenPin(i, GpioSharingMode.Exclusive, out pin, out openStatus); // Debug.WriteLine($"{i} is {openStatus.ToString()}"); //} pin = gpio.OpenPin(LED_PIN); pin.Write(GpioPinValue.Low); pin.SetDriveMode(GpioPinDriveMode.Output); //gpio.TryOpenPin(LED_PIN, GpioSharingMode.Exclusive, out pin, out openStatus); this.GpioStatus = "GPIO pin initialized correctly."; } public void Switch() { this.State = !this.State; GpioPinValue pinValue = ((this.State) ? GpioPinValue.High : GpioPinValue.Low); Debug.WriteLine($"Pin No:{pin.PinNumber}, Value:{pinValue}"); pin.Write(pinValue); } } }
Commons/BindableBase.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace WinIoTSample01.Commons { public class BindableBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual bool SetProperty(ref T field, T value, [CallerMemberName] string propertyName = null) { if (Equals(field, value)) { return false; } field = value; this.OnPropertyChanged(propertyName); return true; } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
ViewModels/MainPageViewModel.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using WinIoTSample01.Commons; using WinIoTSample01.Models; namespace WinIoTSample01.ViewModels { public class MainPageViewModel : BindableBase, IDisposable { public MainPageViewModel() { this.Model.PropertyChanged += this.MainPageViewModel_PropertyChanged; } private void MainPageViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { this.OnPropertyChanged(e.PropertyName); } private MainPageContent Model { get; } = MainPageContent.Instance; public string State { get { return (this.Model.State?"ON":"OFF"); } } public string GpioStatus { get { return this.Model.GpioStatus; } } void IDisposable.Dispose() { throw new NotImplementedException(); } public void Switch() { this.Model.Switch(); } } }
Views/MainPage.xaml
<Page x:Class="WinIoTSample01.Views.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WinIoTSample01.Views" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="{x:Bind ViewModel.State, Mode=OneWay}" HorizontalAlignment="Stretch" TextAlignment="Center"/> <TextBlock Grid.Row="1" Text="{x:Bind ViewModel.GpioStatus, Mode=OneWay}" HorizontalAlignment="Stretch" TextAlignment="Center"/> <Button Grid.Row="2" Content="SWITCH" Click="{x:Bind ViewModel.Switch}" HorizontalAlignment="Stretch"/> </Grid> </Page>