Windows 10 IoT Coreのタイマー関係を調べてみる

Windows 10 IoT Coreのタイマー関連を調べてみる

【注】このエントリーの情報は誤りがありますので追記も必ず御覧ください。

uepon.hatenadiary.com

Arduinoとかmbedなんかのソースを移植するときにmicros()とかsleep()とかdelay()とかがあるんで、Windows10 IoT Coreではどの程度の精度が出るのか調べてみました。

delay()の代わりになるもの

以前のエントリーでも使ってますが、await Task.Delay()を使う感じでしょうか。(Thread.Sleep()でもいいのかも)

private async Task<string> delay(int msec)
{
    var times = 0;

    s.Restart();
    for (times = 0; times < 1000; times++)
    {
        if (pin.Read() == GpioPinValue.High)
        {
            pin.Write(GpioPinValue.Low);
        }
        else
        {
            pin.Write(GpioPinValue.High);
        }
        await Task.Delay(TimeSpan.FromTicks(10 * 1000 * msec));
    }
    s.Stop();

    return msec.ToString() + "msec->" + s.ElapsedMilliseconds / (double)times + "ms" + Environment.NewLine;
}

こんな感じのメソッドを考えてみました。引数で与えた秒数間隔でGPIOでLチカを行い、1000回実行して平均値をとっています。

引数にTimeSpan.FromTicks(10 * 1000 * msec)を入れたのはミリ秒以下のものを試せるようにする意味だったのですが、結果を知ってしまうと無駄です。普通に値を入れてしまえばいいと思います。ちなみにTickは100ナノ秒とのことです。

これを使って実行すると

f:id:ueponx:20160813161053j:plain

あー。

もしかしてGPIOのLチカが影響しているのかもと思ったのですが

f:id:ueponx:20160813161042j:plain

夢でした。ありがとうございます。

これでは秒単位でなければ使い物にならないのかも…そういう用途なの?

別の手段を考えてみた

これではソースの移植なんかもできないかなと思い、別の手段を考えてみました。というか、処理時間の計算に使っていたSystem.Diagnostics.Stopwatch()を使っているだけです。ストップウオッチのように使えるのですが、タイマーを動かしながらでも値の取得ができるのでそれでDelayする値がくるまでループをぶん回しているだけです。

private string myDelay(int msec)
{
    var times = 0;

    var sw = new System.Diagnostics.Stopwatch();
    sw.Restart();

    s.Restart();
    for (times = 0; times < 1000; times++)
    {
        if (pin.Read() == GpioPinValue.High)
        {
            pin.Write(GpioPinValue.Low);
        }
        else
        {
            pin.Write(GpioPinValue.High);
        }
        var old = sw.ElapsedMilliseconds;
        while ((sw.ElapsedMilliseconds - old) <= msec)
        {
        }
    }
    s.Stop();
    sw.Stop();
    return msec.ToString() + "msec->" + s.ElapsedMilliseconds / (double)times + "ms" + Environment.NewLine;
}

実行すると以下のようになります。

f:id:ueponx:20160813162403j:plain

上がawait Task.Delay()を使用、下がSystem.Diagnostics.Stopwatch()を使用したものになります。

だいぶ値的には使える範囲まで来ているかなと思います。 同様の考え方で、Arduinoのmicros()にはならないもののmsec単位の値を取ることもできます。

まとめ

await Task.Delay()ではasync/awaitのコストが結構きいているのかなと思います。秒単位、分単位ならこれでもいいかなと思いますし、UI関連が絡むのであれば選択肢としてありかなとも思えます。 ただ、Arduinoやmbedの移植を考えた時にはシングルタスクで動いていると思われるのでSystem.Diagnostics.Stopwatch()をつかってループをぶん回してもいいのかなと思います。 本当はもっといい方法があるのかもしれません。むしろ教えてほしい・・・。

追記

ネットをみてたら、こういう記事があった。

https://devhammer.net/blog/thread-sleep-equivalent-uwp/

await Task.Delay(1)Task.Delay(1).Wait()変えるって話らしい。

f:id:ueponx:20160813170143j:plain

値は変わらない・・・