我通过 UART 端口对系统进行采样,然后将信息记录在带有时间戳(包括毫秒)的文件中。如果我以 1 秒的间隔采样,数据会按预期返回......类似于
1:52:45 PM 750 data
1:52:45 PM 750 data
1:52:45 PM 750 data
1:52:46 PM 750 data
但是,如果我将计时器的间隔减少到 100 毫秒,数据就会返回
1:52:45 PM 531 data
1:52:45 PM 640 data
1:52:45 PM 750 data
1:52:45 PM 859 data
1:52:45 PM 968 data
1:52:46 PM 78 data
总是迟到一点。
计时器间隔越小,情况就会变得更糟......我在这里错过了什么?
时钟漂移。对于普通计时器来说非常典型。原因是它们通常是使用睡眠函数来实现的。睡眠函数总是保证至少睡眠指定的时间,但不保证不睡眠超过该时间,实际上它总是累积漂移。
有多种方法可以编写计时器来补偿漂移并平均达到目标。
我最喜欢的计时器之一是固定步进计时器,它有一个谨慎的滴答声。它非常简单,看起来像这样:
var t = DateTime.Now + TimeSpan.FromSeconds(1);
for (;;)
{
if (DateTime.Now >= t)
{
t += TimeSpan.FromSeconds(1); // Tick!
}
}
这是一个粗糙但有效的计时器,下面是我为 WPF 计时器构建的时钟示例,其中内置计时器出现漂移。这个计时器要复杂得多,并且不会占用您的 CPU。但它清楚地说明了计时器所存在的典型问题。
这里的 OnTimerTick 使用内置计时器,该计时器会出现漂移,但它会调整间隔以补偿漂移。
/// <summary>
/// Occurs when the timer interval has elapsed.
/// </summary>
public event EventHandler Tick;
DispatcherTimer timer;
public bool IsRunning { get { return timer.IsEnabled; } }
long step, nextTick, n;
public TimeSpan Elapsed { get { return new TimeSpan(n * step); } }
public FixedStepDispatcherTimer(TimeSpan interval)
{
if (interval < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("interval");
}
this.timer = new DispatcherTimer();
this.timer.Tick += new EventHandler(OnTimerTick);
this.step = interval.Ticks;
}
TimeSpan GetTimerInterval()
{
var interval = nextTick - DateTime.Now.Ticks;
if (interval > 0)
{
return new TimeSpan(interval);
}
return TimeSpan.Zero; // yield
}
void OnTimerTick(object sender, EventArgs e)
{
if (DateTime.Now.Ticks >= nextTick)
{
n++;
if (Tick != null)
{
Tick(this, EventArgs.Empty);
}
nextTick += step;
}
var interval = GetTimerInterval();
Trace.WriteLine(interval);
timer.Interval = interval;
}
public void Reset()
{
n = 0;
nextTick = DateTime.Now.Ticks;
}
public void Start()
{
var now = DateTime.Now.Ticks;
nextTick = now + (step - (nextTick % step));
timer.Interval = GetTimerInterval();
timer.Start();
}
public void Stop()
{
timer.Stop();
nextTick = DateTime.Now.Ticks % step;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)