我正在通过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 ms,则数据会返回
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
总是有点晚。
定时器间隔越小,情况越糟......我在这里缺少什么?
答案 0 :(得分:3)
时钟漂移。非常典型的琐碎计时器。这样做的原因是它们通常使用睡眠功能来实现。睡眠功能总是保证至少在指定的时间内睡眠,但不能保证睡眠时间不超过这个时间,实际上它总是会累积漂移。
有一些方法可以编写定时器来补偿漂移并平均击中目标。
我最喜欢的一个定时器是固定步骤,有一个谨慎的滴答声。它很简单,看起来像这样:
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;
}
答案 1 :(得分:0)
请尝试使用Stopwatch课程。计时器并不意味着在那个程度上是准确的。
答案 2 :(得分:0)
.NET计时器没有无限分辨率。我使用.NET 3.5和.NET 4.0进行的实验表明,使用.NET计时器对象,最多只能达到15 ms的分辨率。我的经验是,如果定时器间隔为100 ms,您可以预期通常在100到105 ms范围内打勾,但我看到的范围宽达99到120 ms。
有关详细信息,请参阅http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=815。
如果您需要更高的准确度,可以直接使用Windows计时器。我在http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=817创建了一个Timer Queue API的包装器。
答案 3 :(得分:0)
Windows 多媒体计时器可以实现更高的计时分辨率。请参阅此处了解 Windows 多媒体计时器包装器和示例用法 https://stackoverflow.com/a/67060100/4856020