.NET IoTってのがあるらしい。で、そいつでデバイスいじれるってのがちょっとすごいよね。で、ちょっと触ってみちゃう。ちと脱線して正確なタイミングでデバイスを操作するにはどうするかを考える。いやーすごい人がいるもんだね、、、
酒飲んで少し元気になった。
前回(https://sunday-engineer.blogspot.com/2024/02/net-iot3.html)うまくいかなかったSystem.Timers.Timerに代えてSystem.Threading.Timerでやってみる。
独占的超巨大世界企業によるリファレンスはこちら(https://learn.microsoft.com/ja-jp/dotnet/standard/threading/timers)。 で、こういうコードでどうだろう。
-
using System;
-
using System.Threading;
-
using System.Threading.Tasks;
-
using System.Device.Gpio;
-
using Iot.Device.Ft232H;
-
using Iot.Device.FtCommon;
-
class Program
-
{
-
private static System.Threading.Timer? timer;
-
private static Ft232HDevice? ft232h;
-
private static GpioController? controller;
-
private static int pin;
-
private static int ledOn=0;
-
private static PinValue[] pin_state={PinValue.High,PinValue.Low};
-
static void Main(string[] args)
-
{
-
ft232h = new Ft232HDevice(FtCommon.GetDevices()[0]);
-
controller = ft232h.CreateGpioController();
-
pin = Ft232HDevice.GetPinNumberFromString("D7");
-
controller.OpenPin(pin, PinMode.Output);
-
timer = new Timer(new TimerCallback(TimerTask),null,10,10);
-
Console.ReadLine();
-
timer.Dispose();
-
}
-
private static void TimerTask(object timerState)
-
{
-
ledOn^=1;
-
controller.Write(pin, pin_state[ledOn]);
-
}
-
}
で、出力はというと、、、
いやー、、、またもダメなんよ。明らかにDUTYおかしくなっているし、、、このままだと本当に「タイミングがカス」ってことになる。
先人の知恵を試してみるか。
MicroLibrary.cs
-
using System;
-
namespace MicroLibrary
-
{
-
/// <summary>
-
/// MicroStopwatch class
-
/// </summary>
-
public class MicroStopwatch : System.Diagnostics.Stopwatch
-
{
-
readonly double _microSecPerTick =
-
1000000D / System.Diagnostics.Stopwatch.Frequency;
-
public MicroStopwatch()
-
{
-
if (!System.Diagnostics.Stopwatch.IsHighResolution)
-
{
-
throw new Exception("On this system the high-resolution " +
-
"performance counter is not available");
-
}
-
}
-
public long ElapsedMicroseconds
-
{
-
get
-
{
-
return (long)(ElapsedTicks * _microSecPerTick);
-
}
-
}
-
}
-
/// <summary>
-
/// MicroTimer class
-
/// </summary>
-
public class MicroTimer
-
{
-
public delegate void MicroTimerElapsedEventHandler(
-
object sender,
-
MicroTimerEventArgs timerEventArgs);
-
public event MicroTimerElapsedEventHandler MicroTimerElapsed;
-
System.Threading.Thread _threadTimer = null;
-
long _ignoreEventIfLateBy = long.MaxValue;
-
long _timerIntervalInMicroSec = 0;
-
bool _stopTimer = true;
-
public MicroTimer()
-
{
-
}
-
public MicroTimer(long timerIntervalInMicroseconds)
-
{
-
Interval = timerIntervalInMicroseconds;
-
}
-
public long Interval
-
{
-
get
-
{
-
return System.Threading.Interlocked.Read(
-
ref _timerIntervalInMicroSec);
-
}
-
set
-
{
-
System.Threading.Interlocked.Exchange(
-
ref _timerIntervalInMicroSec, value);
-
}
-
}
-
public long IgnoreEventIfLateBy
-
{
-
get
-
{
-
return System.Threading.Interlocked.Read(
-
ref _ignoreEventIfLateBy);
-
}
-
set
-
{
-
System.Threading.Interlocked.Exchange(
-
ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value);
-
}
-
}
-
public bool Enabled
-
{
-
set
-
{
-
if (value)
-
{
-
Start();
-
}
-
else
-
{
-
Stop();
-
}
-
}
-
get
-
{
-
return (_threadTimer != null && _threadTimer.IsAlive);
-
}
-
}
-
public void Start()
-
{
-
if (Enabled || Interval <= 0)
-
{
-
return;
-
}
-
_stopTimer = false;
-
System.Threading.ThreadStart threadStart = delegate()
-
{
-
NotificationTimer(ref _timerIntervalInMicroSec,
-
ref _ignoreEventIfLateBy,
-
ref _stopTimer);
-
};
-
_threadTimer = new System.Threading.Thread(threadStart);
-
_threadTimer.Priority = System.Threading.ThreadPriority.Highest;
-
_threadTimer.Start();
-
}
-
public void Stop()
-
{
-
_stopTimer = true;
-
}
-
public void StopAndWait()
-
{
-
StopAndWait(System.Threading.Timeout.Infinite);
-
}
-
public bool StopAndWait(int timeoutInMilliSec)
-
{
-
_stopTimer = true;
-
if (!Enabled || _threadTimer.ManagedThreadId ==
-
System.Threading.Thread.CurrentThread.ManagedThreadId)
-
{
-
return true;
-
}
-
return _threadTimer.Join(timeoutInMilliSec);
-
}
-
public void Abort()
-
{
-
_stopTimer = true;
-
if (Enabled)
-
{
-
_threadTimer.Abort();
-
}
-
}
-
void NotificationTimer(ref long timerIntervalInMicroSec,
-
ref long ignoreEventIfLateBy,
-
ref bool stopTimer)
-
{
-
int timerCount = 0;
-
long nextNotification = 0;
-
MicroStopwatch microStopwatch = new MicroStopwatch();
-
microStopwatch.Start();
-
while (!stopTimer)
-
{
-
long callbackFunctionExecutionTime =
-
microStopwatch.ElapsedMicroseconds - nextNotification;
-
long timerIntervalInMicroSecCurrent =
-
System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
-
long ignoreEventIfLateByCurrent =
-
System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
-
nextNotification += timerIntervalInMicroSecCurrent;
-
timerCount++;
-
long elapsedMicroseconds = 0;
-
while ( (elapsedMicroseconds = microStopwatch.ElapsedMicroseconds)
-
< nextNotification)
-
{
-
System.Threading.Thread.SpinWait(10);
-
}
-
long timerLateBy = elapsedMicroseconds - nextNotification;
-
if (timerLateBy >= ignoreEventIfLateByCurrent)
-
{
-
continue;
-
}
-
MicroTimerEventArgs microTimerEventArgs =
-
new MicroTimerEventArgs(timerCount,
-
elapsedMicroseconds,
-
timerLateBy,
-
callbackFunctionExecutionTime);
-
MicroTimerElapsed(this, microTimerEventArgs);
-
}
-
microStopwatch.Stop();
-
}
-
}
-
/// <summary>
-
/// MicroTimer Event Argument class
-
/// </summary>
-
public class MicroTimerEventArgs : EventArgs
-
{
-
// Simple counter, number times timed event (callback function) executed
-
public int TimerCount { get; private set; }
-
// Time when timed event was called since timer started
-
public long ElapsedMicroseconds { get; private set; }
-
// How late the timer was compared to when it should have been called
-
public long TimerLateBy { get; private set; }
-
// Time it took to execute previous call to callback function (OnTimedEvent)
-
public long CallbackFunctionExecutionTime { get; private set; }
-
public MicroTimerEventArgs(int timerCount,
-
long elapsedMicroseconds,
-
long timerLateBy,
-
long callbackFunctionExecutionTime)
-
{
-
TimerCount = timerCount;
-
ElapsedMicroseconds = elapsedMicroseconds;
-
TimerLateBy = timerLateBy;
-
CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
-
}
-
}
-
}
Program.cs
-
using System.Device.Gpio;
-
using Iot.Device.Ft232H;
-
using Iot.Device.FtCommon;
-
-
public class study4{
-
private static Ft232HDevice? ft232h;
-
private static GpioController? controller;
-
private static int pin;
-
private static int ledOn=0;
-
private static PinValue[] pin_state={PinValue.High,PinValue.Low};
-
public static void Main(){
-
ft232h = new Ft232HDevice(FtCommon.GetDevices()[0]);
-
controller = ft232h.CreateGpioController();
-
pin = Ft232HDevice.GetPinNumberFromString("D7");
-
controller.OpenPin(pin, PinMode.Output);
-
MicroLibrary.MicroTimer microTimer = new MicroLibrary.MicroTimer();
-
microTimer.MicroTimerElapsed += new MicroLibrary.MicroTimer.MicroTimerElapsedEventHandler(OnTimedEvent);
-
microTimer.Interval = 10000;
-
microTimer.Enabled = true;
-
Console.ReadLine();
-
}
-
private static void OnTimedEvent(object sender,MicroLibrary.MicroTimerEventArgs timerEventArgs)
-
{
-
ledOn^=1;
-
controller.Write(pin, pin_state[ledOn]);
-
}
-
}
で、「タイミングがカス」説について、基本はそうなんだけど、天才によって補われている。ので克服できる。もしかしたら何か背反があるかもしれないけど、ガチで正確なタイミングが必要な場合は利用しよう。
いやーたまにブツ触るとそれはそれで楽しいもんだね。こういうの家でやるのってまぁまぁな投資だけど、あーでもないこーでもないやりながら考えることで、脳が鍛えられるって信じてる。初老の(もはや初老じゃないかも)おじさんの脳トレ。
コメントをお書きください